diff --git a/Cargo.toml b/Cargo.toml index 6f5b5260..17e25e98 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -10,4 +10,5 @@ members = [ "visualize", "path", "grovedbg-types", + "grovedb-version" ] diff --git a/grovedb-version/Cargo.toml b/grovedb-version/Cargo.toml new file mode 100644 index 00000000..06189c44 --- /dev/null +++ b/grovedb-version/Cargo.toml @@ -0,0 +1,14 @@ +[package] +name = "grovedb-version" +authors = ["Samuel Westrich "] +description = "Versioning library for Platform" +version = "1.0.0-rc.2" +edition = "2021" +license = "MIT" + +[dependencies] +thiserror = { version = "1.0.59" } +versioned-feature-core = { git = "https://github.com/dashpay/versioned-feature-core", version = "1.0.0" } + +[features] +mock-versions = [] diff --git a/grovedb-version/src/error.rs b/grovedb-version/src/error.rs new file mode 100644 index 00000000..0d3d4c9a --- /dev/null +++ b/grovedb-version/src/error.rs @@ -0,0 +1,25 @@ +use thiserror::Error; +use versioned_feature_core::FeatureVersion; + +#[derive(Error, Debug)] +pub enum GroveVersionError { + /// Expected some specific versions + #[error("grove unknown version on {method}, received: {received}")] + UnknownVersionMismatch { + /// method + method: String, + /// the allowed versions for this method + known_versions: Vec, + /// requested core height + received: FeatureVersion, + }, + + /// Expected some specific versions + #[error("{method} not active for grove version")] + VersionNotActive { + /// method + method: String, + /// the allowed versions for this method + known_versions: Vec, + }, +} diff --git a/grovedb-version/src/lib.rs b/grovedb-version/src/lib.rs new file mode 100644 index 00000000..48b80a52 --- /dev/null +++ b/grovedb-version/src/lib.rs @@ -0,0 +1,106 @@ +use crate::version::GroveVersion; + +pub mod error; +pub mod version; + +#[macro_export] +macro_rules! check_grovedb_v0_with_cost { + ($method:expr, $version:expr) => {{ + const EXPECTED_VERSION: u16 = 0; + if $version != EXPECTED_VERSION { + return Err(GroveVersionError::UnknownVersionMismatch { + method: $method.to_string(), + known_versions: vec![EXPECTED_VERSION], + received: $version, + } + .into()) + .wrap_with_cost(OperationCost::default()); + } + }}; +} + +#[macro_export] +macro_rules! check_grovedb_v0 { + ($method:expr, $version:expr) => {{ + const EXPECTED_VERSION: u16 = 0; + if $version != EXPECTED_VERSION { + return Err(GroveVersionError::UnknownVersionMismatch { + method: $method.to_string(), + known_versions: vec![EXPECTED_VERSION], + received: $version, + } + .into()); + } + }}; +} + +#[macro_export] +macro_rules! check_merk_v0_with_cost { + ($method:expr, $version:expr) => {{ + const EXPECTED_VERSION: u16 = 0; + if $version != EXPECTED_VERSION { + return Err(GroveVersionError::UnknownVersionMismatch { + method: $method.to_string(), + known_versions: vec![EXPECTED_VERSION], + received: $version, + } + .into()) + .wrap_with_cost(OperationCost::default()); + } + }}; +} + +#[macro_export] +macro_rules! check_merk_v0 { + ($method:expr, $version:expr) => {{ + const EXPECTED_VERSION: u16 = 0; + if $version != EXPECTED_VERSION { + return Err(GroveVersionError::UnknownVersionMismatch { + method: $method.to_string(), + known_versions: vec![EXPECTED_VERSION], + received: $version, + } + .into()); + } + }}; +} + +pub trait TryFromVersioned: Sized { + /// The type returned in the event of a conversion error. + type Error; + + /// Performs the conversion. + fn try_from_versioned(value: T, grove_version: &GroveVersion) -> Result; +} + +pub trait TryIntoVersioned: Sized { + /// The type returned in the event of a conversion error. + type Error; + + /// Performs the conversion. + fn try_into_versioned(self, grove_version: &GroveVersion) -> Result; +} + +impl TryIntoVersioned for T +where + U: TryFromVersioned, +{ + type Error = U::Error; + + #[inline] + fn try_into_versioned(self, grove_version: &GroveVersion) -> Result { + U::try_from_versioned(self, grove_version) + } +} + +impl TryFromVersioned for T +where + T: TryFrom, +{ + type Error = T::Error; + + #[inline] + fn try_from_versioned(value: U, _grove_version: &GroveVersion) -> Result { + T::try_from(value) + } +} diff --git a/grovedb-version/src/version/grovedb_versions.rs b/grovedb-version/src/version/grovedb_versions.rs new file mode 100644 index 00000000..51bbdcc6 --- /dev/null +++ b/grovedb-version/src/version/grovedb_versions.rs @@ -0,0 +1,226 @@ +use versioned_feature_core::FeatureVersion; + +#[derive(Clone, Debug, Default)] +pub struct GroveDBVersions { + pub apply_batch: GroveDBApplyBatchVersions, + pub element: GroveDBElementMethodVersions, + pub operations: GroveDBOperationsVersions, + pub path_query_methods: GroveDBPathQueryMethodVersions, + pub replication: GroveDBReplicationVersions, +} + +#[derive(Clone, Debug, Default)] +pub struct GroveDBPathQueryMethodVersions { + pub terminal_keys: FeatureVersion, + pub merge: FeatureVersion, + pub query_items_at_path: FeatureVersion, +} + +#[derive(Clone, Debug, Default)] +pub struct GroveDBApplyBatchVersions { + pub apply_batch_structure: FeatureVersion, + pub apply_body: FeatureVersion, + pub continue_partial_apply_body: FeatureVersion, + pub apply_operations_without_batching: FeatureVersion, + pub apply_batch: FeatureVersion, + pub apply_partial_batch: FeatureVersion, + pub open_batch_transactional_merk_at_path: FeatureVersion, + pub open_batch_merk_at_path: FeatureVersion, + pub apply_batch_with_element_flags_update: FeatureVersion, + pub apply_partial_batch_with_element_flags_update: FeatureVersion, + pub estimated_case_operations_for_batch: FeatureVersion, +} + +#[derive(Clone, Debug, Default)] +pub struct GroveDBOperationsVersions { + pub get: GroveDBOperationsGetVersions, + pub insert: GroveDBOperationsInsertVersions, + pub delete: GroveDBOperationsDeleteVersions, + pub delete_up_tree: GroveDBOperationsDeleteUpTreeVersions, + pub query: GroveDBOperationsQueryVersions, + pub proof: GroveDBOperationsProofVersions, + pub average_case: GroveDBOperationsAverageCaseVersions, + pub worst_case: GroveDBOperationsWorstCaseVersions, +} + +#[derive(Clone, Debug, Default)] +pub struct GroveDBOperationsGetVersions { + pub get: FeatureVersion, + pub get_caching_optional: FeatureVersion, + pub follow_reference: FeatureVersion, + pub get_raw: FeatureVersion, + pub get_raw_caching_optional: FeatureVersion, + pub get_raw_optional: FeatureVersion, + pub get_raw_optional_caching_optional: FeatureVersion, + pub has_raw: FeatureVersion, + pub check_subtree_exists_invalid_path: FeatureVersion, + pub average_case_for_has_raw: FeatureVersion, + pub average_case_for_has_raw_tree: FeatureVersion, + pub average_case_for_get_raw: FeatureVersion, + pub average_case_for_get: FeatureVersion, + pub average_case_for_get_tree: FeatureVersion, + pub worst_case_for_has_raw: FeatureVersion, + pub worst_case_for_get_raw: FeatureVersion, + pub worst_case_for_get: FeatureVersion, + pub is_empty_tree: FeatureVersion, +} + +#[derive(Clone, Debug, Default)] +pub struct GroveDBOperationsProofVersions { + pub prove_query: FeatureVersion, + pub prove_query_many: FeatureVersion, + pub verify_query_with_options: FeatureVersion, + pub verify_query_raw: FeatureVersion, + pub verify_layer_proof: FeatureVersion, + pub verify_query: FeatureVersion, + pub verify_subset_query: FeatureVersion, + pub verify_query_with_absence_proof: FeatureVersion, + pub verify_subset_query_with_absence_proof: FeatureVersion, + pub verify_query_with_chained_path_queries: FeatureVersion, +} + +#[derive(Clone, Debug, Default)] +pub struct GroveDBOperationsQueryVersions { + pub query_encoded_many: FeatureVersion, + pub query_many_raw: FeatureVersion, + pub get_proved_path_query: FeatureVersion, + pub query: FeatureVersion, + pub query_item_value: FeatureVersion, + pub query_item_value_or_sum: FeatureVersion, + pub query_sums: FeatureVersion, + pub query_raw: FeatureVersion, + pub query_keys_optional: FeatureVersion, + pub query_raw_keys_optional: FeatureVersion, + pub follow_element: FeatureVersion, +} + +#[derive(Clone, Debug, Default)] +pub struct GroveDBOperationsAverageCaseVersions { + pub add_average_case_get_merk_at_path: FeatureVersion, + pub average_case_merk_replace_tree: FeatureVersion, + pub average_case_merk_insert_tree: FeatureVersion, + pub average_case_merk_delete_tree: FeatureVersion, + pub average_case_merk_insert_element: FeatureVersion, + pub average_case_merk_replace_element: FeatureVersion, + pub average_case_merk_patch_element: FeatureVersion, + pub average_case_merk_delete_element: FeatureVersion, + pub add_average_case_has_raw_cost: FeatureVersion, + pub add_average_case_has_raw_tree_cost: FeatureVersion, + pub add_average_case_get_raw_cost: FeatureVersion, + pub add_average_case_get_raw_tree_cost: FeatureVersion, + pub add_average_case_get_cost: FeatureVersion, +} + +#[derive(Clone, Debug, Default)] +pub struct GroveDBOperationsWorstCaseVersions { + pub add_worst_case_get_merk_at_path: FeatureVersion, + pub worst_case_merk_replace_tree: FeatureVersion, + pub worst_case_merk_insert_tree: FeatureVersion, + pub worst_case_merk_delete_tree: FeatureVersion, + pub worst_case_merk_insert_element: FeatureVersion, + pub worst_case_merk_replace_element: FeatureVersion, + pub worst_case_merk_patch_element: FeatureVersion, + pub worst_case_merk_delete_element: FeatureVersion, + pub add_worst_case_has_raw_cost: FeatureVersion, + pub add_worst_case_get_raw_tree_cost: FeatureVersion, + pub add_worst_case_get_raw_cost: FeatureVersion, + pub add_worst_case_get_cost: FeatureVersion, +} + +#[derive(Clone, Debug, Default)] +pub struct GroveDBOperationsInsertVersions { + pub insert: FeatureVersion, + pub insert_on_transaction: FeatureVersion, + pub insert_without_transaction: FeatureVersion, + pub add_element_on_transaction: FeatureVersion, + pub add_element_without_transaction: FeatureVersion, + pub insert_if_not_exists: FeatureVersion, + pub insert_if_changed_value: FeatureVersion, +} + +#[derive(Clone, Debug, Default)] +pub struct GroveDBOperationsDeleteVersions { + pub delete: FeatureVersion, + pub clear_subtree: FeatureVersion, + pub delete_with_sectional_storage_function: FeatureVersion, + pub delete_if_empty_tree: FeatureVersion, + pub delete_if_empty_tree_with_sectional_storage_function: FeatureVersion, + pub delete_operation_for_delete_internal: FeatureVersion, + pub delete_internal_on_transaction: FeatureVersion, + pub delete_internal_without_transaction: FeatureVersion, + pub average_case_delete_operation_for_delete: FeatureVersion, + pub worst_case_delete_operation_for_delete: FeatureVersion, +} + +#[derive(Clone, Debug, Default)] +pub struct GroveDBOperationsDeleteUpTreeVersions { + pub delete_up_tree_while_empty: FeatureVersion, + pub delete_up_tree_while_empty_with_sectional_storage: FeatureVersion, + pub delete_operations_for_delete_up_tree_while_empty: FeatureVersion, + pub add_delete_operations_for_delete_up_tree_while_empty: FeatureVersion, + pub average_case_delete_operations_for_delete_up_tree_while_empty: FeatureVersion, + pub worst_case_delete_operations_for_delete_up_tree_while_empty: FeatureVersion, +} + +#[derive(Clone, Debug, Default)] +pub struct GroveDBOperationsApplyBatchVersions { + pub apply_batch_structure: FeatureVersion, + pub apply_body: FeatureVersion, + pub continue_partial_apply_body: FeatureVersion, + pub apply_operations_without_batching: FeatureVersion, + pub apply_batch: FeatureVersion, + pub apply_partial_batch: FeatureVersion, + pub open_batch_transactional_merk_at_path: FeatureVersion, + pub open_batch_merk_at_path: FeatureVersion, + pub apply_batch_with_element_flags_update: FeatureVersion, + pub apply_partial_batch_with_element_flags_update: FeatureVersion, + pub estimated_case_operations_for_batch: FeatureVersion, +} + +#[derive(Clone, Debug, Default)] +pub struct GroveDBElementMethodVersions { + pub delete: FeatureVersion, + pub delete_with_sectioned_removal_bytes: FeatureVersion, + pub delete_into_batch_operations: FeatureVersion, + pub element_at_key_already_exists: FeatureVersion, + pub get: FeatureVersion, + pub get_optional: FeatureVersion, + pub get_from_storage: FeatureVersion, + pub get_optional_from_storage: FeatureVersion, + pub get_with_absolute_refs: FeatureVersion, + pub get_value_hash: FeatureVersion, + pub get_specialized_cost: FeatureVersion, + pub value_defined_cost: FeatureVersion, + pub value_defined_cost_for_serialized_value: FeatureVersion, + pub specialized_costs_for_key_value: FeatureVersion, + pub required_item_space: FeatureVersion, + pub insert: FeatureVersion, + pub insert_into_batch_operations: FeatureVersion, + pub insert_if_not_exists: FeatureVersion, + pub insert_if_not_exists_into_batch_operations: FeatureVersion, + pub insert_if_changed_value: FeatureVersion, + pub insert_if_changed_value_into_batch_operations: FeatureVersion, + pub insert_reference: FeatureVersion, + pub insert_reference_into_batch_operations: FeatureVersion, + pub insert_subtree: FeatureVersion, + pub insert_subtree_into_batch_operations: FeatureVersion, + pub get_query: FeatureVersion, + pub get_query_values: FeatureVersion, + pub get_query_apply_function: FeatureVersion, + pub get_path_query: FeatureVersion, + pub get_sized_query: FeatureVersion, + pub path_query_push: FeatureVersion, + pub query_item: FeatureVersion, + pub basic_push: FeatureVersion, + pub serialize: FeatureVersion, + pub serialized_size: FeatureVersion, + pub deserialize: FeatureVersion, +} + +#[derive(Clone, Debug, Default)] +pub struct GroveDBReplicationVersions { + pub get_subtrees_metadata: FeatureVersion, + pub fetch_chunk: FeatureVersion, + pub start_snapshot_syncing: FeatureVersion, + pub apply_chunk: FeatureVersion, +} diff --git a/grovedb-version/src/version/merk_versions.rs b/grovedb-version/src/version/merk_versions.rs new file mode 100644 index 00000000..fac25f91 --- /dev/null +++ b/grovedb-version/src/version/merk_versions.rs @@ -0,0 +1,2 @@ +#[derive(Clone, Debug, Default)] +pub struct MerkVersions {} diff --git a/grovedb-version/src/version/mod.rs b/grovedb-version/src/version/mod.rs new file mode 100644 index 00000000..06ac4e12 --- /dev/null +++ b/grovedb-version/src/version/mod.rs @@ -0,0 +1,26 @@ +pub mod grovedb_versions; +pub mod merk_versions; +pub mod v1; + +pub use versioned_feature_core::*; + +use crate::version::{ + grovedb_versions::GroveDBVersions, merk_versions::MerkVersions, v1::GROVE_V1, +}; + +#[derive(Clone, Debug, Default)] +pub struct GroveVersion { + pub protocol_version: u32, + pub grovedb_versions: GroveDBVersions, + pub merk_versions: MerkVersions, +} + +impl GroveVersion { + pub fn latest<'a>() -> &'a Self { + GROVE_VERSIONS + .last() + .expect("expected to have a platform version") + } +} + +pub const GROVE_VERSIONS: &[GroveVersion] = &[GROVE_V1]; diff --git a/grovedb-version/src/version/v1.rs b/grovedb-version/src/version/v1.rs new file mode 100644 index 00000000..19bf135e --- /dev/null +++ b/grovedb-version/src/version/v1.rs @@ -0,0 +1,187 @@ +use crate::version::{ + grovedb_versions::{ + GroveDBApplyBatchVersions, GroveDBElementMethodVersions, + GroveDBOperationsAverageCaseVersions, GroveDBOperationsDeleteUpTreeVersions, + GroveDBOperationsDeleteVersions, GroveDBOperationsGetVersions, + GroveDBOperationsInsertVersions, GroveDBOperationsProofVersions, + GroveDBOperationsQueryVersions, GroveDBOperationsVersions, + GroveDBOperationsWorstCaseVersions, GroveDBPathQueryMethodVersions, + GroveDBReplicationVersions, GroveDBVersions, + }, + merk_versions::MerkVersions, + GroveVersion, +}; + +pub const GROVE_V1: GroveVersion = GroveVersion { + protocol_version: 0, + grovedb_versions: GroveDBVersions { + apply_batch: GroveDBApplyBatchVersions { + apply_batch_structure: 0, + apply_body: 0, + continue_partial_apply_body: 0, + apply_operations_without_batching: 0, + apply_batch: 0, + apply_partial_batch: 0, + open_batch_transactional_merk_at_path: 0, + open_batch_merk_at_path: 0, + apply_batch_with_element_flags_update: 0, + apply_partial_batch_with_element_flags_update: 0, + estimated_case_operations_for_batch: 0, + }, + element: GroveDBElementMethodVersions { + delete: 0, + delete_with_sectioned_removal_bytes: 0, + delete_into_batch_operations: 0, + element_at_key_already_exists: 0, + get: 0, + get_optional: 0, + get_from_storage: 0, + get_optional_from_storage: 0, + get_with_absolute_refs: 0, + get_value_hash: 0, + get_specialized_cost: 0, + value_defined_cost: 0, + value_defined_cost_for_serialized_value: 0, + specialized_costs_for_key_value: 0, + required_item_space: 0, + insert: 0, + insert_into_batch_operations: 0, + insert_if_not_exists: 0, + insert_if_not_exists_into_batch_operations: 0, + insert_if_changed_value: 0, + insert_if_changed_value_into_batch_operations: 0, + insert_reference: 0, + insert_reference_into_batch_operations: 0, + insert_subtree: 0, + insert_subtree_into_batch_operations: 0, + get_query: 0, + get_query_values: 0, + get_query_apply_function: 0, + get_path_query: 0, + get_sized_query: 0, + path_query_push: 0, + query_item: 0, + basic_push: 0, + serialize: 0, + serialized_size: 0, + deserialize: 0, + }, + operations: GroveDBOperationsVersions { + get: GroveDBOperationsGetVersions { + get: 0, + get_caching_optional: 0, + follow_reference: 0, + get_raw: 0, + get_raw_caching_optional: 0, + get_raw_optional: 0, + get_raw_optional_caching_optional: 0, + has_raw: 0, + check_subtree_exists_invalid_path: 0, + average_case_for_has_raw: 0, + average_case_for_has_raw_tree: 0, + average_case_for_get_raw: 0, + average_case_for_get: 0, + average_case_for_get_tree: 0, + worst_case_for_has_raw: 0, + worst_case_for_get_raw: 0, + worst_case_for_get: 0, + is_empty_tree: 0, + }, + insert: GroveDBOperationsInsertVersions { + insert: 0, + insert_on_transaction: 0, + insert_without_transaction: 0, + add_element_on_transaction: 0, + add_element_without_transaction: 0, + insert_if_not_exists: 0, + insert_if_changed_value: 0, + }, + delete: GroveDBOperationsDeleteVersions { + delete: 0, + clear_subtree: 0, + delete_with_sectional_storage_function: 0, + delete_if_empty_tree: 0, + delete_if_empty_tree_with_sectional_storage_function: 0, + delete_operation_for_delete_internal: 0, + delete_internal_on_transaction: 0, + delete_internal_without_transaction: 0, + average_case_delete_operation_for_delete: 0, + worst_case_delete_operation_for_delete: 0, + }, + delete_up_tree: GroveDBOperationsDeleteUpTreeVersions { + delete_up_tree_while_empty: 0, + delete_up_tree_while_empty_with_sectional_storage: 0, + delete_operations_for_delete_up_tree_while_empty: 0, + add_delete_operations_for_delete_up_tree_while_empty: 0, + average_case_delete_operations_for_delete_up_tree_while_empty: 0, + worst_case_delete_operations_for_delete_up_tree_while_empty: 0, + }, + query: GroveDBOperationsQueryVersions { + query_encoded_many: 0, + query_many_raw: 0, + get_proved_path_query: 0, + query: 0, + query_item_value: 0, + query_item_value_or_sum: 0, + query_sums: 0, + query_raw: 0, + query_keys_optional: 0, + query_raw_keys_optional: 0, + follow_element: 0, + }, + proof: GroveDBOperationsProofVersions { + prove_query: 0, + prove_query_many: 0, + verify_query_with_options: 0, + verify_query_raw: 0, + verify_layer_proof: 0, + verify_query: 0, + verify_subset_query: 0, + verify_query_with_absence_proof: 0, + verify_subset_query_with_absence_proof: 0, + verify_query_with_chained_path_queries: 0, + }, + average_case: GroveDBOperationsAverageCaseVersions { + add_average_case_get_merk_at_path: 0, + average_case_merk_replace_tree: 0, + average_case_merk_insert_tree: 0, + average_case_merk_delete_tree: 0, + average_case_merk_insert_element: 0, + average_case_merk_replace_element: 0, + average_case_merk_patch_element: 0, + average_case_merk_delete_element: 0, + add_average_case_has_raw_cost: 0, + add_average_case_has_raw_tree_cost: 0, + add_average_case_get_raw_cost: 0, + add_average_case_get_raw_tree_cost: 0, + add_average_case_get_cost: 0, + }, + worst_case: GroveDBOperationsWorstCaseVersions { + add_worst_case_get_merk_at_path: 0, + worst_case_merk_replace_tree: 0, + worst_case_merk_insert_tree: 0, + worst_case_merk_delete_tree: 0, + worst_case_merk_insert_element: 0, + worst_case_merk_replace_element: 0, + worst_case_merk_patch_element: 0, + worst_case_merk_delete_element: 0, + add_worst_case_has_raw_cost: 0, + add_worst_case_get_raw_tree_cost: 0, + add_worst_case_get_raw_cost: 0, + add_worst_case_get_cost: 0, + }, + }, + path_query_methods: GroveDBPathQueryMethodVersions { + terminal_keys: 0, + merge: 0, + query_items_at_path: 0, + }, + replication: GroveDBReplicationVersions { + get_subtrees_metadata: 0, + fetch_chunk: 0, + start_snapshot_syncing: 0, + apply_chunk: 0, + }, + }, + merk_versions: MerkVersions {}, +}; diff --git a/grovedb/Cargo.toml b/grovedb/Cargo.toml index 28ba9995..57a27479 100644 --- a/grovedb/Cargo.toml +++ b/grovedb/Cargo.toml @@ -33,6 +33,7 @@ tower-http = { version = "0.5.2", features = ["fs"], optional = true } blake3 = "1.4.0" bitvec = "1" zip-extensions = { version ="0.6.2", optional = true } +grovedb-version = { version = "1.0.0-rc.2", path = "../grovedb-version" } [dev-dependencies] rand = "0.8.5" diff --git a/grovedb/benches/insertion_benchmark.rs b/grovedb/benches/insertion_benchmark.rs index b073508c..051a32d1 100644 --- a/grovedb/benches/insertion_benchmark.rs +++ b/grovedb/benches/insertion_benchmark.rs @@ -50,9 +50,16 @@ pub fn insertion_benchmark_without_transaction(c: &mut Criterion) { let dir = TempDir::new().unwrap(); let db = GroveDb::open(dir.path()).unwrap(); let test_leaf: &[u8] = b"leaf1"; - db.insert(EMPTY_PATH, test_leaf, Element::empty_tree(), None, None) - .unwrap() - .unwrap(); + db.insert( + EMPTY_PATH, + test_leaf, + Element::empty_tree(), + None, + None, + grove_version, + ) + .unwrap() + .unwrap(); let keys = std::iter::repeat_with(|| rand::thread_rng().gen::<[u8; 32]>()).take(N_ITEMS); c.bench_function("scalars insertion without transaction", |b| { @@ -64,6 +71,7 @@ pub fn insertion_benchmark_without_transaction(c: &mut Criterion) { Element::new_item(k.to_vec()), None, None, + grove_version, ) .unwrap() .unwrap(); @@ -79,9 +87,16 @@ pub fn insertion_benchmark_with_transaction(c: &mut Criterion) { let dir = TempDir::new().unwrap(); let db = GroveDb::open(dir.path()).unwrap(); let test_leaf: &[u8] = b"leaf1"; - db.insert(EMPTY_PATH, test_leaf, Element::empty_tree(), None, None) - .unwrap() - .unwrap(); + db.insert( + EMPTY_PATH, + test_leaf, + Element::empty_tree(), + None, + None, + grove_version, + ) + .unwrap() + .unwrap(); let keys = std::iter::repeat_with(|| rand::thread_rng().gen::<[u8; 32]>()).take(N_ITEMS); c.bench_function("scalars insertion with transaction", |b| { @@ -94,6 +109,7 @@ pub fn insertion_benchmark_with_transaction(c: &mut Criterion) { Element::new_item(k.to_vec()), None, Some(&tx), + grove_version, ) .unwrap() .unwrap(); @@ -113,9 +129,16 @@ pub fn root_leaf_insertion_benchmark_without_transaction(c: &mut Criterion) { c.bench_function("root leaves insertion without transaction", |b| { b.iter(|| { for k in keys.clone() { - db.insert(EMPTY_PATH, &k, Element::empty_tree(), None, None) - .unwrap() - .unwrap(); + db.insert( + EMPTY_PATH, + &k, + Element::empty_tree(), + None, + None, + grove_version, + ) + .unwrap() + .unwrap(); } }) }); @@ -132,9 +155,16 @@ pub fn root_leaf_insertion_benchmark_with_transaction(c: &mut Criterion) { b.iter(|| { let tx = db.start_transaction(); for k in keys.clone() { - db.insert(EMPTY_PATH, &k, Element::empty_tree(), None, Some(&tx)) - .unwrap() - .unwrap(); + db.insert( + EMPTY_PATH, + &k, + Element::empty_tree(), + None, + Some(&tx), + grove_version, + ) + .unwrap() + .unwrap(); } db.commit_transaction(tx).unwrap().unwrap(); }) @@ -155,6 +185,7 @@ pub fn deeply_nested_insertion_benchmark_without_transaction(c: &mut Criterion) Element::empty_tree(), None, None, + grove_version, ) .unwrap() .unwrap(); @@ -172,6 +203,7 @@ pub fn deeply_nested_insertion_benchmark_without_transaction(c: &mut Criterion) Element::new_item(k.to_vec()), None, None, + grove_version, ) .unwrap() .unwrap(); @@ -194,6 +226,7 @@ pub fn deeply_nested_insertion_benchmark_with_transaction(c: &mut Criterion) { Element::empty_tree(), None, None, + grove_version, ) .unwrap() .unwrap(); @@ -212,6 +245,7 @@ pub fn deeply_nested_insertion_benchmark_with_transaction(c: &mut Criterion) { Element::new_item(k.to_vec()), None, Some(&tx), + grove_version, ) .unwrap() .unwrap(); diff --git a/grovedb/src/batch/batch_structure.rs b/grovedb/src/batch/batch_structure.rs index f07aad17..eb00f1e8 100644 --- a/grovedb/src/batch/batch_structure.rs +++ b/grovedb/src/batch/batch_structure.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. - //! Batch structure #[cfg(feature = "full")] diff --git a/grovedb/src/batch/estimated_costs/average_case_costs.rs b/grovedb/src/batch/estimated_costs/average_case_costs.rs index 7f4521a7..2f50186b 100644 --- a/grovedb/src/batch/estimated_costs/average_case_costs.rs +++ b/grovedb/src/batch/estimated_costs/average_case_costs.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. - //! Average case costs #[cfg(feature = "full")] @@ -46,6 +18,7 @@ use grovedb_merk::{ }; #[cfg(feature = "full")] use grovedb_storage::rocksdb_storage::RocksDbStorage; +use grovedb_version::version::GroveVersion; #[cfg(feature = "full")] use itertools::Itertools; @@ -69,6 +42,7 @@ impl Op { key: &KeyInfo, layer_element_estimates: &EstimatedLayerInformation, propagate: bool, + grove_version: &GroveVersion, ) -> CostResult<(), Error> { let in_tree_using_sums = layer_element_estimates.is_sum_tree; let propagate_if_input = || { @@ -84,6 +58,7 @@ impl Op { layer_element_estimates, sum.is_some(), propagate, + grove_version, ), Op::InsertTreeWithRootHash { flags, sum, .. } => { GroveDb::average_case_merk_insert_tree( @@ -92,6 +67,7 @@ impl Op { sum.is_some(), in_tree_using_sums, propagate_if_input(), + grove_version, ) } Op::Insert { element } => GroveDb::average_case_merk_insert_element( @@ -99,6 +75,7 @@ impl Op { element, in_tree_using_sums, propagate_if_input(), + grove_version, ), Op::RefreshReference { reference_path_type, @@ -114,12 +91,14 @@ impl Op { ), in_tree_using_sums, propagate_if_input(), + grove_version, ), Op::Replace { element } => GroveDb::average_case_merk_replace_element( key, element, in_tree_using_sums, propagate_if_input(), + grove_version, ), Op::Patch { element, @@ -130,21 +109,27 @@ impl Op { *change_in_bytes, in_tree_using_sums, propagate_if_input(), + grove_version, + ), + Op::Delete => GroveDb::average_case_merk_delete_element( + key, + layer_element_estimates, + propagate, + grove_version, ), - Op::Delete => { - GroveDb::average_case_merk_delete_element(key, layer_element_estimates, propagate) - } Op::DeleteTree => GroveDb::average_case_merk_delete_tree( key, false, layer_element_estimates, propagate, + grove_version, ), Op::DeleteSumTree => GroveDb::average_case_merk_delete_tree( key, true, layer_element_estimates, propagate, + grove_version, ), } } @@ -204,6 +189,7 @@ impl TreeCache for AverageCaseTreeCacheKnownPaths { _batch_apply_options: &BatchApplyOptions, _flags_update: &mut G, _split_removal_bytes: &mut SR, + grove_version: &GroveVersion, ) -> CostResult { let mut cost = OperationCost::default(); @@ -244,11 +230,15 @@ impl TreeCache for AverageCaseTreeCacheKnownPaths { )) }) ); - GroveDb::add_average_case_get_merk_at_path::( - &mut cost, - path, - layer_should_be_empty, - layer_info.is_sum_tree, + cost_return_on_error_no_add!( + &cost, + GroveDb::add_average_case_get_merk_at_path::( + &mut cost, + path, + layer_should_be_empty, + layer_info.is_sum_tree, + grove_version, + ) ); self.cached_merks .insert(path.clone(), layer_info.is_sum_tree); @@ -257,7 +247,7 @@ impl TreeCache for AverageCaseTreeCacheKnownPaths { for (key, op) in ops_at_path_by_key.into_iter() { cost_return_on_error!( &mut cost, - op.average_case_cost(&key, layer_element_estimates, false) + op.average_case_cost(&key, layer_element_estimates, false, grove_version) ); } @@ -268,20 +258,28 @@ impl TreeCache for AverageCaseTreeCacheKnownPaths { Ok(([0u8; 32], None, None)).wrap_with_cost(cost) } - fn update_base_merk_root_key(&mut self, _root_key: Option>) -> CostResult<(), Error> { + fn update_base_merk_root_key( + &mut self, + _root_key: Option>, + grove_version: &GroveVersion, + ) -> CostResult<(), Error> { let mut cost = OperationCost::default(); cost.seek_count += 1; let base_path = KeyInfoPath(vec![]); if let Some(estimated_layer_info) = self.paths.get(&base_path) { // Then we have to get the tree if !self.cached_merks.contains_key(&base_path) { - GroveDb::add_average_case_get_merk_at_path::( - &mut cost, - &base_path, - estimated_layer_info - .estimated_layer_count - .estimated_to_be_empty(), - estimated_layer_info.is_sum_tree, + cost_return_on_error_no_add!( + &cost, + GroveDb::add_average_case_get_merk_at_path::( + &mut cost, + &base_path, + estimated_layer_info + .estimated_layer_count + .estimated_to_be_empty(), + estimated_layer_info.is_sum_tree, + grove_version + ) ); self.cached_merks .insert(base_path, estimated_layer_info.is_sum_tree); @@ -306,6 +304,7 @@ mod tests { EstimatedLayerSizes::{AllItems, AllSubtrees}, EstimatedSumTrees::{NoSumTrees, SomeSumTrees}, }; + use grovedb_version::version::GroveVersion; use crate::{ batch::{ @@ -318,6 +317,7 @@ mod tests { #[test] fn test_batch_root_one_tree_insert_op_average_case_costs() { + let grove_version = GroveVersion::latest(); let db = make_empty_grovedb(); let tx = db.start_transaction(); @@ -343,11 +343,12 @@ mod tests { |_flags, _removed_key_bytes, _removed_value_bytes| { Ok((NoStorageRemoval, NoStorageRemoval)) }, + grove_version, ) .cost_as_result() .expect("expected to get average case costs"); - let cost = db.apply_batch(ops, None, Some(&tx)).cost; + let cost = db.apply_batch(ops, None, Some(&tx), grove_version).cost; assert!( average_case_cost.eq(&cost), "average cost not eq {:?} \n to cost {:?}", @@ -385,6 +386,7 @@ mod tests { #[test] fn test_batch_root_one_tree_with_flags_insert_op_average_case_costs() { + let grove_version = GroveVersion::latest(); let db = make_empty_grovedb(); let tx = db.start_transaction(); @@ -418,11 +420,12 @@ mod tests { |_flags, _removed_key_bytes, _removed_value_bytes| { Ok((NoStorageRemoval, NoStorageRemoval)) }, + grove_version, ) .cost_as_result() .expect("expected to get average case costs"); - let cost = db.apply_batch(ops, None, Some(&tx)).cost; + let cost = db.apply_batch(ops, None, Some(&tx), grove_version).cost; assert!( average_case_cost.worse_or_eq_than(&cost), "not worse {:?} \n than {:?}", @@ -450,6 +453,7 @@ mod tests { #[test] fn test_batch_root_one_item_insert_op_average_case_costs() { + let grove_version = GroveVersion::latest(); let db = make_empty_grovedb(); let tx = db.start_transaction(); @@ -475,11 +479,12 @@ mod tests { |_flags, _removed_key_bytes, _removed_value_bytes| { Ok((NoStorageRemoval, NoStorageRemoval)) }, + grove_version, ) .cost_as_result() .expect("expected to get average case costs"); - let cost = db.apply_batch(ops, None, Some(&tx)).cost; + let cost = db.apply_batch(ops, None, Some(&tx), grove_version).cost; // because we know the object we are inserting we can know the average // case cost if it doesn't already exist assert_eq!( @@ -510,12 +515,20 @@ mod tests { #[test] fn test_batch_root_one_tree_insert_op_under_element_average_case_costs() { + let grove_version = GroveVersion::latest(); let db = make_empty_grovedb(); let tx = db.start_transaction(); - db.insert(EMPTY_PATH, b"0", Element::empty_tree(), None, Some(&tx)) - .unwrap() - .expect("successful root tree leaf insert"); + db.insert( + EMPTY_PATH, + b"0", + Element::empty_tree(), + None, + Some(&tx), + grove_version, + ) + .unwrap() + .expect("successful root tree leaf insert"); let ops = vec![GroveDbOp::insert_op( vec![], @@ -540,11 +553,12 @@ mod tests { |_flags, _removed_key_bytes, _removed_value_bytes| { Ok((NoStorageRemoval, NoStorageRemoval)) }, + grove_version, ) .cost_as_result() .expect("expected to get average case costs"); - let cost = db.apply_batch(ops, None, Some(&tx)).cost; + let cost = db.apply_batch(ops, None, Some(&tx), grove_version).cost; // because we know the object we are inserting we can know the average // case cost if it doesn't already exist assert_eq!(cost.storage_cost, average_case_cost.storage_cost); @@ -587,12 +601,20 @@ mod tests { #[test] fn test_batch_root_one_tree_insert_op_in_sub_tree_average_case_costs() { + let grove_version = GroveVersion::latest(); let db = make_empty_grovedb(); let tx = db.start_transaction(); - db.insert(EMPTY_PATH, b"0", Element::empty_tree(), None, Some(&tx)) - .unwrap() - .expect("successful root tree leaf insert"); + db.insert( + EMPTY_PATH, + b"0", + Element::empty_tree(), + None, + Some(&tx), + grove_version, + ) + .unwrap() + .expect("successful root tree leaf insert"); let ops = vec![GroveDbOp::insert_op( vec![b"0".to_vec()], @@ -626,11 +648,12 @@ mod tests { |_flags, _removed_key_bytes, _removed_value_bytes| { Ok((NoStorageRemoval, NoStorageRemoval)) }, + grove_version, ) .cost_as_result() .expect("expected to get average case costs"); - let cost = db.apply_batch(ops, None, Some(&tx)).cost; + let cost = db.apply_batch(ops, None, Some(&tx), grove_version).cost; assert!( average_case_cost.worse_or_eq_than(&cost), "not worse {:?} \n than {:?}", @@ -671,6 +694,7 @@ mod tests { #[test] fn test_batch_root_one_sum_item_replace_op_average_case_costs() { + let grove_version = GroveVersion::latest(); let ops = vec![GroveDbOp::replace_op( vec![vec![7]], hex::decode("46447a3b4c8939fd4cf8b610ba7da3d3f6b52b39ab2549bf91503b9b07814055") @@ -709,6 +733,7 @@ mod tests { |_flags, _removed_key_bytes, _removed_value_bytes| { Ok((NoStorageRemoval, NoStorageRemoval)) }, + grove_version, ) .cost_as_result() .expect("expected to get average case costs"); @@ -734,12 +759,20 @@ mod tests { #[test] fn test_batch_average_case_costs() { + let grove_version = GroveVersion::latest(); let db = make_empty_grovedb(); let tx = db.start_transaction(); - db.insert(EMPTY_PATH, b"keyb", Element::empty_tree(), None, Some(&tx)) - .unwrap() - .expect("successful root tree leaf insert"); + db.insert( + EMPTY_PATH, + b"keyb", + Element::empty_tree(), + None, + Some(&tx), + grove_version, + ) + .unwrap() + .expect("successful root tree leaf insert"); let ops = vec![GroveDbOp::insert_op( vec![], @@ -773,10 +806,11 @@ mod tests { |_flags, _removed_key_bytes, _removed_value_bytes| { Ok((NoStorageRemoval, NoStorageRemoval)) }, + grove_version, ) .cost_as_result() .expect("expected to estimate costs"); - let cost = db.apply_batch(ops, None, Some(&tx)).cost; + let cost = db.apply_batch(ops, None, Some(&tx), grove_version).cost; // at the moment we just check the added bytes are the same assert_eq!( average_case_cost.storage_cost.added_bytes, diff --git a/grovedb/src/batch/estimated_costs/mod.rs b/grovedb/src/batch/estimated_costs/mod.rs index f0f505bc..54fc109c 100644 --- a/grovedb/src/batch/estimated_costs/mod.rs +++ b/grovedb/src/batch/estimated_costs/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. - //! Estimated costs #[cfg(feature = "full")] diff --git a/grovedb/src/batch/estimated_costs/worst_case_costs.rs b/grovedb/src/batch/estimated_costs/worst_case_costs.rs index f45bbff7..1b1d42e7 100644 --- a/grovedb/src/batch/estimated_costs/worst_case_costs.rs +++ b/grovedb/src/batch/estimated_costs/worst_case_costs.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. - //! Worst case costs #[cfg(feature = "full")] @@ -45,6 +17,7 @@ use grovedb_merk::estimated_costs::worst_case_costs::{ use grovedb_merk::RootHashKeyAndSum; #[cfg(feature = "full")] use grovedb_storage::rocksdb_storage::RocksDbStorage; +use grovedb_version::version::GroveVersion; #[cfg(feature = "full")] use itertools::Itertools; @@ -66,6 +39,7 @@ impl Op { is_in_parent_sum_tree: bool, worst_case_layer_element_estimates: &WorstCaseLayerInformation, propagate: bool, + grove_version: &GroveVersion, ) -> CostResult<(), Error> { let propagate_if_input = || { if propagate { @@ -81,6 +55,7 @@ impl Op { is_in_parent_sum_tree, worst_case_layer_element_estimates, propagate, + grove_version, ), Op::InsertTreeWithRootHash { flags, sum, .. } => GroveDb::worst_case_merk_insert_tree( key, @@ -88,12 +63,14 @@ impl Op { sum.is_some(), is_in_parent_sum_tree, propagate_if_input(), + grove_version, ), Op::Insert { element } => GroveDb::worst_case_merk_insert_element( key, element, is_in_parent_sum_tree, propagate_if_input(), + grove_version, ), Op::RefreshReference { reference_path_type, @@ -109,12 +86,14 @@ impl Op { ), is_in_parent_sum_tree, propagate_if_input(), + grove_version, ), Op::Replace { element } => GroveDb::worst_case_merk_replace_element( key, element, is_in_parent_sum_tree, propagate_if_input(), + grove_version, ), Op::Patch { element, @@ -124,23 +103,27 @@ impl Op { element, is_in_parent_sum_tree, propagate_if_input(), + grove_version, ), Op::Delete => GroveDb::worst_case_merk_delete_element( key, worst_case_layer_element_estimates, propagate, + grove_version, ), Op::DeleteTree => GroveDb::worst_case_merk_delete_tree( key, false, worst_case_layer_element_estimates, propagate, + grove_version, ), Op::DeleteSumTree => GroveDb::worst_case_merk_delete_tree( key, true, worst_case_layer_element_estimates, propagate, + grove_version, ), } } @@ -200,6 +183,7 @@ impl TreeCache for WorstCaseTreeCacheKnownPaths { _batch_apply_options: &BatchApplyOptions, _flags_update: &mut G, _split_removal_bytes: &mut SR, + grove_version: &GroveVersion, ) -> CostResult { let mut cost = OperationCost::default(); @@ -215,14 +199,28 @@ impl TreeCache for WorstCaseTreeCacheKnownPaths { // Then we have to get the tree if !self.cached_merks.contains(path) { - GroveDb::add_worst_case_get_merk_at_path::(&mut cost, path, false); + cost_return_on_error_no_add!( + &cost, + GroveDb::add_worst_case_get_merk_at_path::( + &mut cost, + path, + false, + grove_version, + ) + ); self.cached_merks.insert(path.clone()); } for (key, op) in ops_at_path_by_key.into_iter() { cost_return_on_error!( &mut cost, - op.worst_case_cost(&key, false, worst_case_layer_element_estimates, false) + op.worst_case_cost( + &key, + false, + worst_case_layer_element_estimates, + false, + grove_version + ) ); } @@ -233,15 +231,25 @@ impl TreeCache for WorstCaseTreeCacheKnownPaths { Ok(([0u8; 32], None, None)).wrap_with_cost(cost) } - fn update_base_merk_root_key(&mut self, _root_key: Option>) -> CostResult<(), Error> { + fn update_base_merk_root_key( + &mut self, + _root_key: Option>, + grove_version: &GroveVersion, + ) -> CostResult<(), Error> { let mut cost = OperationCost::default(); cost.seek_count += 1; let base_path = KeyInfoPath(vec![]); if let Some(_estimated_layer_info) = self.paths.get(&base_path) { // Then we have to get the tree if !self.cached_merks.contains(&base_path) { - GroveDb::add_worst_case_get_merk_at_path::( - &mut cost, &base_path, false, + cost_return_on_error_no_add!( + &cost, + GroveDb::add_worst_case_get_merk_at_path::( + &mut cost, + &base_path, + false, + grove_version, + ) ); self.cached_merks.insert(base_path); } @@ -261,6 +269,7 @@ mod tests { }; #[rustfmt::skip] use grovedb_merk::estimated_costs::worst_case_costs::WorstCaseLayerInformation::MaxElementsNumber; + use grovedb_version::version::GroveVersion; use crate::{ batch::{ @@ -273,6 +282,7 @@ mod tests { #[test] fn test_batch_root_one_tree_insert_op_worst_case_costs() { + let grove_version = GroveVersion::latest(); let db = make_empty_grovedb(); let tx = db.start_transaction(); @@ -291,11 +301,12 @@ mod tests { |_flags, _removed_key_bytes, _removed_value_bytes| { Ok((NoStorageRemoval, NoStorageRemoval)) }, + grove_version, ) .cost_as_result() .expect("expected to get worst case costs"); - let cost = db.apply_batch(ops, None, Some(&tx)).cost; + let cost = db.apply_batch(ops, None, Some(&tx), grove_version).cost; assert!( worst_case_cost.worse_or_eq_than(&cost), "not worse {:?} \n than {:?}", @@ -326,6 +337,7 @@ mod tests { #[test] fn test_batch_root_one_tree_with_flags_insert_op_worst_case_costs() { + let grove_version = GroveVersion::latest(); let db = make_empty_grovedb(); let tx = db.start_transaction(); @@ -344,11 +356,12 @@ mod tests { |_flags, _removed_key_bytes, _removed_value_bytes| { Ok((NoStorageRemoval, NoStorageRemoval)) }, + grove_version, ) .cost_as_result() .expect("expected to get worst case costs"); - let cost = db.apply_batch(ops, None, Some(&tx)).cost; + let cost = db.apply_batch(ops, None, Some(&tx), grove_version).cost; assert!( worst_case_cost.worse_or_eq_than(&cost), "not worse {:?} \n than {:?}", @@ -379,6 +392,7 @@ mod tests { #[test] fn test_batch_root_one_item_insert_op_worst_case_costs() { + let grove_version = GroveVersion::latest(); let db = make_empty_grovedb(); let tx = db.start_transaction(); @@ -397,11 +411,12 @@ mod tests { |_flags, _removed_key_bytes, _removed_value_bytes| { Ok((NoStorageRemoval, NoStorageRemoval)) }, + grove_version, ) .cost_as_result() .expect("expected to get worst case costs"); - let cost = db.apply_batch(ops, None, Some(&tx)).cost; + let cost = db.apply_batch(ops, None, Some(&tx), grove_version).cost; assert!( worst_case_cost.worse_or_eq_than(&cost), "not worse {:?} \n than {:?}", @@ -432,12 +447,20 @@ mod tests { #[test] fn test_batch_root_one_tree_insert_op_under_element_worst_case_costs() { + let grove_version = GroveVersion::latest(); let db = make_empty_grovedb(); let tx = db.start_transaction(); - db.insert(EMPTY_PATH, b"0", Element::empty_tree(), None, Some(&tx)) - .unwrap() - .expect("successful root tree leaf insert"); + db.insert( + EMPTY_PATH, + b"0", + Element::empty_tree(), + None, + Some(&tx), + grove_version, + ) + .unwrap() + .expect("successful root tree leaf insert"); let ops = vec![GroveDbOp::insert_op( vec![], @@ -454,11 +477,12 @@ mod tests { |_flags, _removed_key_bytes, _removed_value_bytes| { Ok((NoStorageRemoval, NoStorageRemoval)) }, + grove_version, ) .cost_as_result() .expect("expected to get worst case costs"); - let cost = db.apply_batch(ops, None, Some(&tx)).cost; + let cost = db.apply_batch(ops, None, Some(&tx), grove_version).cost; assert!( worst_case_cost.worse_or_eq_than(&cost), "not worse {:?} \n than {:?}", @@ -489,12 +513,20 @@ mod tests { #[test] fn test_batch_root_one_tree_insert_op_in_sub_tree_worst_case_costs() { + let grove_version = GroveVersion::latest(); let db = make_empty_grovedb(); let tx = db.start_transaction(); - db.insert(EMPTY_PATH, b"0", Element::empty_tree(), None, Some(&tx)) - .unwrap() - .expect("successful root tree leaf insert"); + db.insert( + EMPTY_PATH, + b"0", + Element::empty_tree(), + None, + Some(&tx), + grove_version, + ) + .unwrap() + .expect("successful root tree leaf insert"); let ops = vec![GroveDbOp::insert_op( vec![b"0".to_vec()], @@ -515,11 +547,12 @@ mod tests { |_flags, _removed_key_bytes, _removed_value_bytes| { Ok((NoStorageRemoval, NoStorageRemoval)) }, + grove_version, ) .cost_as_result() .expect("expected to get worst case costs"); - let cost = db.apply_batch(ops, None, Some(&tx)).cost; + let cost = db.apply_batch(ops, None, Some(&tx), grove_version).cost; assert!( worst_case_cost.worse_or_eq_than(&cost), "not worse {:?} \n than {:?}", @@ -544,12 +577,20 @@ mod tests { #[test] fn test_batch_worst_case_costs() { + let grove_version = GroveVersion::latest(); let db = make_empty_grovedb(); let tx = db.start_transaction(); - db.insert(EMPTY_PATH, b"keyb", Element::empty_tree(), None, Some(&tx)) - .unwrap() - .expect("successful root tree leaf insert"); + db.insert( + EMPTY_PATH, + b"keyb", + Element::empty_tree(), + None, + Some(&tx), + grove_version, + ) + .unwrap() + .expect("successful root tree leaf insert"); let ops = vec![GroveDbOp::insert_op( vec![], @@ -566,9 +607,10 @@ mod tests { |_flags, _removed_key_bytes, _removed_value_bytes| { Ok((NoStorageRemoval, NoStorageRemoval)) }, + grove_version, ); assert!(worst_case_cost_result.value.is_ok()); - let cost = db.apply_batch(ops, None, Some(&tx)).cost; + let cost = db.apply_batch(ops, None, Some(&tx), grove_version).cost; // at the moment we just check the added bytes are the same assert_eq!( worst_case_cost_result.cost.storage_cost.added_bytes, diff --git a/grovedb/src/batch/just_in_time_cost_tests.rs b/grovedb/src/batch/just_in_time_cost_tests.rs index 2321b467..e1fddf5c 100644 --- a/grovedb/src/batch/just_in_time_cost_tests.rs +++ b/grovedb/src/batch/just_in_time_cost_tests.rs @@ -1,31 +1,3 @@ -// MIT LICENSE -// -// Copyright (c) 2023 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. - //! This tests just in time costs //! Just in time costs modify the tree in the same batch @@ -33,6 +5,8 @@ mod tests { use std::option::Option::None; + use grovedb_version::version::GroveVersion; + use crate::{ batch::GroveDbOp, reference_path::ReferencePathType::UpstreamFromElementHeightReference, @@ -42,15 +16,30 @@ mod tests { #[test] fn test_partial_costs_with_no_new_operations_are_same_as_apply_batch() { + let grove_version = GroveVersion::latest(); let db = make_empty_grovedb(); let tx = db.start_transaction(); - db.insert(EMPTY_PATH, b"documents", Element::empty_tree(), None, None) - .cost_as_result() - .expect("expected to insert successfully"); - db.insert(EMPTY_PATH, b"balances", Element::empty_tree(), None, None) - .cost_as_result() - .expect("expected to insert successfully"); + db.insert( + EMPTY_PATH, + b"documents", + Element::empty_tree(), + None, + None, + grove_version, + ) + .cost_as_result() + .expect("expected to insert successfully"); + db.insert( + EMPTY_PATH, + b"balances", + Element::empty_tree(), + None, + None, + grove_version, + ) + .cost_as_result() + .expect("expected to insert successfully"); let ops = vec![ GroveDbOp::insert_op( vec![b"documents".to_vec()], @@ -73,27 +62,38 @@ mod tests { ]; let full_cost = db - .apply_batch(ops.clone(), None, Some(&tx)) + .apply_batch(ops.clone(), None, Some(&tx), grove_version) .cost_as_result() .expect("expected to apply batch"); let apply_root_hash = db - .root_hash(Some(&tx)) + .root_hash(Some(&tx), grove_version) .unwrap() .expect("expected to get root hash"); - db.get([b"documents".as_slice()].as_ref(), b"key2", Some(&tx)) - .unwrap() - .expect("cannot get element"); + db.get( + [b"documents".as_slice()].as_ref(), + b"key2", + Some(&tx), + grove_version, + ) + .unwrap() + .expect("cannot get element"); - db.get([b"documents".as_slice()].as_ref(), b"key3", Some(&tx)) - .unwrap() - .expect("cannot get element"); + db.get( + [b"documents".as_slice()].as_ref(), + b"key3", + Some(&tx), + grove_version, + ) + .unwrap() + .expect("cannot get element"); db.get( [b"documents".as_slice(), b"key3".as_slice()].as_ref(), b"key4", Some(&tx), + grove_version, ) .unwrap() .expect("cannot get element"); @@ -101,27 +101,44 @@ mod tests { tx.rollback().expect("expected to rollback"); let cost = db - .apply_partial_batch(ops, None, |_cost, _left_over_ops| Ok(vec![]), Some(&tx)) + .apply_partial_batch( + ops, + None, + |_cost, _left_over_ops| Ok(vec![]), + Some(&tx), + grove_version, + ) .cost_as_result() .expect("expected to apply batch"); let apply_partial_root_hash = db - .root_hash(Some(&tx)) + .root_hash(Some(&tx), grove_version) .unwrap() .expect("expected to get root hash"); - db.get([b"documents".as_slice()].as_ref(), b"key2", Some(&tx)) - .unwrap() - .expect("cannot get element"); + db.get( + [b"documents".as_slice()].as_ref(), + b"key2", + Some(&tx), + grove_version, + ) + .unwrap() + .expect("cannot get element"); - db.get([b"documents".as_slice()].as_ref(), b"key3", Some(&tx)) - .unwrap() - .expect("cannot get element"); + db.get( + [b"documents".as_slice()].as_ref(), + b"key3", + Some(&tx), + grove_version, + ) + .unwrap() + .expect("cannot get element"); db.get( [b"documents".as_slice(), b"key3".as_slice()].as_ref(), b"key4", Some(&tx), + grove_version, ) .unwrap() .expect("cannot get element"); @@ -133,18 +150,27 @@ mod tests { #[test] fn test_partial_costs_with_add_balance_operations() { + let grove_version = GroveVersion::latest(); let db = make_empty_grovedb(); let tx = db.start_transaction(); - db.insert(EMPTY_PATH, b"documents", Element::empty_tree(), None, None) - .cost_as_result() - .expect("expected to insert successfully"); + db.insert( + EMPTY_PATH, + b"documents", + Element::empty_tree(), + None, + None, + grove_version, + ) + .cost_as_result() + .expect("expected to insert successfully"); db.insert( EMPTY_PATH, b"balances", Element::empty_sum_tree(), None, None, + grove_version, ) .cost_as_result() .expect("expected to insert successfully"); @@ -170,27 +196,38 @@ mod tests { ]; let full_cost = db - .apply_batch(ops.clone(), None, Some(&tx)) + .apply_batch(ops.clone(), None, Some(&tx), grove_version) .cost_as_result() .expect("expected to apply batch"); let apply_root_hash = db - .root_hash(Some(&tx)) + .root_hash(Some(&tx), grove_version) .unwrap() .expect("expected to get root hash"); - db.get([b"documents".as_slice()].as_ref(), b"key2", Some(&tx)) - .unwrap() - .expect("cannot get element"); + db.get( + [b"documents".as_slice()].as_ref(), + b"key2", + Some(&tx), + grove_version, + ) + .unwrap() + .expect("cannot get element"); - db.get([b"documents".as_slice()].as_ref(), b"key3", Some(&tx)) - .unwrap() - .expect("cannot get element"); + db.get( + [b"documents".as_slice()].as_ref(), + b"key3", + Some(&tx), + grove_version, + ) + .unwrap() + .expect("cannot get element"); db.get( [b"documents".as_slice(), b"key3".as_slice()].as_ref(), b"key4", Some(&tx), + grove_version, ) .unwrap() .expect("cannot get element"); @@ -218,33 +255,50 @@ mod tests { Ok(new_ops) }, Some(&tx), + grove_version, ) .cost_as_result() .expect("expected to apply batch"); let apply_partial_root_hash = db - .root_hash(Some(&tx)) + .root_hash(Some(&tx), grove_version) .unwrap() .expect("expected to get root hash"); - db.get([b"documents".as_slice()].as_ref(), b"key2", Some(&tx)) - .unwrap() - .expect("cannot get element"); + db.get( + [b"documents".as_slice()].as_ref(), + b"key2", + Some(&tx), + grove_version, + ) + .unwrap() + .expect("cannot get element"); - db.get([b"documents".as_slice()].as_ref(), b"key3", Some(&tx)) - .unwrap() - .expect("cannot get element"); + db.get( + [b"documents".as_slice()].as_ref(), + b"key3", + Some(&tx), + grove_version, + ) + .unwrap() + .expect("cannot get element"); db.get( [b"documents".as_slice(), b"key3".as_slice()].as_ref(), b"key4", Some(&tx), + grove_version, ) .unwrap() .expect("cannot get element"); let balance = db - .get([b"balances".as_slice()].as_ref(), b"person", Some(&tx)) + .get( + [b"balances".as_slice()].as_ref(), + b"person", + Some(&tx), + grove_version, + ) .unwrap() .expect("cannot get element"); diff --git a/grovedb/src/batch/key_info.rs b/grovedb/src/batch/key_info.rs index a8eb50af..e7dd25b5 100644 --- a/grovedb/src/batch/key_info.rs +++ b/grovedb/src/batch/key_info.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. - //! Key info #[cfg(feature = "full")] diff --git a/grovedb/src/batch/mod.rs b/grovedb/src/batch/mod.rs index 474a304e..7f9c119e 100644 --- a/grovedb/src/batch/mod.rs +++ b/grovedb/src/batch/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. - //! Apply multiple GroveDB operations atomically. mod batch_structure; @@ -87,6 +59,9 @@ use grovedb_storage::{ rocksdb_storage::{PrefixedRocksDbStorageContext, PrefixedRocksDbTransactionContext}, Storage, StorageBatch, StorageContext, }; +use grovedb_version::{ + check_grovedb_v0_with_cost, error::GroveVersionError, version::GroveVersion, +}; use grovedb_visualize::{Drawer, Visualize}; use integer_encoding::VarInt; use itertools::Itertools; @@ -694,9 +669,14 @@ trait TreeCache { batch_apply_options: &BatchApplyOptions, flags_update: &mut G, split_removal_bytes: &mut SR, + grove_version: &GroveVersion, ) -> CostResult; - fn update_base_merk_root_key(&mut self, root_key: Option>) -> CostResult<(), Error>; + fn update_base_merk_root_key( + &mut self, + root_key: Option>, + grove_version: &GroveVersion, + ) -> CostResult<(), Error>; } impl<'db, S, F> TreeCacheMerkByPath @@ -751,6 +731,7 @@ where ops_by_qualified_paths: &'a BTreeMap>, Op>, recursions_allowed: u8, intermediate_reference_info: Option<&'a ReferencePathType>, + grove_version: &GroveVersion, ) -> CostResult { let mut cost = OperationCost::default(); let (key, reference_path) = qualified_path.split_last().unwrap(); // already checked @@ -771,7 +752,8 @@ where merk.get_value_hash( key.as_ref(), true, - Some(Element::value_defined_cost_for_serialized_value) + Some(Element::value_defined_cost_for_serialized_value), + grove_version, ) .map_err(|e| Error::CorruptedData(e.to_string())) ); @@ -804,6 +786,7 @@ where path.as_slice(), ops_by_qualified_paths, recursions_allowed - 1, + grove_version, ) } else { // Here the element being referenced doesn't change in the same batch @@ -815,7 +798,8 @@ where merk.get( key.as_ref(), true, - Some(Element::value_defined_cost_for_serialized_value) + Some(Element::value_defined_cost_for_serialized_value), + grove_version ) .map_err(|e| Error::CorruptedData(e.to_string())) ); @@ -838,14 +822,15 @@ where let element = cost_return_on_error_no_add!( &cost, - Element::deserialize(referenced_element.as_slice()).map_err(|_| { + Element::deserialize(referenced_element.as_slice(), grove_version).map_err(|_| { Error::CorruptedData(String::from("unable to deserialize element")) }) ); match element { Element::Item(..) | Element::SumItem(..) => { - let serialized = cost_return_on_error_no_add!(&cost, element.serialize()); + let serialized = + cost_return_on_error_no_add!(&cost, element.serialize(grove_version)); let val_hash = value_hash(&serialized).unwrap_add_cost(&mut cost); Ok(val_hash).wrap_with_cost(cost) } @@ -858,6 +843,7 @@ where path.as_slice(), ops_by_qualified_paths, recursions_allowed - 1, + grove_version, ) } Element::Tree(..) | Element::SumTree(..) => Err(Error::InvalidBatchOperation( @@ -883,6 +869,7 @@ where qualified_path: &[Vec], ops_by_qualified_paths: &'a BTreeMap>, Op>, recursions_allowed: u8, + grove_version: &GroveVersion, ) -> CostResult { let mut cost = OperationCost::default(); if recursions_allowed == 0 { @@ -900,8 +887,10 @@ where Op::Insert { element } | Op::Replace { element } | Op::Patch { element, .. } => { match element { Element::Item(..) | Element::SumItem(..) => { - let serialized = - cost_return_on_error_no_add!(&cost, element.serialize()); + let serialized = cost_return_on_error_no_add!( + &cost, + element.serialize(grove_version) + ); let val_hash = value_hash(&serialized).unwrap_add_cost(&mut cost); Ok(val_hash).wrap_with_cost(cost) } @@ -917,6 +906,7 @@ where path.as_slice(), ops_by_qualified_paths, recursions_allowed - 1, + grove_version, ) } Element::Tree(..) | Element::SumTree(..) => { @@ -943,6 +933,7 @@ where ops_by_qualified_paths, recursions_allowed, reference_info, + grove_version, ) } Op::Delete | Op::DeleteTree | Op::DeleteSumTree => { @@ -958,6 +949,7 @@ where ops_by_qualified_paths, recursions_allowed, None, + grove_version, ) } } @@ -989,7 +981,11 @@ where Ok(()).wrap_with_cost(cost) } - fn update_base_merk_root_key(&mut self, root_key: Option>) -> CostResult<(), Error> { + fn update_base_merk_root_key( + &mut self, + root_key: Option>, + _grove_version: &GroveVersion, + ) -> CostResult<(), Error> { let mut cost = OperationCost::default(); let base_path = vec![]; let merk_wrapped = self @@ -1011,6 +1007,7 @@ where batch_apply_options: &BatchApplyOptions, flags_update: &mut G, split_removal_bytes: &mut SR, + grove_version: &GroveVersion, ) -> CostResult { let mut cost = OperationCost::default(); // todo: fix this @@ -1058,7 +1055,8 @@ where self.follow_reference_get_value_hash( path_reference.as_slice(), ops_by_qualified_paths, - element_max_reference_hop.unwrap_or(MAX_REFERENCE_HOPS as u8) + element_max_reference_hop.unwrap_or(MAX_REFERENCE_HOPS as u8), + grove_version, ) ); @@ -1068,7 +1066,8 @@ where key_info.get_key_clone(), referenced_element_value_hash, &mut batch_operations, - merk_feature_type + merk_feature_type, + grove_version, ) ); } @@ -1086,7 +1085,8 @@ where NULL_HASH, false, &mut batch_operations, - merk_feature_type + merk_feature_type, + grove_version, ) ); } @@ -1104,7 +1104,8 @@ where &mut merk, key_info.get_key(), &mut batch_operations, - merk_feature_type + merk_feature_type, + grove_version, ) ); if !inserted { @@ -1119,7 +1120,8 @@ where element.insert_into_batch_operations( key_info.get_key(), &mut batch_operations, - merk_feature_type + merk_feature_type, + grove_version, ) ); } @@ -1143,7 +1145,8 @@ where merk.get( key_info.as_slice(), true, - Some(Element::value_defined_cost_for_serialized_value) + Some(Element::value_defined_cost_for_serialized_value), + grove_version ) .map( |result_value| result_value.map_err(Error::MerkError).and_then( @@ -1155,7 +1158,7 @@ where ); cost_return_on_error_no_add!( &cost, - Element::deserialize(value.as_slice()).map_err(|_| { + Element::deserialize(value.as_slice(), grove_version).map_err(|_| { Error::CorruptedData(String::from("unable to deserialize element")) }) ) @@ -1195,7 +1198,8 @@ where self.follow_reference_get_value_hash( path_reference.as_slice(), ops_by_qualified_paths, - max_reference_hop.unwrap_or(MAX_REFERENCE_HOPS as u8) + max_reference_hop.unwrap_or(MAX_REFERENCE_HOPS as u8), + grove_version ) ); @@ -1205,7 +1209,8 @@ where key_info.get_key_clone(), referenced_element_value_hash, &mut batch_operations, - merk_feature_type + merk_feature_type, + grove_version ) ); } @@ -1217,7 +1222,8 @@ where false, is_sum_tree, /* we are in a sum tree, this might or might not be a * sum item */ - &mut batch_operations + &mut batch_operations, + grove_version ) ); } @@ -1228,7 +1234,8 @@ where key_info.get_key(), true, false, - &mut batch_operations + &mut batch_operations, + grove_version ) ); } @@ -1239,7 +1246,8 @@ where key_info.get_key(), true, true, - &mut batch_operations + &mut batch_operations, + grove_version ) ); } @@ -1256,7 +1264,8 @@ where root_key, hash, sum, - &mut batch_operations + &mut batch_operations, + grove_version ) ); } @@ -1282,7 +1291,8 @@ where hash, false, &mut batch_operations, - merk_feature_type + merk_feature_type, + grove_version ) ); } @@ -1295,17 +1305,17 @@ where &[], Some(batch_apply_options.as_merk_options()), &|key, value| { - Element::specialized_costs_for_key_value(key, value, is_sum_tree) + Element::specialized_costs_for_key_value(key, value, is_sum_tree, grove_version) .map_err(|e| MerkError::ClientCorruptionError(e.to_string())) }, Some(&Element::value_defined_cost_for_serialized_value), &mut |storage_costs, old_value, new_value| { // todo: change the flags without full deserialization - let old_element = Element::deserialize(old_value.as_slice()) + let old_element = Element::deserialize(old_value.as_slice(), grove_version) .map_err(|e| MerkError::ClientCorruptionError(e.to_string()))?; let maybe_old_flags = old_element.get_flags_owned(); - let mut new_element = Element::deserialize(new_value.as_slice()) + let mut new_element = Element::deserialize(new_value.as_slice(), grove_version) .map_err(|e| MerkError::ClientCorruptionError(e.to_string()))?; let maybe_new_flags = new_element.get_flags_mut(); match maybe_new_flags { @@ -1322,9 +1332,11 @@ where })?; if changed { let flags_len = new_flags.len() as u32; - new_value.clone_from(&new_element.serialize().map_err(|e| { - MerkError::ClientCorruptionError(e.to_string()) - })?); + new_value.clone_from( + &new_element.serialize(grove_version).map_err(|e| { + MerkError::ClientCorruptionError(e.to_string()) + })?, + ); // we need to give back the value defined cost in the case that the // new element is a tree match new_element { @@ -1357,7 +1369,7 @@ where } }, &mut |value, removed_key_bytes, removed_value_bytes| { - let mut element = Element::deserialize(value.as_slice()) + let mut element = Element::deserialize(value.as_slice(), grove_version) .map_err(|e| MerkError::ClientCorruptionError(e.to_string()))?; let maybe_flags = element.get_flags_mut(); match maybe_flags { @@ -1371,6 +1383,7 @@ where } } }, + grove_version, ) .map_err(|e| Error::CorruptedData(e.to_string())) ); @@ -1395,6 +1408,7 @@ impl GroveDb { fn apply_batch_structure, F, SR>( batch_structure: BatchStructure, batch_apply_options: Option, + grove_version: &GroveVersion, ) -> CostResult, Error> where F: FnMut(&StorageCost, Option, &mut ElementFlags) -> Result, @@ -1404,6 +1418,13 @@ impl GroveDb { u32, ) -> Result<(StorageRemovedBytes, StorageRemovedBytes), Error>, { + check_grovedb_v0_with_cost!( + "apply_batch_structure", + grove_version + .grovedb_versions + .apply_batch + .apply_batch_structure + ); let mut cost = OperationCost::default(); let BatchStructure { mut ops_by_level_paths, @@ -1433,6 +1454,7 @@ impl GroveDb { &batch_apply_options, &mut flags_update, &mut split_removal_bytes, + grove_version, ) ); if batch_apply_options.base_root_storage_is_free { @@ -1440,7 +1462,7 @@ impl GroveDb { let mut update_root_cost = cost_return_on_error_no_add!( &cost, merk_tree_cache - .update_base_merk_root_key(calculated_root_key) + .update_base_merk_root_key(calculated_root_key, grove_version) .cost_as_result() ); update_root_cost.storage_cost = StorageCost::default(); @@ -1448,7 +1470,8 @@ impl GroveDb { } else { cost_return_on_error!( &mut cost, - merk_tree_cache.update_base_merk_root_key(calculated_root_key) + merk_tree_cache + .update_base_merk_root_key(calculated_root_key, grove_version) ); } } else { @@ -1461,6 +1484,7 @@ impl GroveDb { &batch_apply_options, &mut flags_update, &mut split_removal_bytes, + grove_version, ) ); @@ -1609,7 +1633,12 @@ impl GroveDb { Error, >, get_merk_fn: impl FnMut(&[Vec], bool) -> CostResult, Error>, + grove_version: &GroveVersion, ) -> CostResult, Error> { + check_grovedb_v0_with_cost!( + "apply_body", + grove_version.grovedb_versions.apply_batch.apply_body + ); let mut cost = OperationCost::default(); let batch_structure = cost_return_on_error!( &mut cost, @@ -1623,7 +1652,8 @@ impl GroveDb { } ) ); - Self::apply_batch_structure(batch_structure, batch_apply_options).add_cost(cost) + Self::apply_batch_structure(batch_structure, batch_apply_options, grove_version) + .add_cost(cost) } /// Method to propagate updated subtree root hashes up to GroveDB root @@ -1648,7 +1678,15 @@ impl GroveDb { Error, >, get_merk_fn: impl FnMut(&[Vec], bool) -> CostResult, Error>, + grove_version: &GroveVersion, ) -> CostResult, Error> { + check_grovedb_v0_with_cost!( + "continue_partial_apply_body", + grove_version + .grovedb_versions + .apply_batch + .continue_partial_apply_body + ); let mut cost = OperationCost::default(); let batch_structure = cost_return_on_error!( &mut cost, @@ -1663,7 +1701,8 @@ impl GroveDb { } ) ); - Self::apply_batch_structure(batch_structure, batch_apply_options).add_cost(cost) + Self::apply_batch_structure(batch_structure, batch_apply_options, grove_version) + .add_cost(cost) } /// Applies operations on GroveDB without batching @@ -1672,7 +1711,15 @@ impl GroveDb { ops: Vec, options: Option, transaction: TransactionArg, + grove_version: &GroveVersion, ) -> CostResult<(), Error> { + check_grovedb_v0_with_cost!( + "apply_operations_without_batching", + grove_version + .grovedb_versions + .apply_batch + .apply_operations_without_batching + ); let mut cost = OperationCost::default(); for op in ops.into_iter() { match op.op { @@ -1688,6 +1735,7 @@ impl GroveDb { element.to_owned(), options.clone().map(|o| o.as_insert_options()), transaction, + grove_version, ) ); } @@ -1700,7 +1748,8 @@ impl GroveDb { path_slices.as_slice(), op.key.as_slice(), options.clone().map(|o| o.as_delete_options()), - transaction + transaction, + grove_version ) ); } @@ -1716,7 +1765,12 @@ impl GroveDb { ops: Vec, batch_apply_options: Option, transaction: TransactionArg, + grove_version: &GroveVersion, ) -> CostResult<(), Error> { + check_grovedb_v0_with_cost!( + "apply_batch", + grove_version.grovedb_versions.apply_batch.apply_batch + ); self.apply_batch_with_element_flags_update( ops, batch_apply_options, @@ -1728,6 +1782,7 @@ impl GroveDb { )) }, transaction, + grove_version, ) } @@ -1741,7 +1796,15 @@ impl GroveDb { &Option, ) -> Result, Error>, transaction: TransactionArg, + grove_version: &GroveVersion, ) -> CostResult<(), Error> { + check_grovedb_v0_with_cost!( + "apply_partial_batch", + grove_version + .grovedb_versions + .apply_batch + .apply_partial_batch + ); self.apply_partial_batch_with_element_flags_update( ops, batch_apply_options, @@ -1754,6 +1817,7 @@ impl GroveDb { }, cost_based_add_on_operations, transaction, + grove_version, ) } @@ -1765,7 +1829,15 @@ impl GroveDb { path: SubtreePath, tx: &'db Transaction, new_merk: bool, + grove_version: &GroveVersion, ) -> CostResult>, Error> { + check_grovedb_v0_with_cost!( + "open_batch_transactional_merk_at_path", + grove_version + .grovedb_versions + .apply_batch + .open_batch_transactional_merk_at_path + ); let mut cost = OperationCost::default(); let storage = self .db @@ -1783,12 +1855,14 @@ impl GroveDb { .unwrap_add_cost(&mut cost); let element = cost_return_on_error!( &mut cost, - Element::get_from_storage(&parent_storage, parent_key).map_err(|_| { - Error::InvalidPath(format!( - "could not get key for parent of subtree for batch at path {}", - parent_path.to_vec().into_iter().map(hex::encode).join("/") - )) - }) + Element::get_from_storage(&parent_storage, parent_key, grove_version).map_err( + |_| { + Error::InvalidPath(format!( + "could not get key for parent of subtree for batch at path {}", + parent_path.to_vec().into_iter().map(hex::encode).join("/") + )) + } + ) ); let is_sum_tree = element.is_sum_tree(); if let Element::Tree(root_key, _) | Element::SumTree(root_key, ..) = element { @@ -1797,6 +1871,7 @@ impl GroveDb { root_key, is_sum_tree, Some(&Element::value_defined_cost_for_serialized_value), + grove_version, ) .map_err(|_| { Error::CorruptedData("cannot open a subtree with given root key".to_owned()) @@ -1816,6 +1891,7 @@ impl GroveDb { storage, false, Some(&Element::value_defined_cost_for_serialized_value), + grove_version, ) .map_err(|_| Error::CorruptedData("cannot open a the root subtree".to_owned())) .add_cost(cost) @@ -1828,7 +1904,15 @@ impl GroveDb { storage_batch: &'a StorageBatch, path: SubtreePath, new_merk: bool, + grove_version: &GroveVersion, ) -> CostResult, Error> { + check_grovedb_v0_with_cost!( + "open_batch_merk_at_path", + grove_version + .grovedb_versions + .apply_batch + .open_batch_merk_at_path + ); let mut local_cost = OperationCost::default(); let storage = self .db @@ -1849,7 +1933,7 @@ impl GroveDb { .unwrap_add_cost(&mut local_cost); let element = cost_return_on_error!( &mut local_cost, - Element::get_from_storage(&parent_storage, last) + Element::get_from_storage(&parent_storage, last, grove_version) ); let is_sum_tree = element.is_sum_tree(); if let Element::Tree(root_key, _) | Element::SumTree(root_key, ..) = element { @@ -1858,6 +1942,7 @@ impl GroveDb { root_key, is_sum_tree, Some(&Element::value_defined_cost_for_serialized_value), + grove_version, ) .map_err(|_| { Error::CorruptedData("cannot open a subtree with given root key".to_owned()) @@ -1874,6 +1959,7 @@ impl GroveDb { storage, false, Some(&Element::value_defined_cost_for_serialized_value), + grove_version, ) .map_err(|_| Error::CorruptedData("cannot open a subtree".to_owned())) .add_cost(local_cost) @@ -1899,7 +1985,15 @@ impl GroveDb { Error, >, transaction: TransactionArg, + grove_version: &GroveVersion, ) -> CostResult<(), Error> { + check_grovedb_v0_with_cost!( + "apply_batch_with_element_flags_update", + grove_version + .grovedb_versions + .apply_batch + .apply_batch_with_element_flags_update + ); let mut cost = OperationCost::default(); if ops.is_empty() { @@ -1952,8 +2046,10 @@ impl GroveDb { path.into(), tx, new_merk, + grove_version, ) - } + }, + grove_version ) ); @@ -1973,8 +2069,14 @@ impl GroveDb { update_element_flags_function, split_removal_bytes_function, |path, new_merk| { - self.open_batch_merk_at_path(&storage_batch, path.into(), new_merk) - } + self.open_batch_merk_at_path( + &storage_batch, + path.into(), + new_merk, + grove_version, + ) + }, + grove_version ) ); @@ -2015,7 +2117,15 @@ impl GroveDb { &Option, ) -> Result, Error>, transaction: TransactionArg, + grove_version: &GroveVersion, ) -> CostResult<(), Error> { + check_grovedb_v0_with_cost!( + "apply_partial_batch_with_element_flags_update", + grove_version + .grovedb_versions + .apply_batch + .apply_partial_batch_with_element_flags_update + ); let mut cost = OperationCost::default(); if ops.is_empty() { @@ -2072,8 +2182,10 @@ impl GroveDb { path.into(), tx, new_merk, + grove_version, ) - } + }, + grove_version ) ); // if we paused at the root height, the left over operations would be to replace @@ -2118,8 +2230,10 @@ impl GroveDb { path.into(), tx, new_merk, + grove_version, ) - } + }, + grove_version ) ); @@ -2149,8 +2263,14 @@ impl GroveDb { &mut update_element_flags_function, &mut split_removal_bytes_function, |path, new_merk| { - self.open_batch_merk_at_path(&storage_batch, path.into(), new_merk) - } + self.open_batch_merk_at_path( + &storage_batch, + path.into(), + new_merk, + grove_version, + ) + }, + grove_version ) ); @@ -2189,8 +2309,14 @@ impl GroveDb { update_element_flags_function, split_removal_bytes_function, |path, new_merk| { - self.open_batch_merk_at_path(&continue_storage_batch, path.into(), new_merk) - } + self.open_batch_merk_at_path( + &continue_storage_batch, + path.into(), + new_merk, + grove_version, + ) + }, + grove_version ) ); @@ -2235,7 +2361,15 @@ impl GroveDb { (StorageRemovedBytes, StorageRemovedBytes), Error, >, + grove_version: &GroveVersion, ) -> CostResult<(), Error> { + check_grovedb_v0_with_cost!( + "estimated_case_operations_for_batch", + grove_version + .grovedb_versions + .apply_batch + .estimated_case_operations_for_batch + ); let mut cost = OperationCost::default(); if ops.is_empty() { @@ -2257,7 +2391,11 @@ impl GroveDb { ); cost_return_on_error!( &mut cost, - Self::apply_batch_structure(batch_structure, batch_apply_options) + Self::apply_batch_structure( + batch_structure, + batch_apply_options, + grove_version + ) ); } @@ -2275,7 +2413,11 @@ impl GroveDb { ); cost_return_on_error!( &mut cost, - Self::apply_batch_structure(batch_structure, batch_apply_options) + Self::apply_batch_structure( + batch_structure, + batch_apply_options, + grove_version + ) ); } } @@ -2300,7 +2442,8 @@ mod tests { #[test] fn test_batch_validation_ok() { - let db = make_test_grovedb(); + let grove_version = GroveVersion::latest(); + let db = make_test_grovedb(grove_version); let element = Element::new_item(b"ayy".to_vec()); let element2 = Element::new_item(b"ayy2".to_vec()); let ops = vec![ @@ -2331,32 +2474,47 @@ mod tests { element2.clone(), ), ]; - db.apply_batch(ops, None, None) + db.apply_batch(ops, None, None, grove_version) .unwrap() .expect("cannot apply batch"); // visualize_stderr(&db); - db.get(EMPTY_PATH, b"key1", None) - .unwrap() - .expect("cannot get element"); - db.get([b"key1".as_ref()].as_ref(), b"key2", None) + db.get(EMPTY_PATH, b"key1", None, grove_version) .unwrap() .expect("cannot get element"); - db.get([b"key1".as_ref(), b"key2"].as_ref(), b"key3", None) - .unwrap() - .expect("cannot get element"); - db.get([b"key1".as_ref(), b"key2", b"key3"].as_ref(), b"key4", None) + db.get([b"key1".as_ref()].as_ref(), b"key2", None, grove_version) .unwrap() .expect("cannot get element"); + db.get( + [b"key1".as_ref(), b"key2"].as_ref(), + b"key3", + None, + grove_version, + ) + .unwrap() + .expect("cannot get element"); + db.get( + [b"key1".as_ref(), b"key2", b"key3"].as_ref(), + b"key4", + None, + grove_version, + ) + .unwrap() + .expect("cannot get element"); assert_eq!( - db.get([b"key1".as_ref(), b"key2", b"key3"].as_ref(), b"key4", None) - .unwrap() - .expect("cannot get element"), + db.get( + [b"key1".as_ref(), b"key2", b"key3"].as_ref(), + b"key4", + None, + grove_version + ) + .unwrap() + .expect("cannot get element"), element ); assert_eq!( - db.get([TEST_LEAF, b"key1"].as_ref(), b"key2", None) + db.get([TEST_LEAF, b"key1"].as_ref(), b"key2", None, grove_version) .unwrap() .expect("cannot get element"), element2 @@ -2365,7 +2523,8 @@ mod tests { #[test] fn test_batch_operation_consistency_checker() { - let db = make_test_grovedb(); + let grove_version = GroveVersion::latest(); + let db = make_test_grovedb(grove_version); // No two operations should be the same let ops = vec![ @@ -2373,7 +2532,7 @@ mod tests { GroveDbOp::insert_op(vec![b"a".to_vec()], b"b".to_vec(), Element::empty_tree()), ]; assert!(matches!( - db.apply_batch(ops, None, None).unwrap(), + db.apply_batch(ops, None, None, grove_version).unwrap(), Err(Error::InvalidBatchOperation( "batch operations fail consistency checks" )) @@ -2389,7 +2548,7 @@ mod tests { GroveDbOp::insert_op(vec![b"a".to_vec()], b"b".to_vec(), Element::empty_tree()), ]; assert!(matches!( - db.apply_batch(ops, None, None).unwrap(), + db.apply_batch(ops, None, None, grove_version).unwrap(), Err(Error::InvalidBatchOperation( "batch operations fail consistency checks" )) @@ -2405,7 +2564,7 @@ mod tests { GroveDbOp::delete_op(vec![], TEST_LEAF.to_vec()), ]; assert!(matches!( - db.apply_batch(ops, None, None).unwrap(), + db.apply_batch(ops, None, None, grove_version).unwrap(), Err(Error::InvalidBatchOperation( "batch operations fail consistency checks" )) @@ -2436,7 +2595,8 @@ mod tests { base_root_storage_is_free: true, batch_pause_height: None, }), - None + None, + grove_version ) .unwrap() .is_ok()); @@ -2444,12 +2604,20 @@ mod tests { #[test] fn test_batch_validation_ok_on_transaction() { - let db = make_test_grovedb(); + let grove_version = GroveVersion::latest(); + let db = make_test_grovedb(grove_version); let tx = db.start_transaction(); - db.insert(EMPTY_PATH, b"keyb", Element::empty_tree(), None, Some(&tx)) - .unwrap() - .expect("successful root tree leaf insert"); + db.insert( + EMPTY_PATH, + b"keyb", + Element::empty_tree(), + None, + Some(&tx), + grove_version, + ) + .unwrap() + .expect("successful root tree leaf insert"); let element = Element::new_item(b"ayy".to_vec()); let element2 = Element::new_item(b"ayy2".to_vec()); @@ -2481,32 +2649,43 @@ mod tests { element2.clone(), ), ]; - db.apply_batch(ops, None, Some(&tx)) + db.apply_batch(ops, None, Some(&tx), grove_version) .unwrap() .expect("cannot apply batch"); - db.get(EMPTY_PATH, b"keyb", None) + db.get(EMPTY_PATH, b"keyb", None, grove_version) .unwrap() .expect_err("we should not get an element"); - db.get(EMPTY_PATH, b"keyb", Some(&tx)) + db.get(EMPTY_PATH, b"keyb", Some(&tx), grove_version) .unwrap() .expect("we should get an element"); - db.get(EMPTY_PATH, b"key1", None) + db.get(EMPTY_PATH, b"key1", None, grove_version) .unwrap() .expect_err("we should not get an element"); - db.get(EMPTY_PATH, b"key1", Some(&tx)) - .unwrap() - .expect("cannot get element"); - db.get([b"key1".as_ref()].as_ref(), b"key2", Some(&tx)) - .unwrap() - .expect("cannot get element"); - db.get([b"key1".as_ref(), b"key2"].as_ref(), b"key3", Some(&tx)) + db.get(EMPTY_PATH, b"key1", Some(&tx), grove_version) .unwrap() .expect("cannot get element"); + db.get( + [b"key1".as_ref()].as_ref(), + b"key2", + Some(&tx), + grove_version, + ) + .unwrap() + .expect("cannot get element"); + db.get( + [b"key1".as_ref(), b"key2"].as_ref(), + b"key3", + Some(&tx), + grove_version, + ) + .unwrap() + .expect("cannot get element"); db.get( [b"key1".as_ref(), b"key2", b"key3"].as_ref(), b"key4", Some(&tx), + grove_version, ) .unwrap() .expect("cannot get element"); @@ -2515,22 +2694,29 @@ mod tests { db.get( [b"key1".as_ref(), b"key2", b"key3"].as_ref(), b"key4", - Some(&tx) + Some(&tx), + grove_version ) .unwrap() .expect("cannot get element"), element ); assert_eq!( - db.get([TEST_LEAF, b"key1"].as_ref(), b"key2", Some(&tx)) - .unwrap() - .expect("cannot get element"), + db.get( + [TEST_LEAF, b"key1"].as_ref(), + b"key2", + Some(&tx), + grove_version + ) + .unwrap() + .expect("cannot get element"), element2 ); } #[test] fn test_batch_add_other_element_in_sub_tree() { + let grove_version = GroveVersion::latest(); let db = make_empty_grovedb(); let tx = db.start_transaction(); // let's start by inserting a tree structure @@ -2586,6 +2772,7 @@ mod tests { Ok((NoStorageRemoval, NoStorageRemoval)) }, Some(&tx), + grove_version, ) .unwrap() .expect("expected to do tree form insert"); @@ -2661,6 +2848,7 @@ mod tests { Ok((NoStorageRemoval, NoStorageRemoval)) }, Some(&tx), + grove_version, ) .unwrap() .expect("expected to do first insert"); @@ -2736,6 +2924,7 @@ mod tests { Ok((NoStorageRemoval, NoStorageRemoval)) }, Some(&tx), + grove_version, ) .unwrap() .expect("successful batch apply"); @@ -2880,37 +3069,40 @@ mod tests { #[ignore] #[test] fn test_batch_produces_same_result() { - let db = make_test_grovedb(); + let grove_version = GroveVersion::latest(); + let db = make_test_grovedb(grove_version); let tx = db.start_transaction(); let ops = grove_db_ops_for_contract_insert(); - db.apply_batch(ops, None, Some(&tx)) + db.apply_batch(ops, None, Some(&tx), grove_version) .unwrap() .expect("expected to apply batch"); - db.root_hash(None).unwrap().expect("cannot get root hash"); + db.root_hash(None, grove_version) + .unwrap() + .expect("cannot get root hash"); - let db = make_test_grovedb(); + let db = make_test_grovedb(grove_version); let tx = db.start_transaction(); let ops = grove_db_ops_for_contract_insert(); - db.apply_batch(ops.clone(), None, Some(&tx)) + db.apply_batch(ops.clone(), None, Some(&tx), grove_version) .unwrap() .expect("expected to apply batch"); let batch_hash = db - .root_hash(Some(&tx)) + .root_hash(Some(&tx), grove_version) .unwrap() .expect("cannot get root hash"); db.rollback_transaction(&tx).expect("expected to rollback"); - db.apply_operations_without_batching(ops, None, Some(&tx)) + db.apply_operations_without_batching(ops, None, Some(&tx), grove_version) .unwrap() .expect("expected to apply batch"); let no_batch_hash = db - .root_hash(Some(&tx)) + .root_hash(Some(&tx), grove_version) .unwrap() .expect("cannot get root hash"); @@ -2920,44 +3112,47 @@ mod tests { #[ignore] #[test] fn test_batch_contract_with_document_produces_same_result() { - let db = make_test_grovedb(); + let grove_version = GroveVersion::latest(); + let db = make_test_grovedb(grove_version); let tx = db.start_transaction(); let ops = grove_db_ops_for_contract_insert(); - db.apply_batch(ops, None, Some(&tx)) + db.apply_batch(ops, None, Some(&tx), grove_version) .unwrap() .expect("expected to apply batch"); - db.root_hash(None).unwrap().expect("cannot get root hash"); + db.root_hash(None, grove_version) + .unwrap() + .expect("cannot get root hash"); - let db = make_test_grovedb(); + let db = make_test_grovedb(grove_version); let tx = db.start_transaction(); let ops = grove_db_ops_for_contract_insert(); let document_ops = grove_db_ops_for_contract_document_insert(); - db.apply_batch(ops.clone(), None, Some(&tx)) + db.apply_batch(ops.clone(), None, Some(&tx), grove_version) .unwrap() .expect("expected to apply batch"); - db.apply_batch(document_ops.clone(), None, Some(&tx)) + db.apply_batch(document_ops.clone(), None, Some(&tx), grove_version) .unwrap() .expect("expected to apply batch"); let batch_hash = db - .root_hash(Some(&tx)) + .root_hash(Some(&tx), grove_version) .unwrap() .expect("cannot get root hash"); db.rollback_transaction(&tx).expect("expected to rollback"); - db.apply_operations_without_batching(ops, None, Some(&tx)) + db.apply_operations_without_batching(ops, None, Some(&tx), grove_version) .unwrap() .expect("expected to apply batch"); - db.apply_operations_without_batching(document_ops, None, Some(&tx)) + db.apply_operations_without_batching(document_ops, None, Some(&tx), grove_version) .unwrap() .expect("expected to apply batch"); let no_batch_hash = db - .root_hash(Some(&tx)) + .root_hash(Some(&tx), grove_version) .unwrap() .expect("cannot get root hash"); @@ -2966,7 +3161,8 @@ mod tests { #[test] fn test_batch_validation_broken_chain() { - let db = make_test_grovedb(); + let grove_version = GroveVersion::latest(); + let db = make_test_grovedb(grove_version); let element = Element::new_item(b"ayy".to_vec()); let ops = vec![ GroveDbOp::insert_op(vec![], b"key1".to_vec(), Element::empty_tree()), @@ -2981,16 +3177,20 @@ mod tests { Element::empty_tree(), ), ]; - assert!(db.apply_batch(ops, None, None).unwrap().is_err()); assert!(db - .get([b"key1".as_ref()].as_ref(), b"key2", None) + .apply_batch(ops, None, None, grove_version) + .unwrap() + .is_err()); + assert!(db + .get([b"key1".as_ref()].as_ref(), b"key2", None, grove_version) .unwrap() .is_err()); } #[test] fn test_batch_validation_broken_chain_aborts_whole_batch() { - let db = make_test_grovedb(); + let grove_version = GroveVersion::latest(); + let db = make_test_grovedb(grove_version); let element = Element::new_item(b"ayy".to_vec()); let ops = vec![ GroveDbOp::insert_op( @@ -3015,31 +3215,43 @@ mod tests { Element::empty_tree(), ), ]; - assert!(db.apply_batch(ops, None, None).unwrap().is_err()); assert!(db - .get([b"key1".as_ref()].as_ref(), b"key2", None) + .apply_batch(ops, None, None, grove_version) .unwrap() .is_err()); assert!(db - .get([TEST_LEAF, b"key1"].as_ref(), b"key2", None) + .get([b"key1".as_ref()].as_ref(), b"key2", None, grove_version) + .unwrap() + .is_err()); + assert!(db + .get([TEST_LEAF, b"key1"].as_ref(), b"key2", None, grove_version) .unwrap() .is_err(),); } #[test] fn test_batch_validation_deletion_brokes_chain() { - let db = make_test_grovedb(); + let grove_version = GroveVersion::latest(); + let db = make_test_grovedb(grove_version); let element = Element::new_item(b"ayy".to_vec()); - db.insert(EMPTY_PATH, b"key1", Element::empty_tree(), None, None) - .unwrap() - .expect("cannot insert a subtree"); + db.insert( + EMPTY_PATH, + b"key1", + Element::empty_tree(), + None, + None, + grove_version, + ) + .unwrap() + .expect("cannot insert a subtree"); db.insert( [b"key1".as_ref()].as_ref(), b"key2", Element::empty_tree(), None, None, + grove_version, ) .unwrap() .expect("cannot insert a subtree"); @@ -3057,12 +3269,16 @@ mod tests { ), GroveDbOp::delete_op(vec![b"key1".to_vec()], b"key2".to_vec()), ]; - assert!(db.apply_batch(ops, None, None).unwrap().is_err()); + assert!(db + .apply_batch(ops, None, None, grove_version) + .unwrap() + .is_err()); } #[test] fn test_batch_validation_insertion_under_deleted_tree() { - let db = make_test_grovedb(); + let grove_version = GroveVersion::latest(); + let db = make_test_grovedb(grove_version); let element = Element::new_item(b"ayy".to_vec()); let ops = vec![ GroveDbOp::insert_op(vec![], b"key1".to_vec(), Element::empty_tree()), @@ -3083,17 +3299,23 @@ mod tests { ), GroveDbOp::delete_op(vec![b"key1".to_vec()], b"key2".to_vec()), ]; - db.apply_batch(ops, None, None) + db.apply_batch(ops, None, None, grove_version) .unwrap() .expect_err("insertion of element under a deleted tree should not be allowed"); - db.get([b"key1".as_ref(), b"key2", b"key3"].as_ref(), b"key4", None) - .unwrap() - .expect_err("nothing should have been inserted"); + db.get( + [b"key1".as_ref(), b"key2", b"key3"].as_ref(), + b"key4", + None, + grove_version, + ) + .unwrap() + .expect_err("nothing should have been inserted"); } #[test] fn test_batch_validation_insert_into_existing_tree() { - let db = make_test_grovedb(); + let grove_version = GroveVersion::latest(); + let db = make_test_grovedb(grove_version); let element = Element::new_item(b"ayy".to_vec()); db.insert( @@ -3102,6 +3324,7 @@ mod tests { element.clone(), None, None, + grove_version, ) .unwrap() .expect("cannot insert value"); @@ -3111,6 +3334,7 @@ mod tests { Element::empty_tree(), None, None, + grove_version, ) .unwrap() .expect("cannot insert value"); @@ -3121,7 +3345,10 @@ mod tests { b"key1".to_vec(), element.clone(), )]; - assert!(db.apply_batch(ops, None, None).unwrap().is_err()); + assert!(db + .apply_batch(ops, None, None, grove_version) + .unwrap() + .is_err()); // Insertion into a tree is correct let ops = vec![GroveDbOp::insert_op( @@ -3129,11 +3356,11 @@ mod tests { b"key1".to_vec(), element.clone(), )]; - db.apply_batch(ops, None, None) + db.apply_batch(ops, None, None, grove_version) .unwrap() .expect("cannot apply batch"); assert_eq!( - db.get([TEST_LEAF, b"valid"].as_ref(), b"key1", None) + db.get([TEST_LEAF, b"valid"].as_ref(), b"key1", None, grove_version) .unwrap() .expect("cannot get element"), element @@ -3142,7 +3369,8 @@ mod tests { #[test] fn test_batch_validation_nested_subtree_overwrite() { - let db = make_test_grovedb(); + let grove_version = GroveVersion::latest(); + let db = make_test_grovedb(grove_version); let element = Element::new_item(b"ayy".to_vec()); let element2 = Element::new_item(b"ayy2".to_vec()); db.insert( @@ -3151,6 +3379,7 @@ mod tests { Element::empty_tree(), None, None, + grove_version, ) .unwrap() .expect("cannot insert a subtree"); @@ -3160,6 +3389,7 @@ mod tests { element, None, None, + grove_version, ) .unwrap() .expect("cannot insert an item"); @@ -3185,7 +3415,8 @@ mod tests { base_root_storage_is_free: true, batch_pause_height: None, }), - None + None, + grove_version ) .unwrap() .is_err()); @@ -3199,7 +3430,10 @@ mod tests { Element::empty_tree(), ), ]; - assert!(db.apply_batch(ops, None, None).unwrap().is_err()); + assert!(db + .apply_batch(ops, None, None, grove_version) + .unwrap() + .is_err()); // TEST_LEAF will be deleted so you can not insert underneath it // We are testing with the batch apply option @@ -3224,7 +3458,8 @@ mod tests { base_root_storage_is_free: true, batch_pause_height: None, }), - None + None, + grove_version ) .unwrap() .is_err()); @@ -3232,7 +3467,8 @@ mod tests { #[test] fn test_batch_validation_root_leaf_removal() { - let db = make_test_grovedb(); + let grove_version = GroveVersion::latest(); + let db = make_test_grovedb(grove_version); let ops = vec![ GroveDbOp::insert_op( vec![], @@ -3257,7 +3493,8 @@ mod tests { base_root_storage_is_free: true, batch_pause_height: None, }), - None + None, + grove_version ) .unwrap() .is_err()); @@ -3265,7 +3502,8 @@ mod tests { #[test] fn test_merk_data_is_deleted() { - let db = make_test_grovedb(); + let grove_version = GroveVersion::latest(); + let db = make_test_grovedb(grove_version); let element = Element::new_item(b"ayy".to_vec()); db.insert( @@ -3274,6 +3512,7 @@ mod tests { Element::empty_tree(), None, None, + grove_version, ) .unwrap() .expect("cannot insert a subtree"); @@ -3283,6 +3522,7 @@ mod tests { element.clone(), None, None, + grove_version, ) .unwrap() .expect("cannot insert an item"); @@ -3293,40 +3533,59 @@ mod tests { )]; assert_eq!( - db.get([TEST_LEAF, b"key1"].as_ref(), b"key2", None) + db.get([TEST_LEAF, b"key1"].as_ref(), b"key2", None, grove_version) .unwrap() .expect("cannot get item"), element ); - db.apply_batch(ops, None, None) + db.apply_batch(ops, None, None, grove_version) .unwrap() .expect("cannot apply batch"); assert!(db - .get([TEST_LEAF, b"key1"].as_ref(), b"key2", None) + .get([TEST_LEAF, b"key1"].as_ref(), b"key2", None, grove_version) .unwrap() .is_err()); } #[test] fn test_multi_tree_insertion_deletion_with_propagation_no_tx() { - let db = make_test_grovedb(); - db.insert(EMPTY_PATH, b"key1", Element::empty_tree(), None, None) - .unwrap() - .expect("cannot insert root leaf"); - db.insert(EMPTY_PATH, b"key2", Element::empty_tree(), None, None) - .unwrap() - .expect("cannot insert root leaf"); + let grove_version = GroveVersion::latest(); + let db = make_test_grovedb(grove_version); + db.insert( + EMPTY_PATH, + b"key1", + Element::empty_tree(), + None, + None, + grove_version, + ) + .unwrap() + .expect("cannot insert root leaf"); + db.insert( + EMPTY_PATH, + b"key2", + Element::empty_tree(), + None, + None, + grove_version, + ) + .unwrap() + .expect("cannot insert root leaf"); db.insert( [ANOTHER_TEST_LEAF].as_ref(), b"key1", Element::empty_tree(), None, None, + grove_version, ) .unwrap() .expect("cannot insert root leaf"); - let hash = db.root_hash(None).unwrap().expect("cannot get root hash"); + let hash = db + .root_hash(None, grove_version) + .unwrap() + .expect("cannot get root hash"); let element = Element::new_item(b"ayy".to_vec()); let element2 = Element::new_item(b"ayy2".to_vec()); @@ -3349,43 +3608,66 @@ mod tests { GroveDbOp::insert_op(vec![TEST_LEAF.to_vec()], b"key".to_vec(), element2.clone()), GroveDbOp::delete_op(vec![ANOTHER_TEST_LEAF.to_vec()], b"key1".to_vec()), ]; - db.apply_batch(ops, None, None) + db.apply_batch(ops, None, None, grove_version) .unwrap() .expect("cannot apply batch"); assert!(db - .get([ANOTHER_TEST_LEAF].as_ref(), b"key1", None) + .get([ANOTHER_TEST_LEAF].as_ref(), b"key1", None, grove_version) .unwrap() .is_err()); assert_eq!( - db.get([b"key1".as_ref(), b"key2", b"key3"].as_ref(), b"key4", None) - .unwrap() - .expect("cannot get element"), + db.get( + [b"key1".as_ref(), b"key2", b"key3"].as_ref(), + b"key4", + None, + grove_version + ) + .unwrap() + .expect("cannot get element"), element ); assert_eq!( - db.get([TEST_LEAF].as_ref(), b"key", None) + db.get([TEST_LEAF].as_ref(), b"key", None, grove_version) .unwrap() .expect("cannot get element"), element2 ); assert_ne!( - db.root_hash(None).unwrap().expect("cannot get root hash"), + db.root_hash(None, grove_version) + .unwrap() + .expect("cannot get root hash"), hash ); // verify root leaves - assert!(db.get(EMPTY_PATH, TEST_LEAF, None).unwrap().is_ok()); - assert!(db.get(EMPTY_PATH, ANOTHER_TEST_LEAF, None).unwrap().is_ok()); - assert!(db.get(EMPTY_PATH, b"key1", None).unwrap().is_ok()); - assert!(db.get(EMPTY_PATH, b"key2", None).unwrap().is_ok()); - assert!(db.get(EMPTY_PATH, b"key3", None).unwrap().is_err()); + assert!(db + .get(EMPTY_PATH, TEST_LEAF, None, grove_version) + .unwrap() + .is_ok()); + assert!(db + .get(EMPTY_PATH, ANOTHER_TEST_LEAF, None, grove_version) + .unwrap() + .is_ok()); + assert!(db + .get(EMPTY_PATH, b"key1", None, grove_version) + .unwrap() + .is_ok()); + assert!(db + .get(EMPTY_PATH, b"key2", None, grove_version) + .unwrap() + .is_ok()); + assert!(db + .get(EMPTY_PATH, b"key3", None, grove_version) + .unwrap() + .is_err()); } #[test] fn test_nested_batch_insertion_corrupts_state() { - let db = make_test_grovedb(); + let grove_version = GroveVersion::latest(); + let db = make_test_grovedb(grove_version); let full_path = vec![ b"leaf1".to_vec(), b"sub1".to_vec(), @@ -3396,9 +3678,16 @@ mod tests { ]; let mut acc_path: Vec> = vec![]; for p in full_path.into_iter() { - db.insert(acc_path.as_slice(), &p, Element::empty_tree(), None, None) - .unwrap() - .expect("expected to insert"); + db.insert( + acc_path.as_slice(), + &p, + Element::empty_tree(), + None, + None, + grove_version, + ) + .unwrap() + .expect("expected to insert"); acc_path.push(p); } @@ -3408,29 +3697,37 @@ mod tests { b"key".to_vec(), element.clone(), )]; - db.apply_batch(batch, None, None) + db.apply_batch(batch, None, None, grove_version) .unwrap() .expect("cannot apply batch"); let batch = vec![GroveDbOp::insert_op(acc_path, b"key".to_vec(), element)]; - db.apply_batch(batch, None, None) + db.apply_batch(batch, None, None, grove_version) .unwrap() .expect("cannot apply same batch twice"); } #[test] fn test_apply_sorted_pre_validated_batch_propagation() { - let db = make_test_grovedb(); + let grove_version = GroveVersion::latest(); + let db = make_test_grovedb(grove_version); let full_path = vec![b"leaf1".to_vec(), b"sub1".to_vec()]; let mut acc_path: Vec> = vec![]; for p in full_path.into_iter() { - db.insert(acc_path.as_slice(), &p, Element::empty_tree(), None, None) - .unwrap() - .expect("expected to insert"); + db.insert( + acc_path.as_slice(), + &p, + Element::empty_tree(), + None, + None, + grove_version, + ) + .unwrap() + .expect("expected to insert"); acc_path.push(p); } - let root_hash = db.root_hash(None).unwrap().unwrap(); + let root_hash = db.root_hash(None, grove_version).unwrap().unwrap(); let element = Element::new_item(b"ayy".to_vec()); let batch = vec![GroveDbOp::insert_op( @@ -3438,17 +3735,21 @@ mod tests { b"key".to_vec(), element, )]; - db.apply_batch(batch, None, None) + db.apply_batch(batch, None, None, grove_version) .unwrap() .expect("cannot apply batch"); - assert_ne!(db.root_hash(None).unwrap().unwrap(), root_hash); + assert_ne!( + db.root_hash(None, grove_version).unwrap().unwrap(), + root_hash + ); } #[test] fn test_references() { + let grove_version = GroveVersion::latest(); // insert reference that points to non-existent item - let db = make_test_grovedb(); + let db = make_test_grovedb(grove_version); let batch = vec![GroveDbOp::insert_op( vec![TEST_LEAF.to_vec()], b"key1".to_vec(), @@ -3458,12 +3759,12 @@ mod tests { ])), )]; assert!(matches!( - db.apply_batch(batch, None, None).unwrap(), + db.apply_batch(batch, None, None, grove_version).unwrap(), Err(Error::MissingReference(String { .. })) )); // insert reference with item it points to in the same batch - let db = make_test_grovedb(); + let db = make_test_grovedb(grove_version); let elem = Element::new_item(b"ayy".to_vec()); let batch = vec![ GroveDbOp::insert_op( @@ -3480,9 +3781,12 @@ mod tests { elem.clone(), ), ]; - assert!(db.apply_batch(batch, None, None).unwrap().is_ok()); + assert!(db + .apply_batch(batch, None, None, grove_version) + .unwrap() + .is_ok()); assert_eq!( - db.get([TEST_LEAF].as_ref(), b"key1", None) + db.get([TEST_LEAF].as_ref(), b"key1", None, grove_version) .unwrap() .unwrap(), elem @@ -3493,15 +3797,15 @@ mod tests { reference_key_query.insert_key(b"key1".to_vec()); let path_query = PathQuery::new_unsized(vec![TEST_LEAF.to_vec()], reference_key_query); let proof = db - .prove_query(&path_query, None) + .prove_query(&path_query, None, grove_version) .unwrap() .expect("should generate proof"); - let verification_result = GroveDb::verify_query_raw(&proof, &path_query); + let verification_result = GroveDb::verify_query_raw(&proof, &path_query, grove_version); assert!(verification_result.is_ok()); // Hit reference limit when you specify max reference hop, lower than actual hop // count - let db = make_test_grovedb(); + let db = make_test_grovedb(grove_version); let elem = Element::new_item(b"ayy".to_vec()); let batch = vec![ GroveDbOp::insert_op( @@ -3529,7 +3833,7 @@ mod tests { GroveDbOp::insert_op(vec![TEST_LEAF.to_vec()], b"invalid_path".to_vec(), elem), ]; assert!(matches!( - db.apply_batch(batch, None, None).unwrap(), + db.apply_batch(batch, None, None, grove_version).unwrap(), Err(Error::ReferenceLimit) )); } diff --git a/grovedb/src/batch/mode.rs b/grovedb/src/batch/mode.rs index 76f15b6d..897d15f2 100644 --- a/grovedb/src/batch/mode.rs +++ b/grovedb/src/batch/mode.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. - //! Batch running mode #[cfg(feature = "estimated_costs")] diff --git a/grovedb/src/batch/multi_insert_cost_tests.rs b/grovedb/src/batch/multi_insert_cost_tests.rs index 501cc50a..ad171d6d 100644 --- a/grovedb/src/batch/multi_insert_cost_tests.rs +++ b/grovedb/src/batch/multi_insert_cost_tests.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. - //! Multi insert cost tests #[cfg(feature = "full")] @@ -36,6 +8,7 @@ mod tests { storage_cost::{removal::StorageRemovedBytes::NoStorageRemoval, StorageCost}, OperationCost, }; + use grovedb_version::version::GroveVersion; use crate::{ batch::GroveDbOp, @@ -46,14 +19,29 @@ mod tests { #[test] fn test_batch_two_insert_empty_tree_same_level_added_bytes_match_non_batch() { + let grove_version = GroveVersion::latest(); let db = make_empty_grovedb(); let tx = db.start_transaction(); let non_batch_cost_1 = db - .insert(EMPTY_PATH, b"key1", Element::empty_tree(), None, Some(&tx)) + .insert( + EMPTY_PATH, + b"key1", + Element::empty_tree(), + None, + Some(&tx), + grove_version, + ) .cost; let non_batch_cost_2 = db - .insert(EMPTY_PATH, b"key2", Element::empty_tree(), None, Some(&tx)) + .insert( + EMPTY_PATH, + b"key2", + Element::empty_tree(), + None, + Some(&tx), + grove_version, + ) .cost; let non_batch_cost = non_batch_cost_1.add(non_batch_cost_2); tx.rollback().expect("expected to rollback"); @@ -61,7 +49,7 @@ mod tests { GroveDbOp::insert_op(vec![], b"key1".to_vec(), Element::empty_tree()), GroveDbOp::insert_op(vec![], b"key2".to_vec(), Element::empty_tree()), ]; - let cost = db.apply_batch(ops, None, Some(&tx)).cost; + let cost = db.apply_batch(ops, None, Some(&tx), grove_version).cost; assert_eq!( non_batch_cost.storage_cost.added_bytes, cost.storage_cost.added_bytes @@ -72,11 +60,19 @@ mod tests { #[test] fn test_batch_three_inserts_elements_same_level_added_bytes_match_non_batch() { + let grove_version = GroveVersion::latest(); let db = make_empty_grovedb(); let tx = db.start_transaction(); let non_batch_cost_1 = db - .insert(EMPTY_PATH, b"key1", Element::empty_tree(), None, Some(&tx)) + .insert( + EMPTY_PATH, + b"key1", + Element::empty_tree(), + None, + Some(&tx), + grove_version, + ) .cost; let non_batch_cost_2 = db .insert( @@ -85,6 +81,7 @@ mod tests { Element::new_item_with_flags(b"pizza".to_vec(), Some([0, 1].to_vec())), None, Some(&tx), + grove_version, ) .cost; let non_batch_cost_3 = db @@ -94,6 +91,7 @@ mod tests { Element::new_reference(SiblingReference(b"key2".to_vec())), None, Some(&tx), + grove_version, ) .cost; let non_batch_cost = non_batch_cost_1.add(non_batch_cost_2).add(non_batch_cost_3); @@ -111,7 +109,7 @@ mod tests { Element::new_reference(SiblingReference(b"key2".to_vec())), ), ]; - let cost = db.apply_batch(ops, None, Some(&tx)).cost; + let cost = db.apply_batch(ops, None, Some(&tx), grove_version).cost; assert_eq!( non_batch_cost.storage_cost.added_bytes, cost.storage_cost.added_bytes @@ -122,11 +120,19 @@ mod tests { #[test] fn test_batch_four_inserts_elements_multi_level_added_bytes_match_non_batch() { + let grove_version = GroveVersion::latest(); let db = make_empty_grovedb(); let tx = db.start_transaction(); let non_batch_cost_1 = db - .insert(EMPTY_PATH, b"key1", Element::empty_tree(), None, Some(&tx)) + .insert( + EMPTY_PATH, + b"key1", + Element::empty_tree(), + None, + Some(&tx), + grove_version, + ) .cost; let non_batch_cost_2 = db .insert( @@ -135,6 +141,7 @@ mod tests { Element::new_item_with_flags(b"pizza".to_vec(), Some([0, 1].to_vec())), None, Some(&tx), + grove_version, ) .cost; let non_batch_cost_3 = db @@ -144,6 +151,7 @@ mod tests { Element::empty_tree(), None, Some(&tx), + grove_version, ) .cost; let non_batch_cost_4 = db @@ -156,6 +164,7 @@ mod tests { )), None, Some(&tx), + grove_version, ) .cost; let non_batch_cost = non_batch_cost_1 @@ -185,7 +194,7 @@ mod tests { ), ]; let cost = db - .apply_batch(ops, None, Some(&tx)) + .apply_batch(ops, None, Some(&tx), grove_version) .cost_as_result() .expect("expected to apply batch"); assert_eq!( @@ -198,6 +207,7 @@ mod tests { #[test] fn test_batch_root_two_insert_tree_cost_same_level() { + let grove_version = GroveVersion::latest(); let db = make_empty_grovedb(); let tx = db.start_transaction(); @@ -205,7 +215,7 @@ mod tests { GroveDbOp::insert_op(vec![], b"key1".to_vec(), Element::empty_tree()), GroveDbOp::insert_op(vec![], b"key2".to_vec(), Element::empty_tree()), ]; - let cost_result = db.apply_batch(ops, None, Some(&tx)); + let cost_result = db.apply_batch(ops, None, Some(&tx), grove_version); cost_result.value.expect("expected to execute batch"); let cost = cost_result.cost; // Explanation for 214 storage_written_bytes @@ -253,6 +263,7 @@ mod tests { #[test] fn test_batch_root_two_insert_tree_cost_different_level() { + let grove_version = GroveVersion::latest(); let db = make_empty_grovedb(); let tx = db.start_transaction(); @@ -264,7 +275,7 @@ mod tests { Element::empty_tree(), ), ]; - let cost_result = db.apply_batch(ops, None, Some(&tx)); + let cost_result = db.apply_batch(ops, None, Some(&tx), grove_version); cost_result.value.expect("expected to execute batch"); let cost = cost_result.cost; // Explanation for 214 storage_written_bytes diff --git a/grovedb/src/batch/options.rs b/grovedb/src/batch/options.rs index b3916eb8..1f60aeb4 100644 --- a/grovedb/src/batch/options.rs +++ b/grovedb/src/batch/options.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. - //! Options #[cfg(feature = "full")] @@ -42,7 +14,7 @@ pub struct BatchApplyOptions { pub validate_insertion_does_not_override: bool, /// Validate insertion does not override tree pub validate_insertion_does_not_override_tree: bool, - /// Allow deleting non empty trees + /// Allow deleting non-empty trees pub allow_deleting_non_empty_trees: bool, /// Deleting non empty trees returns error pub deleting_non_empty_trees_returns_error: bool, diff --git a/grovedb/src/batch/single_deletion_cost_tests.rs b/grovedb/src/batch/single_deletion_cost_tests.rs index 593ac04f..fac9682f 100644 --- a/grovedb/src/batch/single_deletion_cost_tests.rs +++ b/grovedb/src/batch/single_deletion_cost_tests.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. - //! Tests #[cfg(feature = "full")] @@ -35,6 +7,7 @@ mod tests { Identifier, StorageRemovalPerEpochByIdentifier, StorageRemovedBytes::SectionedStorageRemoval, }; + use grovedb_version::version::GroveVersion; use intmap::IntMap; use crate::{ @@ -45,17 +18,25 @@ mod tests { #[test] fn test_batch_one_deletion_tree_costs_match_non_batch_on_transaction() { + let grove_version = GroveVersion::latest(); let db = make_empty_grovedb(); let insertion_cost = db - .insert(EMPTY_PATH, b"key1", Element::empty_tree(), None, None) + .insert( + EMPTY_PATH, + b"key1", + Element::empty_tree(), + None, + None, + grove_version, + ) .cost_as_result() .expect("expected to insert successfully"); let tx = db.start_transaction(); let non_batch_cost = db - .delete(EMPTY_PATH, b"key1", None, Some(&tx)) + .delete(EMPTY_PATH, b"key1", None, Some(&tx), grove_version) .cost_as_result() .expect("expected to delete successfully"); @@ -93,7 +74,7 @@ mod tests { tx.rollback().expect("expected to rollback"); let ops = vec![GroveDbOp::delete_tree_op(vec![], b"key1".to_vec(), false)]; let batch_cost = db - .apply_batch(ops, None, Some(&tx)) + .apply_batch(ops, None, Some(&tx), grove_version) .cost_as_result() .expect("expected to delete successfully"); assert_eq!(non_batch_cost.storage_cost, batch_cost.storage_cost); @@ -101,6 +82,7 @@ mod tests { #[test] fn test_batch_one_deletion_item_costs_match_non_batch_on_transaction() { + let grove_version = GroveVersion::latest(); let db = make_empty_grovedb(); let insertion_cost = db @@ -110,6 +92,7 @@ mod tests { Element::new_item(b"cat".to_vec()), None, None, + grove_version, ) .cost_as_result() .expect("expected to insert successfully"); @@ -117,7 +100,7 @@ mod tests { let tx = db.start_transaction(); let non_batch_cost = db - .delete(EMPTY_PATH, b"key1", None, Some(&tx)) + .delete(EMPTY_PATH, b"key1", None, Some(&tx), grove_version) .cost_as_result() .expect("expected to delete successfully"); @@ -156,7 +139,7 @@ mod tests { tx.rollback().expect("expected to rollback"); let ops = vec![GroveDbOp::delete_op(vec![], b"key1".to_vec())]; let batch_cost = db - .apply_batch(ops, None, Some(&tx)) + .apply_batch(ops, None, Some(&tx), grove_version) .cost_as_result() .expect("expected to delete successfully"); assert_eq!(non_batch_cost.storage_cost, batch_cost.storage_cost); @@ -164,15 +147,23 @@ mod tests { #[test] fn test_batch_one_deletion_tree_costs_match_non_batch_without_transaction() { + let grove_version = GroveVersion::latest(); let db = make_empty_grovedb(); let insertion_cost = db - .insert(EMPTY_PATH, b"key1", Element::empty_tree(), None, None) + .insert( + EMPTY_PATH, + b"key1", + Element::empty_tree(), + None, + None, + grove_version, + ) .cost_as_result() .expect("expected to insert successfully"); let non_batch_cost = db - .delete(EMPTY_PATH, b"key1", None, None) + .delete(EMPTY_PATH, b"key1", None, None, grove_version) .cost_as_result() .expect("expected to delete successfully"); @@ -210,13 +201,20 @@ mod tests { let db = make_empty_grovedb(); let _insertion_cost = db - .insert(EMPTY_PATH, b"key1", Element::empty_tree(), None, None) + .insert( + EMPTY_PATH, + b"key1", + Element::empty_tree(), + None, + None, + grove_version, + ) .cost_as_result() .expect("expected to insert successfully"); let ops = vec![GroveDbOp::delete_tree_op(vec![], b"key1".to_vec(), false)]; let batch_cost = db - .apply_batch(ops, None, None) + .apply_batch(ops, None, None, grove_version) .cost_as_result() .expect("expected to delete successfully"); assert_eq!(non_batch_cost.storage_cost, batch_cost.storage_cost); @@ -224,6 +222,7 @@ mod tests { #[test] fn test_batch_one_deletion_item_costs_match_non_batch_without_transaction() { + let grove_version = GroveVersion::latest(); let db = make_empty_grovedb(); let insertion_cost = db @@ -233,12 +232,13 @@ mod tests { Element::new_item(b"cat".to_vec()), None, None, + grove_version, ) .cost_as_result() .expect("expected to insert successfully"); let non_batch_cost = db - .delete(EMPTY_PATH, b"key1", None, None) + .delete(EMPTY_PATH, b"key1", None, None, grove_version) .cost_as_result() .expect("expected to delete successfully"); @@ -283,13 +283,14 @@ mod tests { Element::new_item(b"cat".to_vec()), None, None, + grove_version, ) .cost_as_result() .expect("expected to insert successfully"); let ops = vec![GroveDbOp::delete_op(vec![], b"key1".to_vec())]; let batch_cost = db - .apply_batch(ops, None, None) + .apply_batch(ops, None, None, grove_version) .cost_as_result() .expect("expected to delete successfully"); assert_eq!(non_batch_cost.storage_cost, batch_cost.storage_cost); @@ -297,6 +298,7 @@ mod tests { #[test] fn test_batch_one_deletion_tree_with_flags_costs_match_non_batch_on_transaction() { + let grove_version = GroveVersion::latest(); let db = make_empty_grovedb(); let insertion_cost = db @@ -306,6 +308,7 @@ mod tests { Element::empty_tree_with_flags(Some(b"dog".to_vec())), None, None, + grove_version, ) .cost_as_result() .expect("expected to insert successfully"); @@ -313,7 +316,7 @@ mod tests { let tx = db.start_transaction(); let non_batch_cost = db - .delete(EMPTY_PATH, b"key1", None, Some(&tx)) + .delete(EMPTY_PATH, b"key1", None, Some(&tx), grove_version) .cost_as_result() .expect("expected to delete successfully"); @@ -356,7 +359,7 @@ mod tests { tx.rollback().expect("expected to rollback"); let ops = vec![GroveDbOp::delete_tree_op(vec![], b"key1".to_vec(), false)]; let batch_cost = db - .apply_batch(ops, None, Some(&tx)) + .apply_batch(ops, None, Some(&tx), grove_version) .cost_as_result() .expect("expected to delete successfully"); assert_eq!(non_batch_cost.storage_cost, batch_cost.storage_cost); @@ -365,6 +368,7 @@ mod tests { #[test] fn test_batch_one_deletion_tree_with_identity_cost_flags_costs_match_non_batch_on_transaction() { + let grove_version = GroveVersion::latest(); let db = make_empty_grovedb(); let insertion_cost = db @@ -374,6 +378,7 @@ mod tests { Element::empty_tree_with_flags(Some(vec![0, 0])), None, None, + grove_version, ) .cost_as_result() .expect("expected to insert successfully"); @@ -402,6 +407,7 @@ mod tests { let value_sectioned = SectionedStorageRemoval(removed_bytes); Ok((key_sectioned, value_sectioned)) }, + grove_version, ) .cost_as_result() .expect("expected to delete successfully"); @@ -469,6 +475,7 @@ mod tests { Ok((key_sectioned, value_sectioned)) }, Some(&tx), + grove_version, ) .cost_as_result() .expect("expected to delete successfully"); @@ -481,6 +488,7 @@ mod tests { #[test] fn test_batch_one_deletion_item_with_flags_costs_match_non_batch_on_transaction() { + let grove_version = GroveVersion::latest(); let db = make_empty_grovedb(); let insertion_cost = db @@ -490,6 +498,7 @@ mod tests { Element::new_item_with_flags(b"cat".to_vec(), Some(b"apple".to_vec())), None, None, + grove_version, ) .cost_as_result() .expect("expected to insert successfully"); @@ -497,7 +506,7 @@ mod tests { let tx = db.start_transaction(); let non_batch_cost = db - .delete(EMPTY_PATH, b"key1", None, Some(&tx)) + .delete(EMPTY_PATH, b"key1", None, Some(&tx), grove_version) .cost_as_result() .expect("expected to delete successfully"); @@ -536,7 +545,7 @@ mod tests { tx.rollback().expect("expected to rollback"); let ops = vec![GroveDbOp::delete_op(vec![], b"key1".to_vec())]; let batch_cost = db - .apply_batch(ops, None, Some(&tx)) + .apply_batch(ops, None, Some(&tx), grove_version) .cost_as_result() .expect("expected to delete successfully"); assert_eq!(non_batch_cost.storage_cost, batch_cost.storage_cost); @@ -544,6 +553,7 @@ mod tests { #[test] fn test_batch_one_deletion_tree_with_flags_costs_match_non_batch_without_transaction() { + let grove_version = GroveVersion::latest(); let db = make_empty_grovedb(); let insertion_cost = db @@ -553,12 +563,13 @@ mod tests { Element::empty_tree_with_flags(Some(b"dog".to_vec())), None, None, + grove_version, ) .cost_as_result() .expect("expected to insert successfully"); let non_batch_cost = db - .delete(EMPTY_PATH, b"key1", None, None) + .delete(EMPTY_PATH, b"key1", None, None, grove_version) .cost_as_result() .expect("expected to delete successfully"); @@ -607,13 +618,14 @@ mod tests { Element::empty_tree_with_flags(Some(b"dog".to_vec())), None, None, + grove_version, ) .cost_as_result() .expect("expected to insert successfully"); let ops = vec![GroveDbOp::delete_tree_op(vec![], b"key1".to_vec(), false)]; let batch_cost = db - .apply_batch(ops, None, None) + .apply_batch(ops, None, None, grove_version) .cost_as_result() .expect("expected to delete successfully"); assert_eq!(non_batch_cost.storage_cost, batch_cost.storage_cost); @@ -621,6 +633,7 @@ mod tests { #[test] fn test_batch_one_deletion_item_with_flags_costs_match_non_batch_without_transaction() { + let grove_version = GroveVersion::latest(); let db = make_empty_grovedb(); let insertion_cost = db @@ -630,12 +643,13 @@ mod tests { Element::new_item_with_flags(b"cat".to_vec(), Some(b"apple".to_vec())), None, None, + grove_version, ) .cost_as_result() .expect("expected to insert successfully"); let non_batch_cost = db - .delete(EMPTY_PATH, b"key1", None, None) + .delete(EMPTY_PATH, b"key1", None, None, grove_version) .cost_as_result() .expect("expected to delete successfully"); @@ -680,13 +694,14 @@ mod tests { Element::new_item_with_flags(b"cat".to_vec(), Some(b"apple".to_vec())), None, None, + grove_version, ) .cost_as_result() .expect("expected to insert successfully"); let ops = vec![GroveDbOp::delete_op(vec![], b"key1".to_vec())]; let batch_cost = db - .apply_batch(ops, None, None) + .apply_batch(ops, None, None, grove_version) .cost_as_result() .expect("expected to delete successfully"); assert_eq!(non_batch_cost.storage_cost, batch_cost.storage_cost); diff --git a/grovedb/src/batch/single_insert_cost_tests.rs b/grovedb/src/batch/single_insert_cost_tests.rs index 1dd2d43c..c025fb27 100644 --- a/grovedb/src/batch/single_insert_cost_tests.rs +++ b/grovedb/src/batch/single_insert_cost_tests.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. - //! Tests #[cfg(feature = "full")] @@ -43,6 +15,7 @@ mod tests { }, OperationCost, }; + use grovedb_version::version::GroveVersion; use integer_encoding::VarInt; use intmap::IntMap; @@ -54,11 +27,19 @@ mod tests { #[test] fn test_batch_one_insert_costs_match_non_batch() { + let grove_version = GroveVersion::latest(); let db = make_empty_grovedb(); let tx = db.start_transaction(); let non_batch_cost = db - .insert(EMPTY_PATH, b"key1", Element::empty_tree(), None, Some(&tx)) + .insert( + EMPTY_PATH, + b"key1", + Element::empty_tree(), + None, + Some(&tx), + grove_version, + ) .cost; tx.rollback().expect("expected to rollback"); let ops = vec![GroveDbOp::insert_op( @@ -66,12 +47,13 @@ mod tests { b"key1".to_vec(), Element::empty_tree(), )]; - let cost = db.apply_batch(ops, None, Some(&tx)).cost; + let cost = db.apply_batch(ops, None, Some(&tx), grove_version).cost; assert_eq!(non_batch_cost.storage_cost, cost.storage_cost); } #[test] fn test_batch_root_one_insert_tree_cost() { + let grove_version = GroveVersion::latest(); let db = make_empty_grovedb(); let tx = db.start_transaction(); @@ -80,7 +62,7 @@ mod tests { b"key1".to_vec(), Element::empty_tree(), )]; - let cost_result = db.apply_batch(ops, None, Some(&tx)); + let cost_result = db.apply_batch(ops, None, Some(&tx), grove_version); cost_result.value.expect("expected to execute batch"); let cost = cost_result.cost; // Explanation for 113 storage_written_bytes @@ -136,6 +118,7 @@ mod tests { #[test] fn test_batch_root_one_insert_item_cost() { + let grove_version = GroveVersion::latest(); let db = make_empty_grovedb(); let tx = db.start_transaction(); @@ -144,7 +127,7 @@ mod tests { b"key1".to_vec(), Element::new_item(b"cat".to_vec()), )]; - let cost_result = db.apply_batch(ops, None, Some(&tx)); + let cost_result = db.apply_batch(ops, None, Some(&tx), grove_version); cost_result.value.expect("expected to execute batch"); let cost = cost_result.cost; // Explanation for 214 storage_written_bytes @@ -199,6 +182,7 @@ mod tests { #[test] fn test_batch_root_one_insert_tree_under_parent_item_in_same_merk_cost() { + let grove_version = GroveVersion::latest(); let db = make_empty_grovedb(); let tx = db.start_transaction(); @@ -209,6 +193,7 @@ mod tests { Element::new_item(b"cat".to_vec()), None, Some(&tx), + grove_version, ) .cost_as_result() .expect("successful root tree leaf insert"); @@ -220,7 +205,7 @@ mod tests { b"key1".to_vec(), Element::empty_tree(), )]; - let cost_result = db.apply_batch(ops, None, Some(&tx)); + let cost_result = db.apply_batch(ops, None, Some(&tx), grove_version); cost_result.value.expect("expected to execute batch"); let cost = cost_result.cost; // Explanation for 115 storage_written_bytes @@ -293,19 +278,27 @@ mod tests { #[test] fn test_batch_root_one_insert_tree_under_parent_tree_in_same_merk_cost() { + let grove_version = GroveVersion::latest(); let db = make_empty_grovedb(); let tx = db.start_transaction(); - db.insert(EMPTY_PATH, b"0", Element::empty_tree(), None, Some(&tx)) - .unwrap() - .expect("successful root tree leaf insert"); + db.insert( + EMPTY_PATH, + b"0", + Element::empty_tree(), + None, + Some(&tx), + grove_version, + ) + .unwrap() + .expect("successful root tree leaf insert"); let ops = vec![GroveDbOp::insert_op( vec![], b"key1".to_vec(), Element::empty_tree(), )]; - let cost_result = db.apply_batch(ops, None, Some(&tx)); + let cost_result = db.apply_batch(ops, None, Some(&tx), grove_version); cost_result.value.expect("expected to execute batch"); let cost = cost_result.cost; // Explanation for 113 storage_written_bytes @@ -367,19 +360,27 @@ mod tests { #[test] fn test_batch_root_one_insert_tree_under_parent_tree_in_different_merk_cost() { + let grove_version = GroveVersion::latest(); let db = make_empty_grovedb(); let tx = db.start_transaction(); - db.insert(EMPTY_PATH, b"0", Element::empty_tree(), None, Some(&tx)) - .unwrap() - .expect("successful root tree leaf insert"); + db.insert( + EMPTY_PATH, + b"0", + Element::empty_tree(), + None, + Some(&tx), + grove_version, + ) + .unwrap() + .expect("successful root tree leaf insert"); let ops = vec![GroveDbOp::insert_op( vec![b"0".to_vec()], b"key1".to_vec(), Element::empty_tree(), )]; - let cost_result = db.apply_batch(ops, None, Some(&tx)); + let cost_result = db.apply_batch(ops, None, Some(&tx), grove_version); cost_result.value.expect("expected to execute batch"); let cost = cost_result.cost; // Explanation for 113 storage_written_bytes @@ -448,6 +449,7 @@ mod tests { #[test] fn test_batch_root_one_insert_cost_right_below_value_required_cost_of_2() { + let grove_version = GroveVersion::latest(); let db = make_empty_grovedb(); let tx = db.start_transaction(); @@ -456,7 +458,7 @@ mod tests { b"key1".to_vec(), Element::new_item([0u8; 59].to_vec()), )]; - let cost_result = db.apply_batch(ops, None, Some(&tx)); + let cost_result = db.apply_batch(ops, None, Some(&tx), grove_version); cost_result.value.expect("expected to execute batch"); let cost = cost_result.cost; // Explanation for 243 storage_written_bytes @@ -510,6 +512,7 @@ mod tests { #[test] fn test_batch_root_one_insert_cost_right_above_value_required_cost_of_2() { + let grove_version = GroveVersion::latest(); let db = make_empty_grovedb(); let tx = db.start_transaction(); @@ -518,7 +521,7 @@ mod tests { b"key1".to_vec(), Element::new_item([0u8; 60].to_vec()), )]; - let cost_result = db.apply_batch(ops, None, Some(&tx)); + let cost_result = db.apply_batch(ops, None, Some(&tx), grove_version); cost_result.value.expect("expected to execute batch"); let cost = cost_result.cost; // Explanation for 243 storage_written_bytes @@ -572,11 +575,19 @@ mod tests { #[test] fn test_batch_root_one_update_item_bigger_cost_no_flags() { + let grove_version = GroveVersion::latest(); let db = make_empty_grovedb(); let tx = db.start_transaction(); - db.insert(EMPTY_PATH, b"tree", Element::empty_tree(), None, None) - .unwrap() - .expect("expected to insert tree"); + db.insert( + EMPTY_PATH, + b"tree", + Element::empty_tree(), + None, + None, + grove_version, + ) + .unwrap() + .expect("expected to insert tree"); db.insert( [b"tree".as_slice()].as_ref(), @@ -584,6 +595,7 @@ mod tests { Element::new_item_with_flags(b"value1".to_vec(), Some(vec![0])), None, None, + grove_version, ) .unwrap() .expect("expected to insert item"); @@ -604,6 +616,7 @@ mod tests { Ok((NoStorageRemoval, NoStorageRemoval)) }, Some(&tx), + grove_version, ) .cost; @@ -628,11 +641,19 @@ mod tests { #[test] fn test_batch_root_one_update_item_bigger_cost() { + let grove_version = GroveVersion::latest(); let db = make_empty_grovedb(); let tx = db.start_transaction(); - db.insert(EMPTY_PATH, b"tree", Element::empty_tree(), None, None) - .unwrap() - .expect("expected to insert tree"); + db.insert( + EMPTY_PATH, + b"tree", + Element::empty_tree(), + None, + None, + grove_version, + ) + .unwrap() + .expect("expected to insert tree"); db.insert( [b"tree".as_slice()].as_ref(), @@ -640,6 +661,7 @@ mod tests { Element::new_item_with_flags(b"value1".to_vec(), Some(vec![0, 0])), None, None, + grove_version, ) .unwrap() .expect("expected to insert item"); @@ -683,6 +705,7 @@ mod tests { )) }, Some(&tx), + grove_version, ) .cost; @@ -707,11 +730,19 @@ mod tests { #[test] fn test_batch_root_one_update_item_smaller_cost_no_flags() { + let grove_version = GroveVersion::latest(); let db = make_empty_grovedb(); let tx = db.start_transaction(); - db.insert(EMPTY_PATH, b"tree", Element::empty_tree(), None, None) - .unwrap() - .expect("expected to insert tree"); + db.insert( + EMPTY_PATH, + b"tree", + Element::empty_tree(), + None, + None, + grove_version, + ) + .unwrap() + .expect("expected to insert tree"); db.insert( [b"tree".as_slice()].as_ref(), @@ -719,6 +750,7 @@ mod tests { Element::new_item_with_flags(b"value1".to_vec(), Some(vec![0])), None, None, + grove_version, ) .unwrap() .expect("expected to insert item"); @@ -742,6 +774,7 @@ mod tests { )) }, Some(&tx), + grove_version, ) .cost; @@ -762,11 +795,19 @@ mod tests { #[test] fn test_batch_root_one_update_item_smaller_cost() { + let grove_version = GroveVersion::latest(); let db = make_empty_grovedb(); let tx = db.start_transaction(); - db.insert(EMPTY_PATH, b"tree", Element::empty_tree(), None, None) - .unwrap() - .expect("expected to insert tree"); + db.insert( + EMPTY_PATH, + b"tree", + Element::empty_tree(), + None, + None, + grove_version, + ) + .unwrap() + .expect("expected to insert tree"); db.insert( [b"tree".as_slice()].as_ref(), @@ -774,6 +815,7 @@ mod tests { Element::new_item_with_flags(b"value1".to_vec(), Some(vec![0, 0])), None, None, + grove_version, ) .unwrap() .expect("expected to insert item"); @@ -816,6 +858,7 @@ mod tests { Ok((NoStorageRemoval, SectionedStorageRemoval(removed_bytes))) }, Some(&tx), + grove_version, ) .cost; @@ -842,11 +885,19 @@ mod tests { #[test] fn test_batch_root_one_update_tree_bigger_flags_cost() { + let grove_version = GroveVersion::latest(); let db = make_empty_grovedb(); let tx = db.start_transaction(); - db.insert(EMPTY_PATH, b"tree", Element::empty_tree(), None, None) - .unwrap() - .expect("expected to insert tree"); + db.insert( + EMPTY_PATH, + b"tree", + Element::empty_tree(), + None, + None, + grove_version, + ) + .unwrap() + .expect("expected to insert tree"); db.insert( [b"tree".as_slice()].as_ref(), @@ -854,6 +905,7 @@ mod tests { Element::new_tree_with_flags(None, Some(vec![0, 0])), None, None, + grove_version, ) .unwrap() .expect("expected to insert item"); @@ -895,6 +947,7 @@ mod tests { Ok((NoStorageRemoval, BasicStorageRemoval(removed_value_bytes))) }, Some(&tx), + grove_version, ) .cost; diff --git a/grovedb/src/batch/single_sum_item_deletion_cost_tests.rs b/grovedb/src/batch/single_sum_item_deletion_cost_tests.rs index b049bf50..bf5637d0 100644 --- a/grovedb/src/batch/single_sum_item_deletion_cost_tests.rs +++ b/grovedb/src/batch/single_sum_item_deletion_cost_tests.rs @@ -1,35 +1,8 @@ -// 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. - //! Tests #[cfg(feature = "full")] mod tests { + use grovedb_version::version::GroveVersion; use crate::{ batch::GroveDbOp, @@ -39,17 +12,25 @@ mod tests { #[test] fn test_batch_one_deletion_sum_tree_costs_match_non_batch_on_transaction() { + let grove_version = GroveVersion::latest(); let db = make_empty_grovedb(); let insertion_cost = db - .insert(EMPTY_PATH, b"key1", Element::empty_sum_tree(), None, None) + .insert( + EMPTY_PATH, + b"key1", + Element::empty_sum_tree(), + None, + None, + grove_version, + ) .cost_as_result() .expect("expected to insert successfully"); let tx = db.start_transaction(); let non_batch_cost = db - .delete(EMPTY_PATH, b"key1", None, Some(&tx)) + .delete(EMPTY_PATH, b"key1", None, Some(&tx), grove_version) .cost_as_result() .expect("expected to delete successfully"); @@ -64,7 +45,7 @@ mod tests { tx.rollback().expect("expected to rollback"); let ops = vec![GroveDbOp::delete_tree_op(vec![], b"key1".to_vec(), false)]; let batch_cost = db - .apply_batch(ops, None, Some(&tx)) + .apply_batch(ops, None, Some(&tx), grove_version) .cost_as_result() .expect("expected to delete successfully"); assert_eq!(non_batch_cost.storage_cost, batch_cost.storage_cost); @@ -72,6 +53,7 @@ mod tests { #[test] fn test_batch_one_deletion_sum_item_costs_match_non_batch_on_transaction() { + let grove_version = GroveVersion::latest(); let db = make_empty_grovedb(); db.insert( @@ -80,6 +62,7 @@ mod tests { Element::empty_sum_tree(), None, None, + grove_version, ) .unwrap() .expect("expected to insert sum tree"); @@ -91,6 +74,7 @@ mod tests { Element::new_sum_item(15), None, None, + grove_version, ) .cost_as_result() .expect("expected to insert successfully"); @@ -98,7 +82,13 @@ mod tests { let tx = db.start_transaction(); let non_batch_cost = db - .delete([b"sum_tree".as_slice()].as_ref(), b"key1", None, Some(&tx)) + .delete( + [b"sum_tree".as_slice()].as_ref(), + b"key1", + None, + Some(&tx), + grove_version, + ) .cost_as_result() .expect("expected to delete successfully"); @@ -116,7 +106,7 @@ mod tests { b"key1".to_vec(), )]; let batch_cost = db - .apply_batch(ops, None, Some(&tx)) + .apply_batch(ops, None, Some(&tx), grove_version) .cost_as_result() .expect("expected to delete successfully"); assert_eq!(non_batch_cost.storage_cost, batch_cost.storage_cost); @@ -124,6 +114,7 @@ mod tests { #[test] fn test_batch_one_deletion_sum_tree_with_flags_costs_match_non_batch_on_transaction() { + let grove_version = GroveVersion::latest(); let db = make_empty_grovedb(); let insertion_cost = db @@ -133,6 +124,7 @@ mod tests { Element::empty_sum_tree_with_flags(Some(b"dog".to_vec())), None, None, + grove_version, ) .cost_as_result() .expect("expected to insert successfully"); @@ -140,7 +132,7 @@ mod tests { let tx = db.start_transaction(); let non_batch_cost = db - .delete(EMPTY_PATH, b"key1", None, Some(&tx)) + .delete(EMPTY_PATH, b"key1", None, Some(&tx), grove_version) .cost_as_result() .expect("expected to delete successfully"); @@ -156,7 +148,7 @@ mod tests { tx.rollback().expect("expected to rollback"); let ops = vec![GroveDbOp::delete_tree_op(vec![], b"key1".to_vec(), false)]; let batch_cost = db - .apply_batch(ops, None, Some(&tx)) + .apply_batch(ops, None, Some(&tx), grove_version) .cost_as_result() .expect("expected to delete successfully"); assert_eq!(non_batch_cost.storage_cost, batch_cost.storage_cost); diff --git a/grovedb/src/batch/single_sum_item_insert_cost_tests.rs b/grovedb/src/batch/single_sum_item_insert_cost_tests.rs index d1e13fea..0ba3da44 100644 --- a/grovedb/src/batch/single_sum_item_insert_cost_tests.rs +++ b/grovedb/src/batch/single_sum_item_insert_cost_tests.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. - //! Tests #[cfg(feature = "full")] @@ -34,6 +6,7 @@ mod tests { storage_cost::{removal::StorageRemovedBytes::NoStorageRemoval, StorageCost}, OperationCost, }; + use grovedb_version::version::GroveVersion; use crate::{ batch::GroveDbOp, @@ -43,6 +16,7 @@ mod tests { #[test] fn test_batch_one_sum_item_insert_costs_match_non_batch() { + let grove_version = GroveVersion::latest(); let db = make_empty_grovedb(); let tx = db.start_transaction(); @@ -52,6 +26,7 @@ mod tests { Element::empty_sum_tree(), None, None, + grove_version, ) .unwrap() .expect("expected to insert sum tree"); @@ -63,6 +38,7 @@ mod tests { Element::new_sum_item(150), None, Some(&tx), + grove_version, ) .cost; tx.rollback().expect("expected to rollback"); @@ -71,12 +47,13 @@ mod tests { b"key1".to_vec(), Element::new_sum_item(150), )]; - let cost = db.apply_batch(ops, None, Some(&tx)).cost; + let cost = db.apply_batch(ops, None, Some(&tx), grove_version).cost; assert_eq!(non_batch_cost.storage_cost, cost.storage_cost); } #[test] fn test_batch_one_insert_sum_tree_cost() { + let grove_version = GroveVersion::latest(); let db = make_empty_grovedb(); let tx = db.start_transaction(); @@ -85,7 +62,7 @@ mod tests { b"key1".to_vec(), Element::empty_sum_tree(), )]; - let cost_result = db.apply_batch(ops, None, Some(&tx)); + let cost_result = db.apply_batch(ops, None, Some(&tx), grove_version); cost_result.value.expect("expected to execute batch"); let cost = cost_result.cost; // Explanation for 124 storage_written_bytes @@ -142,19 +119,27 @@ mod tests { #[test] fn test_batch_one_insert_sum_tree_under_parent_tree_in_same_merk_cost() { + let grove_version = GroveVersion::latest(); let db = make_empty_grovedb(); let tx = db.start_transaction(); - db.insert(EMPTY_PATH, b"0", Element::empty_tree(), None, Some(&tx)) - .unwrap() - .expect("successful root tree leaf insert"); + db.insert( + EMPTY_PATH, + b"0", + Element::empty_tree(), + None, + Some(&tx), + grove_version, + ) + .unwrap() + .expect("successful root tree leaf insert"); let ops = vec![GroveDbOp::insert_op( vec![], b"key1".to_vec(), Element::empty_sum_tree(), )]; - let cost_result = db.apply_batch(ops, None, Some(&tx)); + let cost_result = db.apply_batch(ops, None, Some(&tx), grove_version); cost_result.value.expect("expected to execute batch"); let cost = cost_result.cost; // Explanation for 124 storage_written_bytes @@ -220,19 +205,27 @@ mod tests { #[test] fn test_batch_one_insert_sum_tree_under_parent_sum_tree_in_same_merk_cost() { + let grove_version = GroveVersion::latest(); let db = make_empty_grovedb(); let tx = db.start_transaction(); - db.insert(EMPTY_PATH, b"0", Element::empty_sum_tree(), None, Some(&tx)) - .unwrap() - .expect("successful root tree leaf insert"); + db.insert( + EMPTY_PATH, + b"0", + Element::empty_sum_tree(), + None, + Some(&tx), + grove_version, + ) + .unwrap() + .expect("successful root tree leaf insert"); let ops = vec![GroveDbOp::insert_op( vec![], b"key1".to_vec(), Element::empty_sum_tree(), )]; - let cost_result = db.apply_batch(ops, None, Some(&tx)); + let cost_result = db.apply_batch(ops, None, Some(&tx), grove_version); cost_result.value.expect("expected to execute batch"); let cost = cost_result.cost; // Explanation for 124 storage_written_bytes @@ -298,19 +291,27 @@ mod tests { #[test] fn test_batch_one_insert_sum_tree_under_parent_tree_in_different_merk_cost() { + let grove_version = GroveVersion::latest(); let db = make_empty_grovedb(); let tx = db.start_transaction(); - db.insert(EMPTY_PATH, b"0", Element::empty_tree(), None, Some(&tx)) - .unwrap() - .expect("successful root tree leaf insert"); + db.insert( + EMPTY_PATH, + b"0", + Element::empty_tree(), + None, + Some(&tx), + grove_version, + ) + .unwrap() + .expect("successful root tree leaf insert"); let ops = vec![GroveDbOp::insert_op( vec![b"0".to_vec()], b"key1".to_vec(), Element::empty_sum_tree(), )]; - let cost_result = db.apply_batch(ops, None, Some(&tx)); + let cost_result = db.apply_batch(ops, None, Some(&tx), grove_version); cost_result.value.expect("expected to execute batch"); let cost = cost_result.cost; // Explanation for 124 storage_written_bytes @@ -380,19 +381,27 @@ mod tests { #[test] fn test_batch_one_insert_sum_tree_under_parent_sum_tree_in_different_merk_cost() { + let grove_version = GroveVersion::latest(); let db = make_empty_grovedb(); let tx = db.start_transaction(); - db.insert(EMPTY_PATH, b"0", Element::empty_sum_tree(), None, Some(&tx)) - .unwrap() - .expect("successful root tree leaf insert"); + db.insert( + EMPTY_PATH, + b"0", + Element::empty_sum_tree(), + None, + Some(&tx), + grove_version, + ) + .unwrap() + .expect("successful root tree leaf insert"); let ops = vec![GroveDbOp::insert_op( vec![b"0".to_vec()], b"key1".to_vec(), Element::empty_sum_tree(), )]; - let cost_result = db.apply_batch(ops, None, Some(&tx)); + let cost_result = db.apply_batch(ops, None, Some(&tx), grove_version); cost_result.value.expect("expected to execute batch"); let cost = cost_result.cost; // Explanation for 124 storage_written_bytes @@ -463,6 +472,7 @@ mod tests { #[test] fn test_batch_one_insert_sum_item_cost_right_below_value_required_cost_of_2() { + let grove_version = GroveVersion::latest(); let db = make_empty_grovedb(); let tx = db.start_transaction(); @@ -472,6 +482,7 @@ mod tests { Element::empty_sum_tree(), None, None, + grove_version, ) .unwrap() .expect("expected to insert sum tree"); @@ -481,7 +492,7 @@ mod tests { b"key1".to_vec(), Element::new_sum_item_with_flags(15, Some([0; 42].to_vec())), )]; - let cost_result = db.apply_batch(ops, None, Some(&tx)); + let cost_result = db.apply_batch(ops, None, Some(&tx), grove_version); cost_result.value.expect("expected to execute batch"); let cost = cost_result.cost; // Explanation for 243 storage_written_bytes @@ -536,6 +547,7 @@ mod tests { #[test] fn test_batch_one_insert_sum_item_cost_right_above_value_required_cost_of_2() { + let grove_version = GroveVersion::latest(); let db = make_empty_grovedb(); let tx = db.start_transaction(); @@ -545,6 +557,7 @@ mod tests { Element::empty_sum_tree(), None, None, + grove_version, ) .unwrap() .expect("expected to insert sum tree"); @@ -554,7 +567,7 @@ mod tests { b"key1".to_vec(), Element::new_sum_item_with_flags(15, Some([0; 43].to_vec())), )]; - let cost_result = db.apply_batch(ops, None, Some(&tx)); + let cost_result = db.apply_batch(ops, None, Some(&tx), grove_version); cost_result.value.expect("expected to execute batch"); let cost = cost_result.cost; // Explanation for 243 storage_written_bytes @@ -609,11 +622,19 @@ mod tests { #[test] fn test_batch_one_update_sum_item_bigger_no_flags() { + let grove_version = GroveVersion::latest(); let db = make_empty_grovedb(); let tx = db.start_transaction(); - db.insert(EMPTY_PATH, b"tree", Element::empty_sum_tree(), None, None) - .unwrap() - .expect("expected to insert tree"); + db.insert( + EMPTY_PATH, + b"tree", + Element::empty_sum_tree(), + None, + None, + grove_version, + ) + .unwrap() + .expect("expected to insert tree"); db.insert( [b"tree".as_slice()].as_ref(), @@ -621,6 +642,7 @@ mod tests { Element::new_sum_item_with_flags(100, None), None, None, + grove_version, ) .unwrap() .expect("expected to insert item"); @@ -641,6 +663,7 @@ mod tests { Ok((NoStorageRemoval, NoStorageRemoval)) }, Some(&tx), + grove_version, ) .cost; @@ -665,11 +688,19 @@ mod tests { #[test] fn test_batch_one_update_sum_item_bigger_with_flags() { + let grove_version = GroveVersion::latest(); let db = make_empty_grovedb(); let tx = db.start_transaction(); - db.insert(EMPTY_PATH, b"tree", Element::empty_sum_tree(), None, None) - .unwrap() - .expect("expected to insert tree"); + db.insert( + EMPTY_PATH, + b"tree", + Element::empty_sum_tree(), + None, + None, + grove_version, + ) + .unwrap() + .expect("expected to insert tree"); db.insert( [b"tree".as_slice()].as_ref(), @@ -677,6 +708,7 @@ mod tests { Element::new_sum_item_with_flags(100, Some(vec![0])), None, None, + grove_version, ) .unwrap() .expect("expected to insert item"); @@ -697,6 +729,7 @@ mod tests { Ok((NoStorageRemoval, NoStorageRemoval)) }, Some(&tx), + grove_version, ) .cost; @@ -721,11 +754,19 @@ mod tests { #[test] fn test_batch_one_update_sum_item_smaller_no_flags() { + let grove_version = GroveVersion::latest(); let db = make_empty_grovedb(); let tx = db.start_transaction(); - db.insert(EMPTY_PATH, b"tree", Element::empty_sum_tree(), None, None) - .unwrap() - .expect("expected to insert tree"); + db.insert( + EMPTY_PATH, + b"tree", + Element::empty_sum_tree(), + None, + None, + grove_version, + ) + .unwrap() + .expect("expected to insert tree"); db.insert( [b"tree".as_slice()].as_ref(), @@ -733,6 +774,7 @@ mod tests { Element::new_sum_item_with_flags(1000000, None), None, None, + grove_version, ) .unwrap() .expect("expected to insert item"); @@ -753,6 +795,7 @@ mod tests { Ok((NoStorageRemoval, NoStorageRemoval)) }, Some(&tx), + grove_version, ) .cost; @@ -777,11 +820,19 @@ mod tests { #[test] fn test_batch_one_update_sum_item_smaller_with_flags() { + let grove_version = GroveVersion::latest(); let db = make_empty_grovedb(); let tx = db.start_transaction(); - db.insert(EMPTY_PATH, b"tree", Element::empty_sum_tree(), None, None) - .unwrap() - .expect("expected to insert tree"); + db.insert( + EMPTY_PATH, + b"tree", + Element::empty_sum_tree(), + None, + None, + grove_version, + ) + .unwrap() + .expect("expected to insert tree"); db.insert( [b"tree".as_slice()].as_ref(), @@ -789,6 +840,7 @@ mod tests { Element::new_sum_item_with_flags(10000000, Some(vec![0])), None, None, + grove_version, ) .unwrap() .expect("expected to insert item"); @@ -809,6 +861,7 @@ mod tests { Ok((NoStorageRemoval, NoStorageRemoval)) }, Some(&tx), + grove_version, ) .cost; diff --git a/grovedb/src/debugger.rs b/grovedb/src/debugger.rs index 23acf447..de76c6df 100644 --- a/grovedb/src/debugger.rs +++ b/grovedb/src/debugger.rs @@ -5,6 +5,7 @@ use std::{fs, net::Ipv4Addr, sync::Weak}; use axum::{extract::State, http::StatusCode, response::IntoResponse, routing::post, Json, Router}; use grovedb_merk::debugger::NodeDbg; use grovedb_path::SubtreePath; +use grovedb_version::version::GroveVersion; use grovedbg_types::{NodeFetchRequest, NodeUpdate, Path}; use tokio::{ net::ToSocketAddrs, @@ -85,8 +86,9 @@ async fn fetch_node( return Err(AppError::Closed); }; + // todo: GroveVersion::latest() to actual version let merk = db - .open_non_transactional_merk_at_path(path.as_slice().into(), None) + .open_non_transactional_merk_at_path(path.as_slice().into(), None, GroveVersion::latest()) .unwrap()?; let node = merk.get_node_dbg(&key)?; @@ -106,8 +108,9 @@ async fn fetch_root_node( return Err(AppError::Closed); }; + // todo: GroveVersion::latest() to actual version let merk = db - .open_non_transactional_merk_at_path(SubtreePath::empty(), None) + .open_non_transactional_merk_at_path(SubtreePath::empty(), None, GroveVersion::latest()) .unwrap()?; let node = merk.get_root_node_dbg()?; @@ -129,7 +132,8 @@ fn node_to_update( right_child, }: NodeDbg, ) -> Result { - let grovedb_element = crate::Element::deserialize(&value)?; + // todo: GroveVersion::latest() to actual version + let grovedb_element = crate::Element::deserialize(&value, GroveVersion::latest())?; let element = match grovedb_element { crate::Element::Item(value, ..) => grovedbg_types::Element::Item { value }, diff --git a/grovedb/src/element/constructor.rs b/grovedb/src/element/constructor.rs index 09976e98..91143ec8 100644 --- a/grovedb/src/element/constructor.rs +++ b/grovedb/src/element/constructor.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. - //! Constructor //! Functions for setting an element's type diff --git a/grovedb/src/element/delete.rs b/grovedb/src/element/delete.rs index 92087bc4..9c0879a7 100644 --- a/grovedb/src/element/delete.rs +++ b/grovedb/src/element/delete.rs @@ -1,40 +1,20 @@ -// 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. - //! Delete //! Implements functions in Element for deleting +#[cfg(feature = "full")] +use grovedb_costs::OperationCost; #[cfg(feature = "full")] use grovedb_costs::{storage_cost::removal::StorageRemovedBytes, CostResult, CostsExt}; #[cfg(feature = "full")] use grovedb_merk::{BatchEntry, Error as MerkError, Merk, MerkOptions, Op}; #[cfg(feature = "full")] use grovedb_storage::StorageContext; +#[cfg(feature = "full")] +use grovedb_version::check_grovedb_v0_with_cost; +#[cfg(feature = "full")] +use grovedb_version::error::GroveVersionError; +#[cfg(feature = "full")] +use grovedb_version::version::GroveVersion; #[cfg(feature = "full")] use crate::{Element, Error}; @@ -48,7 +28,9 @@ impl Element { merk_options: Option, is_layered: bool, is_sum: bool, + grove_version: &GroveVersion, ) -> CostResult<(), Error> { + check_grovedb_v0_with_cost!("delete", grove_version.grovedb_versions.element.delete); let op = match (is_sum, is_layered) { (true, true) => Op::DeleteLayeredMaybeSpecialized, (true, false) => Op::DeleteMaybeSpecialized, @@ -62,10 +44,11 @@ impl Element { &[], merk_options, &|key, value| { - Self::specialized_costs_for_key_value(key, value, uses_sum_nodes) + Self::specialized_costs_for_key_value(key, value, uses_sum_nodes, grove_version) .map_err(|e| MerkError::ClientCorruptionError(e.to_string())) }, Some(&Element::value_defined_cost_for_serialized_value), + grove_version, ) .map_err(|e| Error::CorruptedData(e.to_string())) } @@ -86,7 +69,15 @@ impl Element { (StorageRemovedBytes, StorageRemovedBytes), MerkError, >, + grove_version: &GroveVersion, ) -> CostResult<(), Error> { + check_grovedb_v0_with_cost!( + "delete_with_sectioned_removal_bytes", + grove_version + .grovedb_versions + .element + .delete_with_sectioned_removal_bytes + ); let op = match (is_in_sum_tree, is_layered) { (true, true) => Op::DeleteLayeredMaybeSpecialized, (true, false) => Op::DeleteMaybeSpecialized, @@ -100,12 +91,13 @@ impl Element { &[], merk_options, &|key, value| { - Self::specialized_costs_for_key_value(key, value, uses_sum_nodes) + Self::specialized_costs_for_key_value(key, value, uses_sum_nodes, grove_version) .map_err(|e| MerkError::ClientCorruptionError(e.to_string())) }, Some(&Element::value_defined_cost_for_serialized_value), &mut |_costs, _old_value, _value| Ok((false, None)), sectioned_removal, + grove_version, ) .map_err(|e| Error::CorruptedData(e.to_string())) } @@ -117,7 +109,15 @@ impl Element { is_layered: bool, is_sum: bool, batch_operations: &mut Vec>, + grove_version: &GroveVersion, ) -> CostResult<(), Error> { + check_grovedb_v0_with_cost!( + "delete_into_batch_operations", + grove_version + .grovedb_versions + .element + .delete_into_batch_operations + ); let op = match (is_sum, is_layered) { (true, true) => Op::DeleteLayeredMaybeSpecialized, (true, false) => Op::DeleteMaybeSpecialized, diff --git a/grovedb/src/element/exists.rs b/grovedb/src/element/exists.rs index c3bf61fa..63dcfe4b 100644 --- a/grovedb/src/element/exists.rs +++ b/grovedb/src/element/exists.rs @@ -1,56 +1,35 @@ -// 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. - //! Exists //! Implements in Element functions for checking if stuff exists -#[cfg(feature = "full")] -use grovedb_costs::CostResult; -#[cfg(feature = "full")] +use grovedb_costs::{CostResult, CostsExt, OperationCost}; use grovedb_merk::Merk; -#[cfg(feature = "full")] use grovedb_storage::StorageContext; +use grovedb_version::{ + check_grovedb_v0_with_cost, error::GroveVersionError, version::GroveVersion, +}; -#[cfg(feature = "full")] use crate::{Element, Error}; impl Element { - #[cfg(feature = "full")] /// Helper function that returns whether an element at the key for the /// element already exists. pub fn element_at_key_already_exists<'db, K: AsRef<[u8]>, S: StorageContext<'db>>( &self, merk: &mut Merk, key: K, + grove_version: &GroveVersion, ) -> CostResult { + check_grovedb_v0_with_cost!( + "element_at_key_already_exists", + grove_version + .grovedb_versions + .element + .element_at_key_already_exists + ); merk.exists( key.as_ref(), Some(&Element::value_defined_cost_for_serialized_value), + grove_version, ) .map_err(|e| Error::CorruptedData(e.to_string())) } diff --git a/grovedb/src/element/get.rs b/grovedb/src/element/get.rs index 957618d0..1fda91dd 100644 --- a/grovedb/src/element/get.rs +++ b/grovedb/src/element/get.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. - //! Get //! Implements functions in Element for getting @@ -40,6 +12,9 @@ use grovedb_merk::Merk; use grovedb_merk::{ed::Decode, tree::TreeNodeInner}; #[cfg(feature = "full")] use grovedb_storage::StorageContext; +use grovedb_version::{ + check_grovedb_v0_with_cost, error::GroveVersionError, version::GroveVersion, +}; use integer_encoding::VarInt; use crate::element::{SUM_ITEM_COST_SIZE, SUM_TREE_COST_SIZE, TREE_COST_SIZE}; @@ -54,8 +29,10 @@ impl Element { merk: &Merk, key: K, allow_cache: bool, + grove_version: &GroveVersion, ) -> CostResult { - Self::get_optional(merk, key.as_ref(), allow_cache).map(|result| { + check_grovedb_v0_with_cost!("get", grove_version.grovedb_versions.element.get); + Self::get_optional(merk, key.as_ref(), allow_cache, grove_version).map(|result| { let value = result?; value.ok_or_else(|| { Error::PathKeyNotFound(format!( @@ -77,7 +54,12 @@ impl Element { merk: &Merk, key: K, allow_cache: bool, + grove_version: &GroveVersion, ) -> CostResult, Error> { + check_grovedb_v0_with_cost!( + "get_optional", + grove_version.grovedb_versions.element.get_optional + ); let mut cost = OperationCost::default(); let value_opt = cost_return_on_error!( @@ -85,7 +67,8 @@ impl Element { merk.get( key.as_ref(), allow_cache, - Some(&Element::value_defined_cost_for_serialized_value) + Some(&Element::value_defined_cost_for_serialized_value), + grove_version ) .map_err(|e| Error::CorruptedData(e.to_string())) ); @@ -93,7 +76,7 @@ impl Element { &cost, value_opt .map(|value| { - Self::deserialize(value.as_slice()).map_err(|_| { + Self::deserialize(value.as_slice(), grove_version).map_err(|_| { Error::CorruptedData(String::from("unable to deserialize element")) }) }) @@ -110,8 +93,13 @@ impl Element { pub fn get_from_storage<'db, K: AsRef<[u8]>, S: StorageContext<'db>>( storage: &S, key: K, + grove_version: &GroveVersion, ) -> CostResult { - Self::get_optional_from_storage(storage, key.as_ref()).map(|result| { + check_grovedb_v0_with_cost!( + "get_from_storage", + grove_version.grovedb_versions.element.get_from_storage + ); + Self::get_optional_from_storage(storage, key.as_ref(), grove_version).map(|result| { let value = result?; value.ok_or_else(|| { Error::PathKeyNotFound(format!( @@ -128,7 +116,15 @@ impl Element { pub fn get_optional_from_storage<'db, K: AsRef<[u8]>, S: StorageContext<'db>>( storage: &S, key: K, + grove_version: &GroveVersion, ) -> CostResult, Error> { + check_grovedb_v0_with_cost!( + "get_optional_from_storage", + grove_version + .grovedb_versions + .element + .get_optional_from_storage + ); let mut cost = OperationCost::default(); let key_ref = key.as_ref(); let node_value_opt = cost_return_on_error!( @@ -153,7 +149,7 @@ impl Element { value .as_ref() .map(|value| { - Self::deserialize(value.as_slice()).map_err(|_| { + Self::deserialize(value.as_slice(), grove_version).map_err(|_| { Error::CorruptedData(String::from("unable to deserialize element")) }) }) @@ -214,10 +210,21 @@ impl Element { path: &[&[u8]], key: K, allow_cache: bool, + grove_version: &GroveVersion, ) -> CostResult { + check_grovedb_v0_with_cost!( + "get_with_absolute_refs", + grove_version + .grovedb_versions + .element + .get_with_absolute_refs + ); let mut cost = OperationCost::default(); - let element = cost_return_on_error!(&mut cost, Self::get(merk, key.as_ref(), allow_cache)); + let element = cost_return_on_error!( + &mut cost, + Self::get(merk, key.as_ref(), allow_cache, grove_version) + ); let absolute_element = cost_return_on_error_no_add!( &cost, @@ -233,7 +240,12 @@ impl Element { merk: &Merk, key: K, allow_cache: bool, + grove_version: &GroveVersion, ) -> CostResult, Error> { + check_grovedb_v0_with_cost!( + "get_value_hash", + grove_version.grovedb_versions.element.get_value_hash + ); let mut cost = OperationCost::default(); let value_hash = cost_return_on_error!( @@ -241,7 +253,8 @@ impl Element { merk.get_value_hash( key.as_ref(), allow_cache, - Some(&Element::value_defined_cost_for_serialized_value) + Some(&Element::value_defined_cost_for_serialized_value), + grove_version ) .map_err(|e| Error::CorruptedData(e.to_string())) ); @@ -260,6 +273,7 @@ mod tests { #[test] fn test_cache_changes_cost() { + let grove_version = GroveVersion::latest(); let storage = TempStorage::new(); let batch = StorageBatch::new(); let ctx = storage @@ -269,15 +283,16 @@ mod tests { ctx, false, Some(&Element::value_defined_cost_for_serialized_value), + grove_version, ) .unwrap() .unwrap(); Element::empty_tree() - .insert(&mut merk, b"mykey", None) + .insert(&mut merk, b"mykey", None, grove_version) .unwrap() .expect("expected successful insertion"); Element::new_item(b"value".to_vec()) - .insert(&mut merk, b"another-key", None) + .insert(&mut merk, b"another-key", None, grove_version) .unwrap() .expect("expected successful insertion 2"); @@ -293,12 +308,13 @@ mod tests { ctx, false, Some(&Element::value_defined_cost_for_serialized_value), + grove_version, ) .unwrap() .unwrap(); assert_eq!( - Element::get(&merk, b"another-key", true) + Element::get(&merk, b"another-key", true, grove_version) .unwrap() .expect("expected successful get"), Element::new_item(b"value".to_vec()), @@ -306,14 +322,14 @@ mod tests { // Warm up cache because the Merk was reopened. Element::new_item(b"value".to_vec()) - .insert(&mut merk, b"another-key", None) + .insert(&mut merk, b"another-key", None, grove_version) .unwrap() .expect("expected successful insertion 2"); - let cost_with_cache = Element::get(&merk, b"another-key", true) + let cost_with_cache = Element::get(&merk, b"another-key", true, grove_version) .cost_as_result() .expect("expected to get cost"); - let cost_without_cache = Element::get(&merk, b"another-key", false) + let cost_without_cache = Element::get(&merk, b"another-key", false, grove_version) .cost_as_result() .expect("expected to get cost"); assert_ne!(cost_with_cache, cost_without_cache); diff --git a/grovedb/src/element/helpers.rs b/grovedb/src/element/helpers.rs index 59cc2563..2d2db076 100644 --- a/grovedb/src/element/helpers.rs +++ b/grovedb/src/element/helpers.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. - //! Helpers //! Implements helper functions in Element @@ -40,6 +12,7 @@ use grovedb_merk::{ TreeFeatureType, TreeFeatureType::{BasicMerkNode, SummedMerkNode}, }; +use grovedb_version::{check_grovedb_v0, error::GroveVersionError, version::GroveVersion}; #[cfg(feature = "full")] use integer_encoding::VarInt; @@ -216,55 +189,18 @@ impl Element { } } - #[cfg(feature = "full")] - /// Get the size of an element in bytes - #[deprecated] - pub fn byte_size(&self) -> u32 { - match self { - Element::Item(item, element_flag) => { - if let Some(flag) = element_flag { - flag.len() as u32 + item.len() as u32 - } else { - item.len() as u32 - } - } - Element::SumItem(item, element_flag) => { - if let Some(flag) = element_flag { - flag.len() as u32 + item.required_space() as u32 - } else { - item.required_space() as u32 - } - } - Element::Reference(path_reference, _, element_flag) => { - let path_length = path_reference.serialized_size() as u32; - - if let Some(flag) = element_flag { - flag.len() as u32 + path_length - } else { - path_length - } - } - Element::Tree(_, element_flag) => { - if let Some(flag) = element_flag { - flag.len() as u32 + 32 - } else { - 32 - } - } - Element::SumTree(_, _, element_flag) => { - if let Some(flag) = element_flag { - flag.len() as u32 + 32 + 8 - } else { - 32 + 8 - } - } - } - } - #[cfg(feature = "full")] /// Get the required item space - pub fn required_item_space(len: u32, flag_len: u32) -> u32 { - len + len.required_space() as u32 + flag_len + flag_len.required_space() as u32 + 1 + pub fn required_item_space( + len: u32, + flag_len: u32, + grove_version: &GroveVersion, + ) -> Result { + check_grovedb_v0!( + "required_item_space", + grove_version.grovedb_versions.element.required_item_space + ); + Ok(len + len.required_space() as u32 + flag_len + flag_len.required_space() as u32 + 1) } #[cfg(feature = "full")] @@ -274,9 +210,9 @@ impl Element { path: &[&[u8]], key: Option<&[u8]>, ) -> Result { - // Convert any non absolute reference type to an absolute one + // Convert any non-absolute reference type to an absolute one // we do this here because references are aggregated first then followed later - // to follow non absolute references, we need the path they are stored at + // to follow non-absolute references, we need the path they are stored at // this information is lost during the aggregation phase. Ok(match &self { Element::Reference(reference_path_type, ..) => match reference_path_type { @@ -304,9 +240,17 @@ impl Element { key: &Vec, value: &[u8], is_sum_node: bool, + grove_version: &GroveVersion, ) -> Result { + check_grovedb_v0!( + "specialized_costs_for_key_value", + grove_version + .grovedb_versions + .element + .specialized_costs_for_key_value + ); // todo: we actually don't need to deserialize the whole element - let element = Element::deserialize(value)?; + let element = Element::deserialize(value, grove_version)?; let cost = match element { Element::Tree(_, flags) => { let flags_len = flags.map_or(0, |flags| { @@ -358,7 +302,11 @@ impl Element { #[cfg(feature = "full")] /// Get tree cost for the element - pub fn get_specialized_cost(&self) -> Result { + pub fn get_specialized_cost(&self, grove_version: &GroveVersion) -> Result { + check_grovedb_v0!( + "get_specialized_cost", + grove_version.grovedb_versions.element.get_specialized_cost + ); match self { Element::Tree(..) => Ok(TREE_COST_SIZE), Element::SumTree(..) => Ok(SUM_TREE_COST_SIZE), @@ -371,8 +319,8 @@ impl Element { #[cfg(feature = "full")] /// Get the value defined cost for a serialized value - pub fn value_defined_cost(&self) -> Option { - let Some(value_cost) = self.get_specialized_cost().ok() else { + pub fn value_defined_cost(&self, grove_version: &GroveVersion) -> Option { + let Some(value_cost) = self.get_specialized_cost(grove_version).ok() else { return None; }; @@ -391,21 +339,25 @@ impl Element { #[cfg(feature = "full")] /// Get the value defined cost for a serialized value - pub fn value_defined_cost_for_serialized_value(value: &[u8]) -> Option { - let element = Element::deserialize(value).ok()?; - element.value_defined_cost() + pub fn value_defined_cost_for_serialized_value( + value: &[u8], + grove_version: &GroveVersion, + ) -> Option { + let element = Element::deserialize(value, grove_version).ok()?; + element.value_defined_cost(grove_version) } } #[cfg(feature = "full")] /// Decode from bytes -pub fn raw_decode(bytes: &[u8]) -> Result { +pub fn raw_decode(bytes: &[u8], grove_version: &GroveVersion) -> Result { let tree = TreeNode::decode_raw( bytes, vec![], Some(Element::value_defined_cost_for_serialized_value), + grove_version, ) .map_err(|e| Error::CorruptedData(e.to_string()))?; - let element: Element = Element::deserialize(tree.value_as_slice())?; + let element: Element = Element::deserialize(tree.value_as_slice(), grove_version)?; Ok(element) } diff --git a/grovedb/src/element/insert.rs b/grovedb/src/element/insert.rs index 2ba7f92d..ce0144a2 100644 --- a/grovedb/src/element/insert.rs +++ b/grovedb/src/element/insert.rs @@ -1,49 +1,18 @@ -// 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. - //! Insert //! Implements functions in Element for inserting into Merk -use grovedb_costs::cost_return_on_error_default; -#[cfg(feature = "full")] use grovedb_costs::{ - cost_return_on_error, cost_return_on_error_no_add, CostResult, CostsExt, OperationCost, + cost_return_on_error, cost_return_on_error_default, cost_return_on_error_no_add, CostResult, + CostsExt, OperationCost, }; -#[cfg(feature = "full")] use grovedb_merk::{BatchEntry, Error as MerkError, Merk, MerkOptions, Op, TreeFeatureType}; -#[cfg(feature = "full")] use grovedb_storage::StorageContext; -#[cfg(feature = "full")] +use grovedb_version::{ + check_grovedb_v0_with_cost, error::GroveVersionError, version::GroveVersion, +}; use integer_encoding::VarInt; -use crate::Element::SumItem; -#[cfg(feature = "full")] -use crate::{Element, Error, Hash}; +use crate::{Element, Element::SumItem, Error, Hash}; impl Element { #[cfg(feature = "full")] @@ -57,8 +26,11 @@ impl Element { merk: &mut Merk, key: K, options: Option, + grove_version: &GroveVersion, ) -> CostResult<(), Error> { - let serialized = cost_return_on_error_default!(self.serialize()); + check_grovedb_v0_with_cost!("insert", grove_version.grovedb_versions.element.insert); + + let serialized = cost_return_on_error_default!(self.serialize(grove_version)); if !merk.is_sum_tree && self.is_sum_item() { return Err(Error::InvalidInput("cannot add sum item to non sum tree")) @@ -68,7 +40,8 @@ impl Element { let merk_feature_type = cost_return_on_error_default!(self.get_feature_type(merk.is_sum_tree)); let batch_operations = if matches!(self, SumItem(..)) { - let value_cost = cost_return_on_error_default!(self.get_specialized_cost()); + let value_cost = + cost_return_on_error_default!(self.get_specialized_cost(grove_version)); let cost = value_cost + self.get_flags().as_ref().map_or(0, |flags| { @@ -89,10 +62,11 @@ impl Element { options, &|key, value| { // it is possible that a normal item was being replaced with a - Self::specialized_costs_for_key_value(key, value, uses_sum_nodes) + Self::specialized_costs_for_key_value(key, value, uses_sum_nodes, grove_version) .map_err(|e| MerkError::ClientCorruptionError(e.to_string())) }, Some(&Element::value_defined_cost_for_serialized_value), + grove_version, ) .map_err(|e| Error::CorruptedData(e.to_string())) } @@ -105,14 +79,24 @@ impl Element { key: K, batch_operations: &mut Vec>, feature_type: TreeFeatureType, + grove_version: &GroveVersion, ) -> CostResult<(), Error> { - let serialized = match self.serialize() { + check_grovedb_v0_with_cost!( + "insert_into_batch_operations", + grove_version + .grovedb_versions + .element + .insert_into_batch_operations + ); + + let serialized = match self.serialize(grove_version) { Ok(s) => s, Err(e) => return Err(e).wrap_with_cost(Default::default()), }; let entry = if matches!(self, SumItem(..)) { - let value_cost = cost_return_on_error_default!(self.get_specialized_cost()); + let value_cost = + cost_return_on_error_default!(self.get_specialized_cost(grove_version)); let cost = value_cost + self.get_flags().as_ref().map_or(0, |flags| { @@ -141,14 +125,22 @@ impl Element { merk: &mut Merk, key: &[u8], options: Option, + grove_version: &GroveVersion, ) -> CostResult { + check_grovedb_v0_with_cost!( + "insert_if_not_exists", + grove_version.grovedb_versions.element.insert_if_not_exists + ); + let mut cost = OperationCost::default(); - let exists = - cost_return_on_error!(&mut cost, self.element_at_key_already_exists(merk, key)); + let exists = cost_return_on_error!( + &mut cost, + self.element_at_key_already_exists(merk, key, grove_version) + ); if exists { Ok(false).wrap_with_cost(cost) } else { - cost_return_on_error!(&mut cost, self.insert(merk, key, options)); + cost_return_on_error!(&mut cost, self.insert(merk, key, options, grove_version)); Ok(true).wrap_with_cost(cost) } } @@ -166,18 +158,32 @@ impl Element { key: K, batch_operations: &mut Vec>, feature_type: TreeFeatureType, + grove_version: &GroveVersion, ) -> CostResult { + check_grovedb_v0_with_cost!( + "insert_if_not_exists_into_batch_operations", + grove_version + .grovedb_versions + .element + .insert_if_not_exists_into_batch_operations + ); + let mut cost = OperationCost::default(); let exists = cost_return_on_error!( &mut cost, - self.element_at_key_already_exists(merk, key.as_ref()) + self.element_at_key_already_exists(merk, key.as_ref(), grove_version) ); if exists { Ok(false).wrap_with_cost(cost) } else { cost_return_on_error!( &mut cost, - self.insert_into_batch_operations(key, batch_operations, feature_type) + self.insert_into_batch_operations( + key, + batch_operations, + feature_type, + grove_version + ) ); Ok(true).wrap_with_cost(cost) } @@ -196,11 +202,20 @@ impl Element { merk: &mut Merk, key: &[u8], options: Option, + grove_version: &GroveVersion, ) -> CostResult<(bool, Option), Error> { + check_grovedb_v0_with_cost!( + "insert_if_changed_value", + grove_version + .grovedb_versions + .element + .insert_if_changed_value + ); + let mut cost = OperationCost::default(); let previous_element = cost_return_on_error!( &mut cost, - Self::get_optional_from_storage(&merk.storage, key) + Self::get_optional_from_storage(&merk.storage, key, grove_version) ); let needs_insert = match &previous_element { None => true, @@ -209,7 +224,7 @@ impl Element { if !needs_insert { Ok((false, None)).wrap_with_cost(cost) } else { - cost_return_on_error!(&mut cost, self.insert(merk, key, options)); + cost_return_on_error!(&mut cost, self.insert(merk, key, options, grove_version)); Ok((true, previous_element)).wrap_with_cost(cost) } } @@ -229,11 +244,20 @@ impl Element { key: K, batch_operations: &mut Vec>, feature_type: TreeFeatureType, + grove_version: &GroveVersion, ) -> CostResult<(bool, Option), Error> { + check_grovedb_v0_with_cost!( + "insert_if_changed_value_into_batch_operations", + grove_version + .grovedb_versions + .element + .insert_if_changed_value_into_batch_operations + ); + let mut cost = OperationCost::default(); let previous_element = cost_return_on_error!( &mut cost, - Self::get_optional_from_storage(&merk.storage, key.as_ref()) + Self::get_optional_from_storage(&merk.storage, key.as_ref(), grove_version) ); let needs_insert = match &previous_element { None => true, @@ -244,7 +268,12 @@ impl Element { } else { cost_return_on_error!( &mut cost, - self.insert_into_batch_operations(key, batch_operations, feature_type) + self.insert_into_batch_operations( + key, + batch_operations, + feature_type, + grove_version + ) ); Ok((true, previous_element)).wrap_with_cost(cost) } @@ -262,8 +291,14 @@ impl Element { key: K, referenced_value: Hash, options: Option, + grove_version: &GroveVersion, ) -> CostResult<(), Error> { - let serialized = match self.serialize() { + check_grovedb_v0_with_cost!( + "insert_reference", + grove_version.grovedb_versions.element.insert_reference + ); + + let serialized = match self.serialize(grove_version) { Ok(s) => s, Err(e) => return Err(e).wrap_with_cost(Default::default()), }; @@ -285,10 +320,11 @@ impl Element { &[], options, &|key, value| { - Self::specialized_costs_for_key_value(key, value, uses_sum_nodes) + Self::specialized_costs_for_key_value(key, value, uses_sum_nodes, grove_version) .map_err(|e| MerkError::ClientCorruptionError(e.to_string())) }, Some(&Element::value_defined_cost_for_serialized_value), + grove_version, ) .map_err(|e| Error::CorruptedData(e.to_string())) } @@ -302,8 +338,17 @@ impl Element { referenced_value: Hash, batch_operations: &mut Vec>, feature_type: TreeFeatureType, + grove_version: &GroveVersion, ) -> CostResult<(), Error> { - let serialized = match self.serialize() { + check_grovedb_v0_with_cost!( + "insert_reference_into_batch_operations", + grove_version + .grovedb_versions + .element + .insert_reference_into_batch_operations + ); + + let serialized = match self.serialize(grove_version) { Ok(s) => s, Err(e) => return Err(e).wrap_with_cost(Default::default()), }; @@ -328,8 +373,14 @@ impl Element { key: K, subtree_root_hash: Hash, options: Option, + grove_version: &GroveVersion, ) -> CostResult<(), Error> { - let serialized = match self.serialize() { + check_grovedb_v0_with_cost!( + "insert_subtree", + grove_version.grovedb_versions.element.insert_subtree + ); + + let serialized = match self.serialize(grove_version) { Ok(s) => s, Err(e) => return Err(e).wrap_with_cost(Default::default()), }; @@ -338,7 +389,8 @@ impl Element { let merk_feature_type = cost_return_on_error_no_add!(&cost, self.get_feature_type(merk.is_sum_tree)); - let tree_cost = cost_return_on_error_no_add!(&cost, self.get_specialized_cost()); + let tree_cost = + cost_return_on_error_no_add!(&cost, self.get_specialized_cost(grove_version)); let cost = tree_cost + self.get_flags().as_ref().map_or(0, |flags| { @@ -355,10 +407,11 @@ impl Element { &[], options, &|key, value| { - Self::specialized_costs_for_key_value(key, value, uses_sum_nodes) + Self::specialized_costs_for_key_value(key, value, uses_sum_nodes, grove_version) .map_err(|e| MerkError::ClientCorruptionError(e.to_string())) }, Some(&Element::value_defined_cost_for_serialized_value), + grove_version, ) .map_err(|e| Error::CorruptedData(e.to_string())) } @@ -372,13 +425,22 @@ impl Element { is_replace: bool, batch_operations: &mut Vec>, feature_type: TreeFeatureType, + grove_version: &GroveVersion, ) -> CostResult<(), Error> { - let serialized = match self.serialize() { + check_grovedb_v0_with_cost!( + "insert_subtree_into_batch_operations", + grove_version + .grovedb_versions + .element + .insert_subtree_into_batch_operations + ); + + let serialized = match self.serialize(grove_version) { Ok(s) => s, Err(e) => return Err(e).wrap_with_cost(Default::default()), }; - let tree_cost = cost_return_on_error_default!(self.get_specialized_cost()); + let tree_cost = cost_return_on_error_default!(self.get_specialized_cost(grove_version)); let cost = tree_cost + self.get_flags().as_ref().map_or(0, |flags| { @@ -413,18 +475,19 @@ mod tests { #[test] fn test_success_insert() { - let mut merk = TempMerk::new(); + let grove_version = GroveVersion::latest(); + let mut merk = TempMerk::new(grove_version); Element::empty_tree() - .insert(&mut merk, b"mykey", None) + .insert(&mut merk, b"mykey", None, grove_version) .unwrap() .expect("expected successful insertion"); Element::new_item(b"value".to_vec()) - .insert(&mut merk, b"another-key", None) + .insert(&mut merk, b"another-key", None, grove_version) .unwrap() .expect("expected successful insertion 2"); assert_eq!( - Element::get(&merk, b"another-key", true) + Element::get(&merk, b"another-key", true, grove_version) .unwrap() .expect("expected successful get"), Element::new_item(b"value".to_vec()), @@ -433,30 +496,31 @@ mod tests { #[test] fn test_insert_if_changed_value_does_not_insert_when_value_does_not_change() { - let mut merk = TempMerk::new(); + let grove_version = GroveVersion::latest(); + let mut merk = TempMerk::new(grove_version); Element::empty_tree() - .insert(&mut merk, b"mykey", None) + .insert(&mut merk, b"mykey", None, grove_version) .unwrap() .expect("expected successful insertion"); Element::new_item(b"value".to_vec()) - .insert(&mut merk, b"another-key", None) + .insert(&mut merk, b"another-key", None, grove_version) .unwrap() .expect("expected successful insertion 2"); - merk.commit(); + merk.commit(grove_version); let (inserted, previous) = Element::new_item(b"value".to_vec()) - .insert_if_changed_value(&mut merk, b"another-key", None) + .insert_if_changed_value(&mut merk, b"another-key", None, grove_version) .unwrap() .expect("expected successful insertion 2"); - merk.commit(); + merk.commit(grove_version); assert!(!inserted); assert_eq!(previous, None); assert_eq!( - Element::get(&merk, b"another-key", true) + Element::get(&merk, b"another-key", true, grove_version) .unwrap() .expect("expected successful get"), Element::new_item(b"value".to_vec()), @@ -465,16 +529,17 @@ mod tests { #[test] fn test_insert_if_changed_value_inserts_when_value_changed() { + let grove_version = GroveVersion::latest(); let storage = TempStorage::new(); let batch = StorageBatch::new(); - let mut merk = empty_path_merk(&*storage, &batch); + let mut merk = empty_path_merk(&*storage, &batch, grove_version); Element::empty_tree() - .insert(&mut merk, b"mykey", None) + .insert(&mut merk, b"mykey", None, grove_version) .unwrap() .expect("expected successful insertion"); Element::new_item(b"value".to_vec()) - .insert(&mut merk, b"another-key", None) + .insert(&mut merk, b"another-key", None, grove_version) .unwrap() .expect("expected successful insertion 2"); @@ -484,9 +549,9 @@ mod tests { .unwrap(); let batch = StorageBatch::new(); - let mut merk = empty_path_merk(&*storage, &batch); + let mut merk = empty_path_merk(&*storage, &batch, grove_version); let (inserted, previous) = Element::new_item(b"value2".to_vec()) - .insert_if_changed_value(&mut merk, b"another-key", None) + .insert_if_changed_value(&mut merk, b"another-key", None, grove_version) .unwrap() .expect("expected successful insertion 2"); @@ -497,10 +562,10 @@ mod tests { .commit_multi_context_batch(batch, None) .unwrap() .unwrap(); - let merk = empty_path_merk_read_only(&*storage); + let merk = empty_path_merk_read_only(&*storage, grove_version); assert_eq!( - Element::get(&merk, b"another-key", true) + Element::get(&merk, b"another-key", true, grove_version) .unwrap() .expect("expected successful get"), Element::new_item(b"value2".to_vec()), @@ -509,13 +574,14 @@ mod tests { #[test] fn test_insert_if_changed_value_inserts_when_no_value() { - let mut merk = TempMerk::new(); + let grove_version = GroveVersion::latest(); + let mut merk = TempMerk::new(grove_version); Element::empty_tree() - .insert(&mut merk, b"mykey", None) + .insert(&mut merk, b"mykey", None, grove_version) .unwrap() .expect("expected successful insertion"); let (inserted, previous) = Element::new_item(b"value2".to_vec()) - .insert_if_changed_value(&mut merk, b"another-key", None) + .insert_if_changed_value(&mut merk, b"another-key", None, grove_version) .unwrap() .expect("expected successful insertion 2"); @@ -523,7 +589,7 @@ mod tests { assert_eq!(previous, None); assert_eq!( - Element::get(&merk, b"another-key", true) + Element::get(&merk, b"another-key", true, grove_version) .unwrap() .expect("expected successful get"), Element::new_item(b"value2".to_vec()), diff --git a/grovedb/src/element/query.rs b/grovedb/src/element/query.rs index 48d9e34d..39c0494c 100644 --- a/grovedb/src/element/query.rs +++ b/grovedb/src/element/query.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. - //! Query //! Implements functions in Element for querying @@ -46,6 +18,9 @@ use grovedb_merk::proofs::Query; use grovedb_path::SubtreePath; #[cfg(feature = "full")] use grovedb_storage::{rocksdb_storage::RocksDbStorage, RawIterator, StorageContext}; +use grovedb_version::{ + check_grovedb_v0, check_grovedb_v0_with_cost, error::GroveVersionError, version::GroveVersion, +}; #[cfg(feature = "full")] use crate::operations::proof::util::hex_to_ascii; @@ -261,7 +236,13 @@ impl Element { query_options: QueryOptions, result_type: QueryResultType, transaction: TransactionArg, + grove_version: &GroveVersion, ) -> CostResult { + check_grovedb_v0_with_cost!( + "insert_subtree_into_batch_operations", + grove_version.grovedb_versions.element.get_query + ); + let sized_query = SizedQuery::new(query.clone(), None, None); Element::get_sized_query( storage, @@ -270,6 +251,7 @@ impl Element { query_options, result_type, transaction, + grove_version, ) .map_ok(|(elements, _)| elements) } @@ -282,7 +264,13 @@ impl Element { query: &Query, query_options: QueryOptions, transaction: TransactionArg, + grove_version: &GroveVersion, ) -> CostResult, Error> { + check_grovedb_v0_with_cost!( + "get_query_values", + grove_version.grovedb_versions.element.get_query_values + ); + Element::get_query( storage, merk_path, @@ -290,6 +278,7 @@ impl Element { query_options, QueryElementResultType, transaction, + grove_version, ) .flat_map_ok(|result_items| { let elements: Vec = result_items @@ -315,8 +304,17 @@ impl Element { query_options: QueryOptions, result_type: QueryResultType, transaction: TransactionArg, - add_element_function: fn(PathQueryPushArgs) -> CostResult<(), Error>, + add_element_function: fn(PathQueryPushArgs, &GroveVersion) -> CostResult<(), Error>, + grove_version: &GroveVersion, ) -> CostResult<(QueryResultElements, u16), Error> { + check_grovedb_v0_with_cost!( + "get_query_apply_function", + grove_version + .grovedb_versions + .element + .get_query_apply_function + ); + let mut cost = OperationCost::default(); let mut results = Vec::new(); @@ -341,6 +339,7 @@ impl Element { query_options, result_type, add_element_function, + grove_version, ) ); if limit == Some(0) { @@ -363,6 +362,7 @@ impl Element { query_options, result_type, add_element_function, + grove_version, ) ); if limit == Some(0) { @@ -388,7 +388,13 @@ impl Element { query_options: QueryOptions, result_type: QueryResultType, transaction: TransactionArg, + grove_version: &GroveVersion, ) -> CostResult<(QueryResultElements, u16), Error> { + check_grovedb_v0_with_cost!( + "get_path_query", + grove_version.grovedb_versions.element.get_path_query + ); + let path_slices = path_query .path .iter() @@ -402,6 +408,7 @@ impl Element { result_type, transaction, Element::path_query_push, + grove_version, ) } @@ -414,7 +421,13 @@ impl Element { query_options: QueryOptions, result_type: QueryResultType, transaction: TransactionArg, + grove_version: &GroveVersion, ) -> CostResult<(QueryResultElements, u16), Error> { + check_grovedb_v0_with_cost!( + "get_sized_query", + grove_version.grovedb_versions.element.get_sized_query + ); + Element::get_query_apply_function( storage, path, @@ -423,12 +436,21 @@ impl Element { result_type, transaction, Element::path_query_push, + grove_version, ) } #[cfg(feature = "full")] /// Push arguments to path query - fn path_query_push(args: PathQueryPushArgs) -> CostResult<(), Error> { + fn path_query_push( + args: PathQueryPushArgs, + grove_version: &GroveVersion, + ) -> CostResult<(), Error> { + check_grovedb_v0_with_cost!( + "path_query_push", + grove_version.grovedb_versions.element.path_query_push + ); + // println!("path_query_push {} \n", args); let mut cost = OperationCost::default(); @@ -480,7 +502,8 @@ impl Element { &inner_path_query, query_options, result_type, - transaction + transaction, + grove_version, ) ); @@ -514,6 +537,7 @@ impl Element { None, transaction, subtree, + grove_version, { results.push(QueryResultElement::ElementResultItem( cost_return_on_error!( @@ -523,6 +547,7 @@ impl Element { path_vec.as_slice(), subquery_path_last_key.as_slice(), allow_cache, + grove_version, ) ), )); @@ -537,6 +562,7 @@ impl Element { None, transaction, subtree, + grove_version, { results.push(QueryResultElement::KeyElementPairResultItem( ( @@ -548,6 +574,7 @@ impl Element { path_vec.as_slice(), subquery_path_last_key.as_slice(), allow_cache, + grove_version, ) ), ), @@ -563,6 +590,7 @@ impl Element { None, transaction, subtree, + grove_version, { results.push( QueryResultElement::PathKeyElementTrioResultItem(( @@ -575,6 +603,7 @@ impl Element { path_vec.as_slice(), subquery_path_last_key.as_slice(), allow_cache, + grove_version, ) ), )), @@ -599,21 +628,24 @@ impl Element { } else if allow_get_raw { cost_return_on_error_no_add!( &cost, - Element::basic_push(PathQueryPushArgs { - storage, - transaction, - key: Some(key), - element, - path, - subquery_path, - subquery, - left_to_right, - query_options, - result_type, - results, - limit, - offset, - }) + Element::basic_push( + PathQueryPushArgs { + storage, + transaction, + key: Some(key), + element, + path, + subquery_path, + subquery, + left_to_right, + query_options, + result_type, + results, + limit, + offset, + }, + grove_version + ) ); } else { return Err(Error::InvalidPath( @@ -626,21 +658,24 @@ impl Element { } else { cost_return_on_error_no_add!( &cost, - Element::basic_push(PathQueryPushArgs { - storage, - transaction, - key, - element, - path, - subquery_path, - subquery, - left_to_right, - query_options, - result_type, - results, - limit, - offset, - }) + Element::basic_push( + PathQueryPushArgs { + storage, + transaction, + key, + element, + path, + subquery_path, + subquery, + left_to_right, + query_options, + result_type, + results, + limit, + offset, + }, + grove_version + ) ); } Ok(()).wrap_with_cost(cost) @@ -649,7 +684,7 @@ impl Element { #[cfg(any(feature = "full", feature = "verify"))] /// Takes a sized query and a key and returns subquery key and subquery as /// tuple - pub fn subquery_paths_and_value_for_sized_query( + fn subquery_paths_and_value_for_sized_query( sized_query: &SizedQuery, key: &[u8], ) -> (Option, Option) { @@ -700,8 +735,14 @@ impl Element { offset: &mut Option, query_options: QueryOptions, result_type: QueryResultType, - add_element_function: fn(PathQueryPushArgs) -> CostResult<(), Error>, + add_element_function: fn(PathQueryPushArgs, &GroveVersion) -> CostResult<(), Error>, + grove_version: &GroveVersion, ) -> CostResult<(), Error> { + check_grovedb_v0_with_cost!( + "query_item", + grove_version.grovedb_versions.element.query_item + ); + let mut cost = OperationCost::default(); let subtree_path: SubtreePath<_> = path.into(); @@ -716,8 +757,9 @@ impl Element { None, transaction, subtree, + grove_version, { - Element::get(&subtree, key, query_options.allow_cache) + Element::get(&subtree, key, query_options.allow_cache, grove_version) .unwrap_add_cost(&mut cost) } ); @@ -725,21 +767,24 @@ impl Element { Ok(element) => { let (subquery_path, subquery) = Self::subquery_paths_and_value_for_sized_query(sized_query, key); - match add_element_function(PathQueryPushArgs { - storage, - transaction, - key: Some(key.as_slice()), - element, - path, - subquery_path, - subquery, - left_to_right: sized_query.query.left_to_right, - query_options, - result_type, - results, - limit, - offset, - }) + match add_element_function( + PathQueryPushArgs { + storage, + transaction, + key: Some(key.as_slice()), + element, + path, + subquery_path, + subquery, + left_to_right: sized_query.query.left_to_right, + query_options, + result_type, + results, + limit, + offset, + }, + grove_version, + ) .unwrap_add_cost(&mut cost) { Ok(_) => Ok(()), @@ -790,7 +835,8 @@ impl Element { raw_decode( iter.value() .unwrap_add_cost(&mut cost) - .expect("if key exists then value should too") + .expect("if key exists then value should too"), + grove_version ) ); let key = iter @@ -799,21 +845,24 @@ impl Element { .expect("key should exist"); let (subquery_path, subquery) = Self::subquery_paths_and_value_for_sized_query(sized_query, key); - let result_with_cost = add_element_function(PathQueryPushArgs { - storage, - transaction, - key: Some(key), - element, - path, - subquery_path, - subquery, - left_to_right: sized_query.query.left_to_right, - query_options, - result_type, - results, - limit, - offset, - }); + let result_with_cost = add_element_function( + PathQueryPushArgs { + storage, + transaction, + key: Some(key), + element, + path, + subquery_path, + subquery, + left_to_right: sized_query.query.left_to_right, + query_options, + result_type, + results, + limit, + offset, + }, + grove_version, + ); let result = result_with_cost.unwrap_add_cost(&mut cost); match result { Ok(x) => x, @@ -843,7 +892,12 @@ impl Element { } #[cfg(feature = "full")] - fn basic_push(args: PathQueryPushArgs) -> Result<(), Error> { + fn basic_push(args: PathQueryPushArgs, grove_version: &GroveVersion) -> Result<(), Error> { + check_grovedb_v0!( + "basic_push", + grove_version.grovedb_versions.element.basic_push + ); + // println!("basic_push {}", args); let PathQueryPushArgs { path, @@ -907,6 +961,7 @@ impl Element { mod tests { use grovedb_merk::proofs::Query; use grovedb_storage::{Storage, StorageBatch}; + use grovedb_version::version::GroveVersion; use crate::{ element::{query::QueryOptions, *}, @@ -920,7 +975,8 @@ mod tests { #[test] fn test_get_query() { - let db = make_test_grovedb(); + let grove_version = GroveVersion::latest(); + let db = make_test_grovedb(grove_version); db.insert( [TEST_LEAF].as_ref(), @@ -928,6 +984,7 @@ mod tests { Element::new_item(b"ayyd".to_vec()), None, None, + grove_version, ) .unwrap() .expect("cannot insert element"); @@ -937,6 +994,7 @@ mod tests { Element::new_item(b"ayyc".to_vec()), None, None, + grove_version, ) .unwrap() .expect("cannot insert element"); @@ -946,6 +1004,7 @@ mod tests { Element::new_item(b"ayya".to_vec()), None, None, + grove_version, ) .unwrap() .expect("cannot insert element"); @@ -955,6 +1014,7 @@ mod tests { Element::new_item(b"ayyb".to_vec()), None, None, + grove_version, ) .unwrap() .expect("cannot insert element"); @@ -965,9 +1025,16 @@ mod tests { query.insert_key(b"a".to_vec()); assert_eq!( - Element::get_query_values(&db.db, &[TEST_LEAF], &query, QueryOptions::default(), None) - .unwrap() - .expect("expected successful get_query"), + Element::get_query_values( + &db.db, + &[TEST_LEAF], + &query, + QueryOptions::default(), + None, + grove_version + ) + .unwrap() + .expect("expected successful get_query"), vec![ Element::new_item(b"ayya".to_vec()), Element::new_item(b"ayyc".to_vec()) @@ -979,9 +1046,16 @@ mod tests { query.insert_range(b"b".to_vec()..b"d".to_vec()); query.insert_range(b"a".to_vec()..b"c".to_vec()); assert_eq!( - Element::get_query_values(&db.db, &[TEST_LEAF], &query, QueryOptions::default(), None) - .unwrap() - .expect("expected successful get_query"), + Element::get_query_values( + &db.db, + &[TEST_LEAF], + &query, + QueryOptions::default(), + None, + grove_version + ) + .unwrap() + .expect("expected successful get_query"), vec![ Element::new_item(b"ayya".to_vec()), Element::new_item(b"ayyb".to_vec()), @@ -994,9 +1068,16 @@ mod tests { query.insert_range_inclusive(b"b".to_vec()..=b"d".to_vec()); query.insert_range(b"b".to_vec()..b"c".to_vec()); assert_eq!( - Element::get_query_values(&db.db, &[TEST_LEAF], &query, QueryOptions::default(), None) - .unwrap() - .expect("expected successful get_query"), + Element::get_query_values( + &db.db, + &[TEST_LEAF], + &query, + QueryOptions::default(), + None, + grove_version + ) + .unwrap() + .expect("expected successful get_query"), vec![ Element::new_item(b"ayyb".to_vec()), Element::new_item(b"ayyc".to_vec()), @@ -1010,9 +1091,16 @@ mod tests { query.insert_range(b"b".to_vec()..b"d".to_vec()); query.insert_range(b"a".to_vec()..b"c".to_vec()); assert_eq!( - Element::get_query_values(&db.db, &[TEST_LEAF], &query, QueryOptions::default(), None) - .unwrap() - .expect("expected successful get_query"), + Element::get_query_values( + &db.db, + &[TEST_LEAF], + &query, + QueryOptions::default(), + None, + grove_version + ) + .unwrap() + .expect("expected successful get_query"), vec![ Element::new_item(b"ayya".to_vec()), Element::new_item(b"ayyb".to_vec()), @@ -1023,7 +1111,8 @@ mod tests { #[test] fn test_get_query_with_path() { - let db = make_test_grovedb(); + let grove_version = GroveVersion::latest(); + let db = make_test_grovedb(grove_version); db.insert( [TEST_LEAF].as_ref(), @@ -1031,6 +1120,7 @@ mod tests { Element::new_item(b"ayyd".to_vec()), None, None, + grove_version, ) .unwrap() .expect("cannot insert element"); @@ -1040,6 +1130,7 @@ mod tests { Element::new_item(b"ayyc".to_vec()), None, None, + grove_version, ) .unwrap() .expect("cannot insert element"); @@ -1049,6 +1140,7 @@ mod tests { Element::new_item(b"ayya".to_vec()), None, None, + grove_version, ) .unwrap() .expect("cannot insert element"); @@ -1058,6 +1150,7 @@ mod tests { Element::new_item(b"ayyb".to_vec()), None, None, + grove_version, ) .unwrap() .expect("cannot insert element"); @@ -1073,7 +1166,8 @@ mod tests { &query, QueryOptions::default(), QueryPathKeyElementTrioResultType, - None + None, + grove_version ) .unwrap() .expect("expected successful get_query") @@ -1095,29 +1189,34 @@ mod tests { #[test] fn test_get_range_query() { - let db = make_test_grovedb(); + let grove_version = GroveVersion::latest(); + let db = make_test_grovedb(grove_version); let batch = StorageBatch::new(); let storage = &db.db; let mut merk = db - .open_non_transactional_merk_at_path([TEST_LEAF].as_ref().into(), Some(&batch)) + .open_non_transactional_merk_at_path( + [TEST_LEAF].as_ref().into(), + Some(&batch), + grove_version, + ) .unwrap() .expect("cannot open Merk"); // TODO implement costs Element::new_item(b"ayyd".to_vec()) - .insert(&mut merk, b"d", None) + .insert(&mut merk, b"d", None, grove_version) .unwrap() .expect("expected successful insertion"); Element::new_item(b"ayyc".to_vec()) - .insert(&mut merk, b"c", None) + .insert(&mut merk, b"c", None, grove_version) .unwrap() .expect("expected successful insertion"); Element::new_item(b"ayya".to_vec()) - .insert(&mut merk, b"a", None) + .insert(&mut merk, b"a", None, grove_version) .unwrap() .expect("expected successful insertion"); Element::new_item(b"ayyb".to_vec()) - .insert(&mut merk, b"b", None) + .insert(&mut merk, b"b", None, grove_version) .unwrap() .expect("expected successful insertion"); @@ -1138,6 +1237,7 @@ mod tests { QueryOptions::default(), QueryKeyElementPairResultType, None, + grove_version, ) .unwrap() .expect("expected successful get_query"); @@ -1172,6 +1272,7 @@ mod tests { QueryOptions::default(), QueryKeyElementPairResultType, None, + grove_version, ) .unwrap() .expect("expected successful get_query"); @@ -1199,30 +1300,35 @@ mod tests { #[test] fn test_get_range_inclusive_query() { - let db = make_test_grovedb(); + let grove_version = GroveVersion::latest(); + let db = make_test_grovedb(grove_version); let batch = StorageBatch::new(); let storage = &db.db; let mut merk = db - .open_non_transactional_merk_at_path([TEST_LEAF].as_ref().into(), Some(&batch)) + .open_non_transactional_merk_at_path( + [TEST_LEAF].as_ref().into(), + Some(&batch), + grove_version, + ) .unwrap() .expect("cannot open Merk"); Element::new_item(b"ayyd".to_vec()) - .insert(&mut merk, b"d", None) + .insert(&mut merk, b"d", None, grove_version) .unwrap() .expect("expected successful insertion"); Element::new_item(b"ayyc".to_vec()) - .insert(&mut merk, b"c", None) + .insert(&mut merk, b"c", None, grove_version) .unwrap() .expect("expected successful insertion"); Element::new_item(b"ayya".to_vec()) - .insert(&mut merk, b"a", None) + .insert(&mut merk, b"a", None, grove_version) .unwrap() .expect("expected successful insertion"); Element::new_item(b"ayyb".to_vec()) - .insert(&mut merk, b"b", None) + .insert(&mut merk, b"b", None, grove_version) .unwrap() .expect("expected successful insertion"); @@ -1261,6 +1367,7 @@ mod tests { QueryOptions::default(), QueryKeyElementPairResultType, None, + grove_version, ) .unwrap() .expect("expected successful get_query"), @@ -1278,6 +1385,7 @@ mod tests { QueryOptions::default(), QueryKeyElementPairResultType, None, + grove_version, ) .unwrap() .expect("expected successful get_query"), @@ -1298,6 +1406,7 @@ mod tests { QueryOptions::default(), QueryKeyElementPairResultType, None, + grove_version, ) .unwrap() .expect("expected successful get_query"), @@ -1307,7 +1416,8 @@ mod tests { #[test] fn test_get_limit_query() { - let db = make_test_grovedb(); + let grove_version = GroveVersion::latest(); + let db = make_test_grovedb(grove_version); db.insert( [TEST_LEAF].as_ref(), @@ -1315,6 +1425,7 @@ mod tests { Element::new_item(b"ayyd".to_vec()), None, None, + grove_version, ) .unwrap() .expect("cannot insert element"); @@ -1324,6 +1435,7 @@ mod tests { Element::new_item(b"ayyc".to_vec()), None, None, + grove_version, ) .unwrap() .expect("cannot insert element"); @@ -1333,6 +1445,7 @@ mod tests { Element::new_item(b"ayya".to_vec()), None, None, + grove_version, ) .unwrap() .expect("cannot insert element"); @@ -1342,6 +1455,7 @@ mod tests { Element::new_item(b"ayyb".to_vec()), None, None, + grove_version, ) .unwrap() .expect("cannot insert element"); @@ -1360,6 +1474,7 @@ mod tests { QueryOptions::default(), QueryKeyElementPairResultType, None, + grove_version, ) .unwrap() .expect("expected successful get_query"); @@ -1386,6 +1501,7 @@ mod tests { QueryOptions::default(), QueryKeyElementPairResultType, None, + grove_version, ) .unwrap() .expect("expected successful get_query"); @@ -1407,6 +1523,7 @@ mod tests { QueryOptions::default(), QueryKeyElementPairResultType, None, + grove_version, ) .unwrap() .expect("expected successful get_query"); @@ -1428,6 +1545,7 @@ mod tests { QueryOptions::default(), QueryKeyElementPairResultType, None, + grove_version, ) .unwrap() .expect("expected successful get_query"); @@ -1448,6 +1566,7 @@ mod tests { QueryOptions::default(), QueryKeyElementPairResultType, None, + grove_version, ) .unwrap() .expect("expected successful get_query"); @@ -1473,6 +1592,7 @@ mod tests { QueryOptions::default(), QueryKeyElementPairResultType, None, + grove_version, ) .unwrap() .expect("expected successful get_query"); @@ -1497,6 +1617,7 @@ mod tests { QueryOptions::default(), QueryKeyElementPairResultType, None, + grove_version, ) .unwrap() .expect("expected successful get_query"); @@ -1522,6 +1643,7 @@ mod tests { QueryOptions::default(), QueryKeyElementPairResultType, None, + grove_version, ) .unwrap() .expect("expected successful get_query"); @@ -1547,6 +1669,7 @@ mod tests { QueryOptions::default(), QueryKeyElementPairResultType, None, + grove_version, ) .unwrap() .expect("expected successful get_query"); @@ -1572,7 +1695,10 @@ impl ElementsIterator { ElementsIterator { raw_iter } } - pub fn next_element(&mut self) -> CostResult, Error> { + pub fn next_element( + &mut self, + grove_version: &GroveVersion, + ) -> CostResult, Error> { let mut cost = OperationCost::default(); Ok(if self.raw_iter.valid().unwrap_add_cost(&mut cost) { @@ -1582,7 +1708,7 @@ impl ElementsIterator { .unwrap_add_cost(&mut cost) .zip(self.raw_iter.value().unwrap_add_cost(&mut cost)) { - let element = cost_return_on_error_no_add!(&cost, raw_decode(value)); + let element = cost_return_on_error_no_add!(&cost, raw_decode(value, grove_version)); let key_vec = key.to_vec(); self.raw_iter.next().unwrap_add_cost(&mut cost); Some((key_vec, element)) diff --git a/grovedb/src/element/serialize.rs b/grovedb/src/element/serialize.rs index ab798054..395fea8d 100644 --- a/grovedb/src/element/serialize.rs +++ b/grovedb/src/element/serialize.rs @@ -1,35 +1,8 @@ -// 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. - //! Serialize //! Implements serialization functions in Element use bincode::config; +use grovedb_version::{check_grovedb_v0, error::GroveVersionError, version::GroveVersion}; #[cfg(any(feature = "full", feature = "verify"))] use crate::{Element, Error}; @@ -37,23 +10,34 @@ use crate::{Element, Error}; impl Element { #[cfg(feature = "full")] /// Serializes self. Returns vector of u8s. - pub fn serialize(&self) -> Result, Error> { - let config = bincode::config::standard() - .with_big_endian() - .with_no_limit(); + pub fn serialize(&self, grove_version: &GroveVersion) -> Result, Error> { + check_grovedb_v0!( + "Element::serialize", + grove_version.grovedb_versions.element.serialize + ); + let config = config::standard().with_big_endian().with_no_limit(); bincode::encode_to_vec(self, config) .map_err(|e| Error::CorruptedData(format!("unable to serialize element {}", e))) } #[cfg(feature = "full")] /// Serializes self. Returns usize. - pub fn serialized_size(&self) -> Result { - self.serialize().map(|serialized| serialized.len()) + pub fn serialized_size(&self, grove_version: &GroveVersion) -> Result { + check_grovedb_v0!( + "Element::serialized_size", + grove_version.grovedb_versions.element.serialized_size + ); + self.serialize(grove_version) + .map(|serialized| serialized.len()) } #[cfg(any(feature = "full", feature = "verify"))] /// Deserializes given bytes and sets as self - pub fn deserialize(bytes: &[u8]) -> Result { + pub fn deserialize(bytes: &[u8], grove_version: &GroveVersion) -> Result { + check_grovedb_v0!( + "Element::deserialize", + grove_version.grovedb_versions.element.deserialize + ); let config = config::standard().with_big_endian().with_no_limit(); Ok(bincode::decode_from_slice(bytes, config) .map_err(|e| Error::CorruptedData(format!("unable to deserialize element {}", e)))? @@ -71,32 +55,53 @@ mod tests { #[test] fn test_serialization() { + let grove_version = GroveVersion::latest(); let empty_tree = Element::empty_tree(); - let serialized = empty_tree.serialize().expect("expected to serialize"); + let serialized = empty_tree + .serialize(grove_version) + .expect("expected to serialize"); assert_eq!(serialized.len(), 3); - assert_eq!(serialized.len(), empty_tree.serialized_size().unwrap()); + assert_eq!( + serialized.len(), + empty_tree.serialized_size(grove_version).unwrap() + ); // The tree is fixed length 32 bytes, so it's enum 2 then 32 bytes of zeroes assert_eq!(hex::encode(serialized), "020000"); let empty_tree = Element::new_tree_with_flags(None, Some(vec![5])); - let serialized = empty_tree.serialize().expect("expected to serialize"); + let serialized = empty_tree + .serialize(grove_version) + .expect("expected to serialize"); assert_eq!(serialized.len(), 5); - assert_eq!(serialized.len(), empty_tree.serialized_size().unwrap()); + assert_eq!( + serialized.len(), + empty_tree.serialized_size(grove_version).unwrap() + ); assert_eq!(hex::encode(serialized), "0200010105"); let item = Element::new_item(hex::decode("abcdef").expect("expected to decode")); - let serialized = item.serialize().expect("expected to serialize"); + let serialized = item + .serialize(grove_version) + .expect("expected to serialize"); assert_eq!(serialized.len(), 6); - assert_eq!(serialized.len(), item.serialized_size().unwrap()); + assert_eq!( + serialized.len(), + item.serialized_size(grove_version).unwrap() + ); // The item is variable length 3 bytes, so it's enum 2 then 32 bytes of zeroes assert_eq!(hex::encode(serialized), "0003abcdef00"); assert_eq!(hex::encode(5.encode_var_vec()), "0a"); let item = Element::new_sum_item(5); - let serialized = item.serialize().expect("expected to serialize"); + let serialized = item + .serialize(grove_version) + .expect("expected to serialize"); assert_eq!(serialized.len(), 3); - assert_eq!(serialized.len(), item.serialized_size().unwrap()); + assert_eq!( + serialized.len(), + item.serialized_size(grove_version).unwrap() + ); // The item is variable length 3 bytes, so it's enum 2 then 32 bytes of zeroes assert_eq!(hex::encode(serialized), "030a00"); @@ -104,9 +109,14 @@ mod tests { hex::decode("abcdef").expect("expected to decode"), Some(vec![1]), ); - let serialized = item.serialize().expect("expected to serialize"); + let serialized = item + .serialize(grove_version) + .expect("expected to serialize"); assert_eq!(serialized.len(), 8); - assert_eq!(serialized.len(), item.serialized_size().unwrap()); + assert_eq!( + serialized.len(), + item.serialized_size(grove_version).unwrap() + ); assert_eq!(hex::encode(serialized), "0003abcdef010101"); let reference = Element::new_reference(ReferencePathType::AbsolutePathReference(vec![ @@ -114,9 +124,14 @@ mod tests { hex::decode("abcd").expect("expected to decode"), vec![5], ])); - let serialized = reference.serialize().expect("expected to serialize"); + let serialized = reference + .serialize(grove_version) + .expect("expected to serialize"); assert_eq!(serialized.len(), 12); - assert_eq!(serialized.len(), reference.serialized_size().unwrap()); + assert_eq!( + serialized.len(), + reference.serialized_size(grove_version).unwrap() + ); // The item is variable length 2 bytes, so it's enum 1 then 1 byte for length, // then 1 byte for 0, then 1 byte 02 for abcd, then 1 byte '1' for 05 assert_eq!(hex::encode(serialized), "010003010002abcd01050000"); @@ -129,9 +144,14 @@ mod tests { ]), Some(vec![1, 2, 3]), ); - let serialized = reference.serialize().expect("expected to serialize"); + let serialized = reference + .serialize(grove_version) + .expect("expected to serialize"); assert_eq!(serialized.len(), 16); - assert_eq!(serialized.len(), reference.serialized_size().unwrap()); + assert_eq!( + serialized.len(), + reference.serialized_size(grove_version).unwrap() + ); assert_eq!(hex::encode(serialized), "010003010002abcd0105000103010203"); } } diff --git a/grovedb/src/error.rs b/grovedb/src/error.rs index c430c5ae..0f6cd5d1 100644 --- a/grovedb/src/error.rs +++ b/grovedb/src/error.rs @@ -147,6 +147,11 @@ pub enum Error { #[error("merk error: {0}")] /// Merk error MerkError(grovedb_merk::error::Error), + + // Version errors + #[error(transparent)] + /// Version error + VersionError(grovedb_version::error::GroveVersionError), } impl From for Error { @@ -160,3 +165,9 @@ impl From for Error { Error::MerkError(value) } } + +impl From for Error { + fn from(value: grovedb_version::error::GroveVersionError) -> Self { + Error::VersionError(value) + } +} diff --git a/grovedb/src/estimated_costs/average_case_costs.rs b/grovedb/src/estimated_costs/average_case_costs.rs index 8d803daf..32d5a315 100644 --- a/grovedb/src/estimated_costs/average_case_costs.rs +++ b/grovedb/src/estimated_costs/average_case_costs.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. - //! Average case costs //! Implements average case cost functions in GroveDb @@ -44,6 +16,9 @@ use grovedb_merk::{ HASH_LENGTH, }; use grovedb_storage::{worst_case_costs::WorstKeyLength, Storage}; +use grovedb_version::{ + check_grovedb_v0, check_grovedb_v0_with_cost, error::GroveVersionError, version::GroveVersion, +}; use integer_encoding::VarInt; use crate::{ @@ -59,7 +34,17 @@ impl GroveDb { path: &KeyInfoPath, merk_should_be_empty: bool, is_sum_tree: bool, - ) { + grove_version: &GroveVersion, + ) -> Result<(), Error> { + check_grovedb_v0!( + "add_average_case_get_merk_at_path", + grove_version + .grovedb_versions + .operations + .average_case + .add_average_case_get_merk_at_path + ); + cost.seek_count += 1; // If the merk is not empty we load the tree if !merk_should_be_empty { @@ -76,6 +61,8 @@ impl GroveDb { } } *cost += S::get_storage_context_cost(path.as_vec()); + + Ok(()) } /// Add average case for insertion into merk @@ -84,7 +71,17 @@ impl GroveDb { estimated_layer_information: &EstimatedLayerInformation, _is_sum_tree: bool, propagate: bool, + grove_version: &GroveVersion, ) -> CostResult<(), Error> { + check_grovedb_v0_with_cost!( + "average_case_merk_replace_tree", + grove_version + .grovedb_versions + .operations + .average_case + .average_case_merk_replace_tree + ); + let mut cost = OperationCost::default(); let key_len = key.max_length() as u32; let flags_size = cost_return_on_error_no_add!( @@ -124,7 +121,17 @@ impl GroveDb { is_sum_tree: bool, in_tree_using_sums: bool, propagate_if_input: Option<&EstimatedLayerInformation>, + grove_version: &GroveVersion, ) -> CostResult<(), Error> { + check_grovedb_v0_with_cost!( + "average_case_merk_insert_tree", + grove_version + .grovedb_versions + .operations + .average_case + .average_case_merk_insert_tree + ); + let mut cost = OperationCost::default(); let key_len = key.max_length() as u32; let flags_len = flags.as_ref().map_or(0, |flags| { @@ -152,7 +159,17 @@ impl GroveDb { is_sum_tree: bool, estimated_layer_information: &EstimatedLayerInformation, propagate: bool, + grove_version: &GroveVersion, ) -> CostResult<(), Error> { + check_grovedb_v0_with_cost!( + "average_case_merk_delete_tree", + grove_version + .grovedb_versions + .operations + .average_case + .average_case_merk_delete_tree + ); + let mut cost = OperationCost::default(); let key_len = key.max_length() as u32; let flags_size = cost_return_on_error_no_add!( @@ -188,7 +205,17 @@ impl GroveDb { value: &Element, in_tree_using_sums: bool, propagate_for_level: Option<&EstimatedLayerInformation>, + grove_version: &GroveVersion, ) -> CostResult<(), Error> { + check_grovedb_v0_with_cost!( + "average_case_merk_insert_element", + grove_version + .grovedb_versions + .operations + .average_case + .average_case_merk_insert_element + ); + let mut cost = OperationCost::default(); let key_len = key.max_length() as u32; match value { @@ -208,7 +235,7 @@ impl GroveDb { _ => add_cost_case_merk_insert( &mut cost, key_len, - cost_return_on_error_no_add!(&cost, value.serialized_size()) as u32, + cost_return_on_error_no_add!(&cost, value.serialized_size(grove_version)) as u32, in_tree_using_sums, ), }; @@ -228,7 +255,17 @@ impl GroveDb { value: &Element, in_tree_using_sums: bool, propagate_for_level: Option<&EstimatedLayerInformation>, + grove_version: &GroveVersion, ) -> CostResult<(), Error> { + check_grovedb_v0_with_cost!( + "average_case_merk_replace_element", + grove_version + .grovedb_versions + .operations + .average_case + .average_case_merk_replace_element + ); + let mut cost = OperationCost::default(); let key_len = key.max_length() as u32; match value { @@ -259,7 +296,7 @@ impl GroveDb { let sum_item_cost_size = if value.is_sum_item() { SUM_ITEM_COST_SIZE } else { - cost_return_on_error_no_add!(&cost, value.serialized_size()) as u32 + cost_return_on_error_no_add!(&cost, value.serialized_size(grove_version)) as u32 }; let value_len = sum_item_cost_size + flags_len; add_cost_case_merk_replace_same_size( @@ -272,7 +309,7 @@ impl GroveDb { _ => add_cost_case_merk_replace_same_size( &mut cost, key_len, - cost_return_on_error_no_add!(&cost, value.serialized_size()) as u32, + cost_return_on_error_no_add!(&cost, value.serialized_size(grove_version)) as u32, in_tree_using_sums, ), }; @@ -293,7 +330,17 @@ impl GroveDb { change_in_bytes: i32, in_tree_using_sums: bool, propagate_for_level: Option<&EstimatedLayerInformation>, + grove_version: &GroveVersion, ) -> CostResult<(), Error> { + check_grovedb_v0_with_cost!( + "average_case_merk_patch_element", + grove_version + .grovedb_versions + .operations + .average_case + .average_case_merk_patch_element + ); + let mut cost = OperationCost::default(); let key_len = key.max_length() as u32; match value { @@ -304,7 +351,8 @@ impl GroveDb { }); // Items need to be always the same serialized size for this to work let item_cost_size = - cost_return_on_error_no_add!(&cost, value.serialized_size()) as u32; + cost_return_on_error_no_add!(&cost, value.serialized_size(grove_version)) + as u32; let value_len = item_cost_size + flags_len; add_cost_case_merk_patch( &mut cost, @@ -332,7 +380,17 @@ impl GroveDb { key: &KeyInfo, estimated_layer_information: &EstimatedLayerInformation, propagate: bool, + grove_version: &GroveVersion, ) -> CostResult<(), Error> { + check_grovedb_v0_with_cost!( + "average_case_merk_delete_element", + grove_version + .grovedb_versions + .operations + .average_case + .average_case_merk_delete_element + ); + let mut cost = OperationCost::default(); let key_len = key.max_length() as u32; let value_size = cost_return_on_error_no_add!( @@ -359,7 +417,17 @@ impl GroveDb { key: &KeyInfo, estimated_element_size: u32, in_parent_tree_using_sums: bool, - ) { + grove_version: &GroveVersion, + ) -> Result<(), Error> { + check_grovedb_v0!( + "add_average_case_has_raw_cost", + grove_version + .grovedb_versions + .operations + .average_case + .add_average_case_has_raw_cost + ); + let value_size = TreeNode::average_case_encoded_tree_size( key.max_length() as u32, estimated_element_size, @@ -368,6 +436,7 @@ impl GroveDb { cost.seek_count += 1; cost.storage_loaded_bytes += value_size; *cost += S::get_storage_context_cost(path.as_vec()); + Ok(()) } /// Adds the average case of checking to see if a tree exists @@ -378,7 +447,17 @@ impl GroveDb { estimated_flags_size: u32, is_sum_tree: bool, in_parent_tree_using_sums: bool, - ) { + grove_version: &GroveVersion, + ) -> Result<(), Error> { + check_grovedb_v0!( + "add_average_case_has_raw_tree_cost", + grove_version + .grovedb_versions + .operations + .average_case + .add_average_case_has_raw_tree_cost + ); + let estimated_element_size = if is_sum_tree { SUM_TREE_COST_SIZE + estimated_flags_size } else { @@ -390,7 +469,8 @@ impl GroveDb { key, estimated_element_size, in_parent_tree_using_sums, - ); + grove_version, + ) } /// Add average case to get raw cost into merk @@ -400,14 +480,25 @@ impl GroveDb { key: &KeyInfo, estimated_element_size: u32, in_parent_tree_using_sums: bool, - ) { + grove_version: &GroveVersion, + ) -> Result<(), Error> { + check_grovedb_v0!( + "add_average_case_get_raw_cost", + grove_version + .grovedb_versions + .operations + .average_case + .add_average_case_get_raw_cost + ); + cost.seek_count += 1; add_average_case_get_merk_node( cost, key.max_length() as u32, estimated_element_size, in_parent_tree_using_sums, - ); + ) + .map_err(Error::MerkError) } /// adds the average cost of getting a tree @@ -418,7 +509,17 @@ impl GroveDb { estimated_flags_size: u32, is_sum_tree: bool, in_parent_tree_using_sums: bool, - ) { + grove_version: &GroveVersion, + ) -> Result<(), Error> { + check_grovedb_v0!( + "add_average_case_get_raw_tree_cost", + grove_version + .grovedb_versions + .operations + .average_case + .add_average_case_get_raw_tree_cost + ); + let estimated_element_size = if is_sum_tree { SUM_TREE_COST_SIZE + estimated_flags_size } else { @@ -430,7 +531,8 @@ impl GroveDb { key.max_length() as u32, estimated_element_size, in_parent_tree_using_sums, - ); + ) + .map_err(Error::MerkError) } /// adds the average cost of getting an element knowing there can be @@ -442,7 +544,17 @@ impl GroveDb { in_parent_tree_using_sums: bool, estimated_element_size: u32, estimated_references_sizes: Vec, - ) { + grove_version: &GroveVersion, + ) -> Result<(), Error> { + check_grovedb_v0!( + "add_average_case_get_cost", + grove_version + .grovedb_versions + .operations + .average_case + .add_average_case_get_cost + ); + // todo: verify let value_size: u32 = TreeNode::average_case_encoded_tree_size( key.max_length() as u32, @@ -452,6 +564,7 @@ impl GroveDb { cost.seek_count += 1 + estimated_references_sizes.len() as u16; cost.storage_loaded_bytes += value_size + estimated_references_sizes.iter().sum::(); *cost += S::get_storage_context_cost(path.as_vec()); + Ok(()) } } @@ -467,6 +580,7 @@ mod test { use grovedb_storage::{ rocksdb_storage::RocksDbStorage, worst_case_costs::WorstKeyLength, Storage, StorageBatch, }; + use grovedb_version::version::GroveVersion; use tempfile::TempDir; use crate::{ @@ -477,6 +591,7 @@ mod test { #[test] fn test_get_merk_node_average_case() { + let grove_version = GroveVersion::latest(); // Open a merk and insert 10 elements. let tmp_dir = TempDir::new().expect("cannot open tempdir"); let storage = RocksDbStorage::default_rocksdb_with_path(tmp_dir.path()) @@ -488,12 +603,13 @@ mod test { .get_storage_context(EMPTY_PATH, Some(&batch)) .unwrap(), false, - None::<&fn(&[u8]) -> Option>, + None::<&fn(&[u8], &GroveVersion) -> Option>, + grove_version, ) .unwrap() .expect("cannot open merk"); let merk_batch = make_batch_seq(1..10); - merk.apply::<_, Vec<_>>(merk_batch.as_slice(), &[], None) + merk.apply::<_, Vec<_>>(merk_batch.as_slice(), &[], None, grove_version) .unwrap() .unwrap(); @@ -507,7 +623,8 @@ mod test { let merk = Merk::open_base( storage.get_storage_context(EMPTY_PATH, None).unwrap(), false, - None::<&fn(&[u8]) -> Option>, + None::<&fn(&[u8], &GroveVersion) -> Option>, + grove_version, ) .unwrap() .expect("cannot open merk"); @@ -520,7 +637,8 @@ mod test { let node_result = merk.get( &8_u64.to_be_bytes(), true, - None::<&fn(&[u8]) -> Option>, + None::<&fn(&[u8], &GroveVersion) -> Option>, + grove_version, ); // By tweaking the max element size, we can adapt the average case function to @@ -528,33 +646,63 @@ mod test { // (this will be the max_element_size) let mut cost = OperationCost::default(); let key = KnownKey(8_u64.to_be_bytes().to_vec()); - add_average_case_get_merk_node(&mut cost, key.max_length() as u32, 60, false); + add_average_case_get_merk_node(&mut cost, key.max_length() as u32, 60, false) + .expect("expected to add cost"); assert_eq!(cost, node_result.cost); } #[test] fn test_has_raw_average_case() { + let grove_version = GroveVersion::latest(); let tmp_dir = TempDir::new().unwrap(); let db = GroveDb::open(tmp_dir.path()).unwrap(); // insert empty tree to start - db.insert(EMPTY_PATH, TEST_LEAF, Element::empty_tree(), None, None) - .unwrap() - .expect("successful root tree leaf insert"); + db.insert( + EMPTY_PATH, + TEST_LEAF, + Element::empty_tree(), + None, + None, + grove_version, + ) + .unwrap() + .expect("successful root tree leaf insert"); // In this tree, we insert 3 items with keys [1, 2, 3] // after tree rotation, 2 will be at the top hence would have both left and // right links this will serve as our average case candidate. let elem = Element::new_item(b"value".to_vec()); - db.insert([TEST_LEAF].as_ref(), &[1], elem.clone(), None, None) - .unwrap() - .expect("expected insert"); - db.insert([TEST_LEAF].as_ref(), &[2], elem.clone(), None, None) - .unwrap() - .expect("expected insert"); - db.insert([TEST_LEAF].as_ref(), &[3], elem.clone(), None, None) - .unwrap() - .expect("expected insert"); + db.insert( + [TEST_LEAF].as_ref(), + &[1], + elem.clone(), + None, + None, + grove_version, + ) + .unwrap() + .expect("expected insert"); + db.insert( + [TEST_LEAF].as_ref(), + &[2], + elem.clone(), + None, + None, + grove_version, + ) + .unwrap() + .expect("expected insert"); + db.insert( + [TEST_LEAF].as_ref(), + &[3], + elem.clone(), + None, + None, + grove_version, + ) + .unwrap() + .expect("expected insert"); let path = KeyInfoPath::from_vec(vec![KnownKey(TEST_LEAF.to_vec())]); let key = KnownKey(vec![1]); @@ -563,11 +711,13 @@ mod test { &mut average_case_has_raw_cost, &path, &key, - elem.serialized_size().expect("expected size") as u32, + elem.serialized_size(grove_version).expect("expected size") as u32, false, - ); + GroveVersion::latest(), + ) + .expect("expected to add cost"); - let actual_cost = db.has_raw([TEST_LEAF].as_ref(), &[2], None); + let actual_cost = db.has_raw([TEST_LEAF].as_ref(), &[2], None, GroveVersion::latest()); assert_eq!(average_case_has_raw_cost, actual_cost.cost); } diff --git a/grovedb/src/estimated_costs/worst_case_costs.rs b/grovedb/src/estimated_costs/worst_case_costs.rs index 106c2bb6..2daf18b6 100644 --- a/grovedb/src/estimated_costs/worst_case_costs.rs +++ b/grovedb/src/estimated_costs/worst_case_costs.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. - //! Worst case costs //! Implements worst case cost functions in GroveDb @@ -46,6 +18,9 @@ use grovedb_merk::{ HASH_LENGTH, }; use grovedb_storage::{worst_case_costs::WorstKeyLength, Storage}; +use grovedb_version::{ + check_grovedb_v0, check_grovedb_v0_with_cost, error::GroveVersionError, version::GroveVersion, +}; use integer_encoding::VarInt; use crate::{ @@ -62,7 +37,17 @@ impl GroveDb { cost: &mut OperationCost, path: &KeyInfoPath, is_sum_tree: bool, - ) { + grove_version: &GroveVersion, + ) -> Result<(), Error> { + check_grovedb_v0!( + "add_worst_case_get_merk_at_path", + grove_version + .grovedb_versions + .operations + .worst_case + .add_worst_case_get_merk_at_path + ); + cost.seek_count += 2; match path.last() { None => {} @@ -75,6 +60,7 @@ impl GroveDb { } } *cost += S::get_storage_context_cost(path.as_vec()); + Ok(()) } /// Add worst case for insertion into merk @@ -84,7 +70,17 @@ impl GroveDb { is_in_parent_sum_tree: bool, worst_case_layer_information: &WorstCaseLayerInformation, propagate: bool, + grove_version: &GroveVersion, ) -> CostResult<(), Error> { + check_grovedb_v0_with_cost!( + "worst_case_merk_replace_tree", + grove_version + .grovedb_versions + .operations + .worst_case + .worst_case_merk_replace_tree + ); + let mut cost = OperationCost::default(); let key_len = key.max_length() as u32; let tree_cost = if is_sum_tree { @@ -115,7 +111,17 @@ impl GroveDb { is_sum_tree: bool, is_in_parent_sum_tree: bool, propagate_if_input: Option<&WorstCaseLayerInformation>, + grove_version: &GroveVersion, ) -> CostResult<(), Error> { + check_grovedb_v0_with_cost!( + "worst_case_merk_insert_tree", + grove_version + .grovedb_versions + .operations + .worst_case + .worst_case_merk_insert_tree + ); + let mut cost = OperationCost::default(); let key_len = key.max_length() as u32; let flags_len = flags.as_ref().map_or(0, |flags| { @@ -143,7 +149,17 @@ impl GroveDb { is_sum_tree: bool, worst_case_layer_information: &WorstCaseLayerInformation, propagate: bool, + grove_version: &GroveVersion, ) -> CostResult<(), Error> { + check_grovedb_v0_with_cost!( + "worst_case_merk_delete_tree", + grove_version + .grovedb_versions + .operations + .worst_case + .worst_case_merk_delete_tree + ); + let mut cost = OperationCost::default(); let key_len = key.max_length() as u32; let tree_cost = if is_sum_tree { @@ -170,7 +186,17 @@ impl GroveDb { value: &Element, in_parent_tree_using_sums: bool, propagate_for_level: Option<&WorstCaseLayerInformation>, + grove_version: &GroveVersion, ) -> CostResult<(), Error> { + check_grovedb_v0_with_cost!( + "worst_case_merk_insert_element", + grove_version + .grovedb_versions + .operations + .worst_case + .worst_case_merk_insert_element + ); + let mut cost = OperationCost::default(); let key_len = key.max_length() as u32; match value { @@ -195,7 +221,7 @@ impl GroveDb { _ => add_cost_case_merk_insert( &mut cost, key_len, - cost_return_on_error_no_add!(&cost, value.serialized_size()) as u32, + cost_return_on_error_no_add!(&cost, value.serialized_size(grove_version)) as u32, in_parent_tree_using_sums, ), }; @@ -215,7 +241,17 @@ impl GroveDb { value: &Element, in_parent_tree_using_sums: bool, propagate_for_level: Option<&WorstCaseLayerInformation>, + grove_version: &GroveVersion, ) -> CostResult<(), Error> { + check_grovedb_v0_with_cost!( + "worst_case_merk_replace_element", + grove_version + .grovedb_versions + .operations + .worst_case + .worst_case_merk_replace_element + ); + let mut cost = OperationCost::default(); let key_len = key.max_length() as u32; match value { @@ -253,7 +289,7 @@ impl GroveDb { _ => add_cost_case_merk_replace( &mut cost, key_len, - cost_return_on_error_no_add!(&cost, value.serialized_size()) as u32, + cost_return_on_error_no_add!(&cost, value.serialized_size(grove_version)) as u32, in_parent_tree_using_sums, ), }; @@ -274,7 +310,17 @@ impl GroveDb { change_in_bytes: i32, in_tree_using_sums: bool, propagate_for_level: Option<&WorstCaseLayerInformation>, + grove_version: &GroveVersion, ) -> CostResult<(), Error> { + check_grovedb_v0_with_cost!( + "worst_case_merk_patch_element", + grove_version + .grovedb_versions + .operations + .worst_case + .worst_case_merk_patch_element + ); + let mut cost = OperationCost::default(); let key_len = key.max_length() as u32; match value { @@ -285,7 +331,8 @@ impl GroveDb { }); // Items need to be always the same serialized size for this to work let sum_item_cost_size = - cost_return_on_error_no_add!(&cost, value.serialized_size()) as u32; + cost_return_on_error_no_add!(&cost, value.serialized_size(grove_version)) + as u32; let value_len = sum_item_cost_size + flags_len; add_cost_case_merk_patch( &mut cost, @@ -313,7 +360,17 @@ impl GroveDb { key: &KeyInfo, worst_case_layer_information: &WorstCaseLayerInformation, propagate: bool, + grove_version: &GroveVersion, ) -> CostResult<(), Error> { + check_grovedb_v0_with_cost!( + "worst_case_merk_delete_element", + grove_version + .grovedb_versions + .operations + .worst_case + .worst_case_merk_delete_element + ); + let mut cost = OperationCost::default(); let key_len = key.max_length() as u32; add_worst_case_merk_delete(&mut cost, key_len, MERK_BIGGEST_VALUE_SIZE); @@ -333,7 +390,17 @@ impl GroveDb { key: &KeyInfo, max_element_size: u32, in_parent_tree_using_sums: bool, - ) { + grove_version: &GroveVersion, + ) -> Result<(), Error> { + check_grovedb_v0!( + "add_worst_case_has_raw_cost", + grove_version + .grovedb_versions + .operations + .worst_case + .add_worst_case_has_raw_cost + ); + let value_size = TreeNode::worst_case_encoded_tree_size( key.max_length() as u32, max_element_size, @@ -342,6 +409,7 @@ impl GroveDb { cost.seek_count += 1; cost.storage_loaded_bytes += value_size; *cost += S::get_storage_context_cost(path.as_vec()); + Ok(()) } /// Add worst case cost for get raw tree into merk @@ -351,7 +419,17 @@ impl GroveDb { key: &KeyInfo, is_sum_tree: bool, in_parent_tree_using_sums: bool, - ) { + grove_version: &GroveVersion, + ) -> Result<(), Error> { + check_grovedb_v0!( + "add_worst_case_get_raw_tree_cost", + grove_version + .grovedb_versions + .operations + .worst_case + .add_worst_case_get_raw_tree_cost + ); + cost.seek_count += 1; let tree_cost_size = if is_sum_tree { SUM_TREE_COST_SIZE @@ -363,7 +441,8 @@ impl GroveDb { key.max_length() as u32, tree_cost_size, in_parent_tree_using_sums, - ); + ) + .map_err(Error::MerkError) } /// Add worst case cost for get raw into merk @@ -373,14 +452,25 @@ impl GroveDb { key: &KeyInfo, max_element_size: u32, in_parent_tree_using_sums: bool, - ) { + grove_version: &GroveVersion, + ) -> Result<(), Error> { + check_grovedb_v0!( + "add_worst_case_get_raw_cost", + grove_version + .grovedb_versions + .operations + .worst_case + .add_worst_case_get_raw_cost + ); + cost.seek_count += 1; add_worst_case_get_merk_node( cost, key.max_length() as u32, max_element_size, in_parent_tree_using_sums, - ); + ) + .map_err(Error::MerkError) } /// Add worst case cost for get into merk @@ -391,7 +481,17 @@ impl GroveDb { max_element_size: u32, in_parent_tree_using_sums: bool, max_references_sizes: Vec, - ) { + grove_version: &GroveVersion, + ) -> Result<(), Error> { + check_grovedb_v0!( + "add_worst_case_get_cost", + grove_version + .grovedb_versions + .operations + .worst_case + .add_worst_case_get_cost + ); + // todo: verify let value_size: u32 = TreeNode::worst_case_encoded_tree_size( key.max_length() as u32, @@ -401,6 +501,7 @@ impl GroveDb { cost.seek_count += 1 + max_references_sizes.len() as u16; cost.storage_loaded_bytes += value_size + max_references_sizes.iter().sum::(); *cost += S::get_storage_context_cost(path.as_vec()); + Ok(()) } } @@ -419,6 +520,7 @@ mod test { worst_case_costs::WorstKeyLength, Storage, StorageBatch, }; + use grovedb_version::version::GroveVersion; use tempfile::TempDir; use crate::{ @@ -429,13 +531,14 @@ mod test { #[test] fn test_get_merk_node_worst_case() { + let grove_version = GroveVersion::latest(); // Open a merk and insert 10 elements. let storage = TempStorage::new(); let batch = StorageBatch::new(); - let mut merk = empty_path_merk(&*storage, &batch); + let mut merk = empty_path_merk(&*storage, &batch, grove_version); let merk_batch = make_batch_seq(1..10); - merk.apply::<_, Vec<_>>(merk_batch.as_slice(), &[], None) + merk.apply::<_, Vec<_>>(merk_batch.as_slice(), &[], None, grove_version) .unwrap() .unwrap(); @@ -446,7 +549,7 @@ mod test { .unwrap(); // Reopen merk: this time, only root node is loaded to memory - let merk = empty_path_merk_read_only(&*storage); + let merk = empty_path_merk_read_only(&*storage, grove_version); // To simulate worst case, we need to pick a node that: // 1. Is not in memory @@ -456,7 +559,8 @@ mod test { let node_result = merk.get( &8_u64.to_be_bytes(), true, - None::<&fn(&[u8]) -> Option>, + None::<&fn(&[u8], &GroveVersion) -> Option>, + grove_version, ); // By tweaking the max element size, we can adapt the worst case function to @@ -464,33 +568,63 @@ mod test { // (this will be the max_element_size) let mut cost = OperationCost::default(); let key = KnownKey(8_u64.to_be_bytes().to_vec()); - add_worst_case_get_merk_node(&mut cost, key.max_length() as u32, 60, false); + add_worst_case_get_merk_node(&mut cost, key.max_length() as u32, 60, false) + .expect("no issue with version"); assert_eq!(cost, node_result.cost); } #[test] fn test_has_raw_worst_case() { + let grove_version = GroveVersion::latest(); let tmp_dir = TempDir::new().unwrap(); let db = GroveDb::open(tmp_dir.path()).unwrap(); // insert empty tree to start - db.insert(EMPTY_PATH, TEST_LEAF, Element::empty_tree(), None, None) - .unwrap() - .expect("successful root tree leaf insert"); + db.insert( + EMPTY_PATH, + TEST_LEAF, + Element::empty_tree(), + None, + None, + grove_version, + ) + .unwrap() + .expect("successful root tree leaf insert"); // In this tree, we insert 3 items with keys [1, 2, 3] // after tree rotation, 2 will be at the top hence would have both left and // right links this will serve as our worst case candidate. let elem = Element::new_item(b"value".to_vec()); - db.insert([TEST_LEAF].as_ref(), &[1], elem.clone(), None, None) - .unwrap() - .expect("expected insert"); - db.insert([TEST_LEAF].as_ref(), &[2], elem.clone(), None, None) - .unwrap() - .expect("expected insert"); - db.insert([TEST_LEAF].as_ref(), &[3], elem.clone(), None, None) - .unwrap() - .expect("expected insert"); + db.insert( + [TEST_LEAF].as_ref(), + &[1], + elem.clone(), + None, + None, + grove_version, + ) + .unwrap() + .expect("expected insert"); + db.insert( + [TEST_LEAF].as_ref(), + &[2], + elem.clone(), + None, + None, + grove_version, + ) + .unwrap() + .expect("expected insert"); + db.insert( + [TEST_LEAF].as_ref(), + &[3], + elem.clone(), + None, + None, + grove_version, + ) + .unwrap() + .expect("expected insert"); let path = KeyInfoPath::from_vec(vec![KnownKey(TEST_LEAF.to_vec())]); let key = KnownKey(vec![1]); @@ -499,11 +633,13 @@ mod test { &mut worst_case_has_raw_cost, &path, &key, - elem.serialized_size().expect("expected size") as u32, + elem.serialized_size(grove_version).expect("expected size") as u32, false, - ); + GroveVersion::latest(), + ) + .expect("expected to add cost"); - let actual_cost = db.has_raw([TEST_LEAF].as_ref(), &[2], None); + let actual_cost = db.has_raw([TEST_LEAF].as_ref(), &[2], None, GroveVersion::latest()); assert_eq!(worst_case_has_raw_cost, actual_cost.cost); } diff --git a/grovedb/src/lib.rs b/grovedb/src/lib.rs index 206ace71..012785ca 100644 --- a/grovedb/src/lib.rs +++ b/grovedb/src/lib.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. - //! GroveDB is a database that enables cryptographic proofs for complex queries. //! //! # Examples @@ -48,8 +20,11 @@ //! Insert, Update, Delete and Prove elements. //! ``` //! use grovedb::{Element, GroveDb}; +//! use grovedb_version::version::GroveVersion; //! use tempfile::TempDir; //! +//! let grove_version = GroveVersion::latest(); +//! //! // Specify the path where you want to set up the GroveDB instance //! let tmp_dir = TempDir::new().unwrap(); //! let path = tmp_dir.path(); @@ -60,9 +35,16 @@ //! let root_path: &[&[u8]] = &[]; //! //! // Insert new tree to root -//! db.insert(root_path, b"tree1", Element::empty_tree(), None, None) -//! .unwrap() -//! .expect("successful tree insert"); +//! db.insert( +//! root_path, +//! b"tree1", +//! Element::empty_tree(), +//! None, +//! None, +//! grove_version, +//! ) +//! .unwrap() +//! .expect("successful tree insert"); //! //! // Insert key-value 1 into tree1 //! // key - hello, value - world @@ -72,6 +54,7 @@ //! Element::new_item(b"world".to_vec()), //! None, //! None, +//! grove_version, //! ) //! .unwrap() //! .expect("successful key1 insert"); @@ -84,19 +67,20 @@ //! Element::new_item(b"rocks".to_vec()), //! None, //! None, +//! grove_version, //! ) //! .unwrap() //! .expect("successful key2 insert"); //! //! // Retrieve inserted elements //! let elem = db -//! .get(&[b"tree1"], b"hello", None) +//! .get(&[b"tree1"], b"hello", None, grove_version) //! .unwrap() //! .expect("successful get"); //! assert_eq!(elem, Element::new_item(b"world".to_vec())); //! //! let elem = db -//! .get(&[b"tree1"], b"grovedb", None) +//! .get(&[b"tree1"], b"grovedb", None, grove_version) //! .unwrap() //! .expect("successful get"); //! assert_eq!(elem, Element::new_item(b"rocks".to_vec())); @@ -109,27 +93,28 @@ //! Element::new_item(b"WORLD".to_vec()), //! None, //! None, +//! grove_version, //! ) //! .unwrap() //! .expect("successful update"); //! //! // Retrieve updated element //! let elem = db -//! .get(&[b"tree1"], b"hello", None) +//! .get(&[b"tree1"], b"hello", None, grove_version) //! .unwrap() //! .expect("successful get"); //! assert_eq!(elem, Element::new_item(b"WORLD".to_vec())); //! //! // Deletion -//! db.delete(&[b"tree1"], b"hello", None, None) +//! db.delete(&[b"tree1"], b"hello", None, None, grove_version) //! .unwrap() //! .expect("successful delete"); -//! let elem_result = db.get(&[b"tree1"], b"hello", None).unwrap(); +//! let elem_result = db.get(&[b"tree1"], b"hello", None, grove_version).unwrap(); //! assert_eq!(elem_result.is_err(), true); //! //! // State Root //! // Get the GroveDB root hash -//! let root_hash = db.root_hash(None).unwrap().unwrap(); +//! let root_hash = db.root_hash(None, grove_version).unwrap().unwrap(); //! assert_eq!( //! hex::encode(root_hash), //! "3884be3d197ac49981e54b21ea423351fc4ccdb770aaf7cf40f5e65dc3e2e1aa" @@ -214,6 +199,7 @@ use grovedb_storage::{ }; #[cfg(feature = "full")] use grovedb_storage::{Storage, StorageContext}; +use grovedb_version::version::GroveVersion; #[cfg(feature = "full")] use grovedb_visualize::DebugByteVectors; #[cfg(any(feature = "full", feature = "verify"))] @@ -279,6 +265,7 @@ impl GroveDb { path: SubtreePath<'b, B>, tx: &'db Transaction, batch: Option<&'db StorageBatch>, + grove_version: &GroveVersion, ) -> CostResult>, Error> where B: AsRef<[u8]> + 'b, @@ -296,14 +283,16 @@ impl GroveDb { .unwrap_add_cost(&mut cost); let element = cost_return_on_error!( &mut cost, - Element::get_from_storage(&parent_storage, parent_key).map_err(|e| { - Error::InvalidParentLayerPath(format!( - "could not get key {} for parent {:?} of subtree: {}", - hex::encode(parent_key), - DebugByteVectors(parent_path.to_vec()), - e - )) - }) + Element::get_from_storage(&parent_storage, parent_key, grove_version).map_err( + |e| { + Error::InvalidParentLayerPath(format!( + "could not get key {} for parent {:?} of subtree: {}", + hex::encode(parent_key), + DebugByteVectors(parent_path.to_vec()), + e + )) + } + ) ); let is_sum_tree = element.is_sum_tree(); if let Element::Tree(root_key, _) | Element::SumTree(root_key, ..) = element { @@ -312,6 +301,7 @@ impl GroveDb { root_key, is_sum_tree, Some(&Element::value_defined_cost_for_serialized_value), + grove_version, ) .map_err(|_| { Error::CorruptedData("cannot open a subtree with given root key".to_owned()) @@ -328,6 +318,7 @@ impl GroveDb { storage, false, Some(&Element::value_defined_cost_for_serialized_value), + grove_version, ) .map_err(|_| Error::CorruptedData("cannot open a the root subtree".to_owned())) .add_cost(cost) @@ -340,6 +331,7 @@ impl GroveDb { &'db self, path: SubtreePath<'b, B>, tx: &'tx Transaction<'db>, + grove_version: &GroveVersion, ) -> Result>, Error> where B: AsRef<[u8]> + 'b, @@ -355,7 +347,7 @@ impl GroveDb { .db .get_immediate_storage_context(parent_path.clone(), tx) .unwrap_add_cost(&mut cost); - let element = Element::get_from_storage(&parent_storage, parent_key) + let element = Element::get_from_storage(&parent_storage, parent_key, grove_version) .map_err(|e| { Error::InvalidParentLayerPath(format!( "could not get key {} for parent {:?} of subtree: {}", @@ -372,6 +364,7 @@ impl GroveDb { root_key, is_sum_tree, Some(&Element::value_defined_cost_for_serialized_value), + grove_version, ) .map_err(|_| { Error::CorruptedData("cannot open a subtree with given root key".to_owned()) @@ -386,7 +379,8 @@ impl GroveDb { Merk::open_base( storage, false, - None::<&fn(&[u8]) -> Option>, + None::<&fn(&[u8], &GroveVersion) -> Option>, + grove_version, ) .map_err(|_| Error::CorruptedData("cannot open a the root subtree".to_owned())) .unwrap() @@ -398,6 +392,7 @@ impl GroveDb { &'db self, path: SubtreePath<'b, B>, batch: Option<&'db StorageBatch>, + grove_version: &GroveVersion, ) -> CostResult, Error> where B: AsRef<[u8]> + 'b, @@ -416,14 +411,16 @@ impl GroveDb { .unwrap_add_cost(&mut cost); let element = cost_return_on_error!( &mut cost, - Element::get_from_storage(&parent_storage, parent_key).map_err(|e| { - Error::InvalidParentLayerPath(format!( - "could not get key {} for parent {:?} of subtree: {}", - hex::encode(parent_key), - DebugByteVectors(parent_path.to_vec()), - e - )) - }) + Element::get_from_storage(&parent_storage, parent_key, grove_version).map_err( + |e| { + Error::InvalidParentLayerPath(format!( + "could not get key {} for parent {:?} of subtree: {}", + hex::encode(parent_key), + DebugByteVectors(parent_path.to_vec()), + e + )) + } + ) ); let is_sum_tree = element.is_sum_tree(); if let Element::Tree(root_key, _) | Element::SumTree(root_key, ..) = element { @@ -432,6 +429,7 @@ impl GroveDb { root_key, is_sum_tree, Some(&Element::value_defined_cost_for_serialized_value), + grove_version, ) .map_err(|_| { Error::CorruptedData("cannot open a subtree with given root key".to_owned()) @@ -448,6 +446,7 @@ impl GroveDb { storage, false, Some(&Element::value_defined_cost_for_serialized_value), + grove_version, ) .map_err(|_| Error::CorruptedData("cannot open a the root subtree".to_owned())) .add_cost(cost) @@ -461,28 +460,52 @@ impl GroveDb { /// Returns root key of GroveDb. /// Will be `None` if GroveDb is empty. - pub fn root_key(&self, transaction: TransactionArg) -> CostResult, Error> { + pub fn root_key( + &self, + transaction: TransactionArg, + grove_version: &GroveVersion, + ) -> CostResult, Error> { let mut cost = OperationCost { ..Default::default() }; - root_merk_optional_tx!(&mut cost, self.db, None, transaction, subtree, { - let root_key = subtree.root_key().unwrap(); - Ok(root_key).wrap_with_cost(cost) - }) + root_merk_optional_tx!( + &mut cost, + self.db, + None, + transaction, + subtree, + grove_version, + { + let root_key = subtree.root_key().unwrap(); + Ok(root_key).wrap_with_cost(cost) + } + ) } /// Returns root hash of GroveDb. /// Will be `None` if GroveDb is empty. - pub fn root_hash(&self, transaction: TransactionArg) -> CostResult { + pub fn root_hash( + &self, + transaction: TransactionArg, + grove_version: &GroveVersion, + ) -> CostResult { let mut cost = OperationCost { ..Default::default() }; - root_merk_optional_tx!(&mut cost, self.db, None, transaction, subtree, { - let root_hash = subtree.root_hash().unwrap_add_cost(&mut cost); - Ok(root_hash).wrap_with_cost(cost) - }) + root_merk_optional_tx!( + &mut cost, + self.db, + None, + transaction, + subtree, + grove_version, + { + let root_hash = subtree.root_hash().unwrap_add_cost(&mut cost); + Ok(root_hash).wrap_with_cost(cost) + } + ) } /// Method to propagate updated subtree key changes one level up inside a @@ -493,6 +516,7 @@ impl GroveDb { mut merk_cache: HashMap, Merk>, path: &SubtreePath<'b, B>, transaction: &Transaction, + grove_version: &GroveVersion, ) -> CostResult<(), Error> { let mut cost = OperationCost::default(); @@ -512,7 +536,8 @@ impl GroveDb { storage_batch, parent_path.clone(), transaction, - false + false, + grove_version, ) ); let (root_hash, root_key, sum) = cost_return_on_error!( @@ -526,7 +551,8 @@ impl GroveDb { parent_key, root_key, root_hash, - sum + sum, + grove_version, ) ); child_tree = parent_tree; @@ -543,6 +569,7 @@ impl GroveDb { path: SubtreePath<'b, B>, transaction: &Transaction, batch: &StorageBatch, + grove_version: &GroveVersion, ) -> CostResult<(), Error> { let mut cost = OperationCost::default(); @@ -560,7 +587,12 @@ impl GroveDb { while let Some((parent_path, parent_key)) = current_path.derive_parent() { let mut parent_tree: Merk = cost_return_on_error!( &mut cost, - self.open_transactional_merk_at_path(parent_path.clone(), transaction, Some(batch)) + self.open_transactional_merk_at_path( + parent_path.clone(), + transaction, + Some(batch), + grove_version + ) ); let (root_hash, root_key, sum) = cost_return_on_error!( &mut cost, @@ -573,7 +605,8 @@ impl GroveDb { parent_key, root_key, root_hash, - sum + sum, + grove_version, ) ); child_tree = parent_tree; @@ -588,6 +621,7 @@ impl GroveDb { mut merk_cache: HashMap, Merk>, path: SubtreePath<'b, B>, batch: &StorageBatch, + grove_version: &GroveVersion, ) -> CostResult<(), Error> { let mut cost = OperationCost::default(); @@ -605,7 +639,11 @@ impl GroveDb { while let Some((parent_path, parent_key)) = current_path.derive_parent() { let mut parent_tree: Merk = cost_return_on_error!( &mut cost, - self.open_non_transactional_merk_at_path(parent_path.clone(), Some(batch)) + self.open_non_transactional_merk_at_path( + parent_path.clone(), + Some(batch), + grove_version + ) ); let (root_hash, root_key, sum) = cost_return_on_error!( &mut cost, @@ -618,7 +656,8 @@ impl GroveDb { parent_key, root_key, root_hash, - sum + sum, + grove_version, ) ); child_tree = parent_tree; @@ -634,20 +673,27 @@ impl GroveDb { maybe_root_key: Option>, root_tree_hash: Hash, sum: Option, + grove_version: &GroveVersion, ) -> CostResult<(), Error> { let key_ref = key.as_ref(); - Self::get_element_from_subtree(parent_tree, key_ref).flat_map_ok(|element| { + Self::get_element_from_subtree(parent_tree, key_ref, grove_version).flat_map_ok(|element| { if let Element::Tree(_, flag) = element { let tree = Element::new_tree_with_flags(maybe_root_key, flag); - tree.insert_subtree(parent_tree, key_ref, root_tree_hash, None) + tree.insert_subtree(parent_tree, key_ref, root_tree_hash, None, grove_version) } else if let Element::SumTree(.., flag) = element { let tree = Element::new_sum_tree_with_flags_and_sum_value( maybe_root_key, sum.unwrap_or_default(), flag, ); - tree.insert_subtree(parent_tree, key.as_ref(), root_tree_hash, None) + tree.insert_subtree( + parent_tree, + key.as_ref(), + root_tree_hash, + None, + grove_version, + ) } else { Err(Error::InvalidPath( "can only propagate on tree items".to_owned(), @@ -670,60 +716,67 @@ impl GroveDb { root_tree_hash: Hash, sum: Option, batch_operations: &mut Vec>, + grove_version: &GroveVersion, ) -> CostResult<(), Error> { let mut cost = OperationCost::default(); - Self::get_element_from_subtree(parent_tree, key.as_ref()).flat_map_ok(|element| { - if let Element::Tree(_, flag) = element { - let tree = Element::new_tree_with_flags(maybe_root_key, flag); - let merk_feature_type = cost_return_on_error!( - &mut cost, - tree.get_feature_type(parent_tree.is_sum_tree) - .wrap_with_cost(OperationCost::default()) - ); - tree.insert_subtree_into_batch_operations( - key, - root_tree_hash, - true, - batch_operations, - merk_feature_type, - ) - } else if let Element::SumTree(.., flag) = element { - let tree = Element::new_sum_tree_with_flags_and_sum_value( - maybe_root_key, - sum.unwrap_or_default(), - flag, - ); - let merk_feature_type = cost_return_on_error!( - &mut cost, - tree.get_feature_type(parent_tree.is_sum_tree) - .wrap_with_cost(OperationCost::default()) - ); - tree.insert_subtree_into_batch_operations( - key, - root_tree_hash, - true, - batch_operations, - merk_feature_type, - ) - } else { - Err(Error::InvalidPath( - "can only propagate on tree items".to_owned(), - )) - .wrap_with_cost(Default::default()) - } - }) + Self::get_element_from_subtree(parent_tree, key.as_ref(), grove_version).flat_map_ok( + |element| { + if let Element::Tree(_, flag) = element { + let tree = Element::new_tree_with_flags(maybe_root_key, flag); + let merk_feature_type = cost_return_on_error!( + &mut cost, + tree.get_feature_type(parent_tree.is_sum_tree) + .wrap_with_cost(OperationCost::default()) + ); + tree.insert_subtree_into_batch_operations( + key, + root_tree_hash, + true, + batch_operations, + merk_feature_type, + grove_version, + ) + } else if let Element::SumTree(.., flag) = element { + let tree = Element::new_sum_tree_with_flags_and_sum_value( + maybe_root_key, + sum.unwrap_or_default(), + flag, + ); + let merk_feature_type = cost_return_on_error!( + &mut cost, + tree.get_feature_type(parent_tree.is_sum_tree) + .wrap_with_cost(OperationCost::default()) + ); + tree.insert_subtree_into_batch_operations( + key, + root_tree_hash, + true, + batch_operations, + merk_feature_type, + grove_version, + ) + } else { + Err(Error::InvalidPath( + "can only propagate on tree items".to_owned(), + )) + .wrap_with_cost(Default::default()) + } + }, + ) } /// Get element from subtree. Return CostResult. fn get_element_from_subtree<'db, K: AsRef<[u8]>, S: StorageContext<'db>>( subtree: &Merk, key: K, + grove_version: &GroveVersion, ) -> CostResult { subtree .get( key.as_ref(), true, Some(&Element::value_defined_cost_for_serialized_value), + grove_version, ) .map_err(|_| { Error::InvalidPath("can't find subtree in parent during propagation".to_owned()) @@ -745,7 +798,7 @@ impl GroveDb { }) .flatten() .map_ok(|element_bytes| { - Element::deserialize(&element_bytes).map_err(|_| { + Element::deserialize(&element_bytes, grove_version).map_err(|_| { Error::CorruptedData( "failed to deserialized parent during propagation".to_owned(), ) @@ -768,11 +821,16 @@ impl GroveDb { /// # use std::convert::TryFrom; /// # use tempfile::TempDir; /// # use grovedb_path::SubtreePath; + /// # use grovedb_version::version::GroveVersion; /// # /// # fn main() -> Result<(), Box> { /// use std::option::Option::None; + /// /// + /// /// const TEST_LEAF: &[u8] = b"test_leaf"; /// + /// let grove_version = GroveVersion::latest(); + /// /// let tmp_dir = TempDir::new().unwrap(); /// let mut db = GroveDb::open(tmp_dir.path())?; /// db.insert( @@ -781,6 +839,7 @@ impl GroveDb { /// Element::empty_tree(), /// None, /// None, + /// grove_version, /// ) /// .unwrap()?; /// @@ -793,22 +852,27 @@ impl GroveDb { /// Element::empty_tree(), /// None, /// Some(&tx), + /// grove_version, /// ) /// .unwrap()?; /// /// // This action exists only inside the transaction for now - /// let result = db.get([TEST_LEAF].as_ref(), subtree_key, None).unwrap(); + /// let result = db + /// .get([TEST_LEAF].as_ref(), subtree_key, None, grove_version) + /// .unwrap(); /// assert!(matches!(result, Err(Error::PathKeyNotFound(_)))); /// /// // To access values inside the transaction, transaction needs to be passed to the `db::get` /// let result_with_transaction = db - /// .get([TEST_LEAF].as_ref(), subtree_key, Some(&tx)) + /// .get([TEST_LEAF].as_ref(), subtree_key, Some(&tx), grove_version) /// .unwrap()?; /// assert_eq!(result_with_transaction, Element::empty_tree()); /// /// // After transaction is committed, the value from it can be accessed normally. - /// db.commit_transaction(tx); - /// let result = db.get([TEST_LEAF].as_ref(), subtree_key, None).unwrap()?; + /// let _ = db.commit_transaction(tx); + /// let result = db + /// .get([TEST_LEAF].as_ref(), subtree_key, None, grove_version) + /// .unwrap()?; /// assert_eq!(result, Element::empty_tree()); /// /// # Ok(()) @@ -834,9 +898,10 @@ impl GroveDb { /// Method to visualize hash mismatch after verification pub fn visualize_verify_grovedb( &self, + grove_version: &GroveVersion, ) -> Result, Error> { Ok(self - .verify_grovedb(None)? + .verify_grovedb(None, grove_version)? .iter() .map(|(path, (root_hash, expected, actual))| { ( @@ -859,22 +924,29 @@ impl GroveDb { pub fn verify_grovedb( &self, transaction: TransactionArg, + grove_version: &GroveVersion, ) -> Result>, (CryptoHash, CryptoHash, CryptoHash)>, Error> { if let Some(transaction) = transaction { let root_merk = self - .open_transactional_merk_at_path(SubtreePath::empty(), transaction, None) + .open_transactional_merk_at_path( + SubtreePath::empty(), + transaction, + None, + grove_version, + ) .unwrap()?; self.verify_merk_and_submerks_in_transaction( root_merk, &SubtreePath::empty(), None, transaction, + grove_version, ) } else { let root_merk = self - .open_non_transactional_merk_at_path(SubtreePath::empty(), None) + .open_non_transactional_merk_at_path(SubtreePath::empty(), None, grove_version) .unwrap()?; - self.verify_merk_and_submerks(root_merk, &SubtreePath::empty(), None) + self.verify_merk_and_submerks(root_merk, &SubtreePath::empty(), None, grove_version) } } @@ -885,6 +957,7 @@ impl GroveDb { merk: Merk, path: &SubtreePath, batch: Option<&'db StorageBatch>, + grove_version: &GroveVersion, ) -> Result>, (CryptoHash, CryptoHash, CryptoHash)>, Error> { let mut all_query = Query::new(); all_query.insert_all(); @@ -894,13 +967,14 @@ impl GroveDb { let mut element_iterator = KVIterator::new(merk.storage.raw_iter(), &all_query).unwrap(); while let Some((key, element_value)) = element_iterator.next_kv().unwrap() { - let element = raw_decode(&element_value)?; + let element = raw_decode(&element_value, grove_version)?; if element.is_any_tree() { let (kv_value, element_value_hash) = merk .get_value_and_value_hash( &key, true, - None::<&fn(&[u8]) -> Option>, + None::<&fn(&[u8], &GroveVersion) -> Option>, + grove_version, ) .unwrap() .map_err(MerkError)? @@ -911,7 +985,7 @@ impl GroveDb { let new_path_ref = SubtreePath::from(&new_path); let inner_merk = self - .open_non_transactional_merk_at_path(new_path_ref.clone(), batch) + .open_non_transactional_merk_at_path(new_path_ref.clone(), batch, grove_version) .unwrap()?; let root_hash = inner_merk.root_hash().unwrap(); @@ -924,13 +998,19 @@ impl GroveDb { (root_hash, combined_value_hash, element_value_hash), ); } - issues.extend(self.verify_merk_and_submerks(inner_merk, &new_path_ref, batch)?); + issues.extend(self.verify_merk_and_submerks( + inner_merk, + &new_path_ref, + batch, + grove_version, + )?); } else if element.is_any_item() { let (kv_value, element_value_hash) = merk .get_value_and_value_hash( &key, true, - None::<&fn(&[u8]) -> Option>, + None::<&fn(&[u8], &GroveVersion) -> Option>, + grove_version, ) .unwrap() .map_err(MerkError)? @@ -955,6 +1035,7 @@ impl GroveDb { path: &SubtreePath, batch: Option<&'db StorageBatch>, transaction: &Transaction, + grove_version: &GroveVersion, ) -> Result>, (CryptoHash, CryptoHash, CryptoHash)>, Error> { let mut all_query = Query::new(); all_query.insert_all(); @@ -964,13 +1045,14 @@ impl GroveDb { let mut element_iterator = KVIterator::new(merk.storage.raw_iter(), &all_query).unwrap(); while let Some((key, element_value)) = element_iterator.next_kv().unwrap() { - let element = raw_decode(&element_value)?; + let element = raw_decode(&element_value, grove_version)?; if element.is_any_tree() { let (kv_value, element_value_hash) = merk .get_value_and_value_hash( &key, true, - None::<&fn(&[u8]) -> Option>, + None::<&fn(&[u8], &GroveVersion) -> Option>, + grove_version, ) .unwrap() .map_err(MerkError)? @@ -981,7 +1063,12 @@ impl GroveDb { let new_path_ref = SubtreePath::from(&new_path); let inner_merk = self - .open_transactional_merk_at_path(new_path_ref.clone(), transaction, batch) + .open_transactional_merk_at_path( + new_path_ref.clone(), + transaction, + batch, + grove_version, + ) .unwrap()?; let root_hash = inner_merk.root_hash().unwrap(); @@ -999,13 +1086,15 @@ impl GroveDb { &new_path_ref, batch, transaction, + grove_version, )?); } else if element.is_any_item() { let (kv_value, element_value_hash) = merk .get_value_and_value_hash( &key, true, - None::<&fn(&[u8]) -> Option>, + None::<&fn(&[u8], &GroveVersion) -> Option>, + grove_version, ) .unwrap() .map_err(MerkError)? diff --git a/grovedb/src/operations/auxiliary.rs b/grovedb/src/operations/auxiliary.rs index 6f9fd576..516796ed 100644 --- a/grovedb/src/operations/auxiliary.rs +++ b/grovedb/src/operations/auxiliary.rs @@ -37,6 +37,7 @@ use grovedb_path::SubtreePath; #[cfg(feature = "full")] use grovedb_storage::StorageContext; use grovedb_storage::{Storage, StorageBatch}; +use grovedb_version::version::GroveVersion; use crate::util::storage_context_optional_tx; #[cfg(feature = "full")] @@ -129,6 +130,7 @@ impl GroveDb { &self, path: &SubtreePath, transaction: TransactionArg, + grove_version: &GroveVersion, ) -> CostResult>>, Error> { let mut cost = OperationCost::default(); @@ -153,7 +155,7 @@ impl GroveDb { let storage = storage.unwrap_add_cost(&mut cost); let mut raw_iter = Element::iterator(storage.raw_iter()).unwrap_add_cost(&mut cost); while let Some((key, value)) = - cost_return_on_error!(&mut cost, raw_iter.next_element()) + cost_return_on_error!(&mut cost, raw_iter.next_element(grove_version)) { if value.is_any_tree() { let mut sub_path = q.clone(); diff --git a/grovedb/src/operations/delete/average_case.rs b/grovedb/src/operations/delete/average_case.rs index 5b1dba7c..3ed1abd1 100644 --- a/grovedb/src/operations/delete/average_case.rs +++ b/grovedb/src/operations/delete/average_case.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. - //! Average case delete cost use grovedb_costs::{ @@ -39,6 +11,9 @@ use grovedb_merk::{ HASH_LENGTH_U32, }; use grovedb_storage::{worst_case_costs::WorstKeyLength, Storage}; +use grovedb_version::{ + check_grovedb_v0_with_cost, error::GroveVersionError, version::GroveVersion, +}; use intmap::IntMap; use crate::{ @@ -58,7 +33,16 @@ impl GroveDb { stop_path_height: Option, validate: bool, estimated_layer_info: IntMap, + grove_version: &GroveVersion, ) -> CostResult, Error> { + check_grovedb_v0_with_cost!( + "average_case_delete_operations_for_delete_up_tree_while_empty", + grove_version + .grovedb_versions + .operations + .delete_up_tree + .average_case_delete_operations_for_delete_up_tree_while_empty + ); let mut cost = OperationCost::default(); let stop_path_height = stop_path_height.unwrap_or_default(); @@ -134,14 +118,15 @@ impl GroveDb { ); let op = cost_return_on_error!( &mut cost, - Self::average_case_delete_operation_for_delete_internal::( + Self::average_case_delete_operation_for_delete::( &KeyInfoPath::from_vec(path_at_level.to_vec()), key_at_level, is_sum_tree, validate, check_if_tree, except_keys_count, - (key_len, estimated_element_size) + (key_len, estimated_element_size), + grove_version, ) ); ops.push(op); @@ -150,8 +135,8 @@ impl GroveDb { } } - /// Average case delete operation for delete internal - pub fn average_case_delete_operation_for_delete_internal<'db, S: Storage<'db>>( + /// Average case delete operation for delete + pub fn average_case_delete_operation_for_delete<'db, S: Storage<'db>>( path: &KeyInfoPath, key: &KeyInfo, parent_tree_is_sum_tree: bool, @@ -159,24 +144,41 @@ impl GroveDb { check_if_tree: bool, except_keys_count: u16, estimated_key_element_size: EstimatedKeyAndElementSize, + grove_version: &GroveVersion, ) -> CostResult { + check_grovedb_v0_with_cost!( + "average_case_delete_operation_for_delete", + grove_version + .grovedb_versions + .operations + .delete + .average_case_delete_operation_for_delete + ); let mut cost = OperationCost::default(); if validate { - GroveDb::add_average_case_get_merk_at_path::( - &mut cost, - path, - false, - parent_tree_is_sum_tree, + cost_return_on_error_no_add!( + &cost, + GroveDb::add_average_case_get_merk_at_path::( + &mut cost, + path, + false, + parent_tree_is_sum_tree, + grove_version, + ) ); } if check_if_tree { - GroveDb::add_average_case_get_raw_cost::( - &mut cost, - path, - key, - estimated_key_element_size.1, - parent_tree_is_sum_tree, + cost_return_on_error_no_add!( + &cost, + GroveDb::add_average_case_get_raw_cost::( + &mut cost, + path, + key, + estimated_key_element_size.1, + parent_tree_is_sum_tree, + grove_version, + ) ); } // in the worst case this is a tree diff --git a/grovedb/src/operations/delete/delete_up_tree.rs b/grovedb/src/operations/delete/delete_up_tree.rs index 5e0439b2..dd331b69 100644 --- a/grovedb/src/operations/delete/delete_up_tree.rs +++ b/grovedb/src/operations/delete/delete_up_tree.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. - //! Delete up tree use grovedb_costs::{ @@ -34,6 +6,9 @@ use grovedb_costs::{ CostResult, CostsExt, OperationCost, }; use grovedb_path::SubtreePath; +use grovedb_version::{ + check_grovedb_v0_with_cost, error::GroveVersionError, version::GroveVersion, +}; use crate::{ batch::GroveDbOp, operations::delete::DeleteOptions, ElementFlags, Error, GroveDb, @@ -91,11 +66,20 @@ impl GroveDb { key: &[u8], options: &DeleteUpTreeOptions, transaction: TransactionArg, + grove_version: &GroveVersion, ) -> CostResult where B: AsRef<[u8]> + 'b, P: Into>, { + check_grovedb_v0_with_cost!( + "delete", + grove_version + .grovedb_versions + .operations + .delete_up_tree + .delete_up_tree_while_empty + ); self.delete_up_tree_while_empty_with_sectional_storage( path.into(), key, @@ -107,6 +91,7 @@ impl GroveDb { (BasicStorageRemoval(removed_value_bytes)), )) }, + grove_version, ) } @@ -126,7 +111,16 @@ impl GroveDb { (StorageRemovedBytes, StorageRemovedBytes), Error, >, + grove_version: &GroveVersion, ) -> CostResult { + check_grovedb_v0_with_cost!( + "delete", + grove_version + .grovedb_versions + .operations + .delete_up_tree + .delete_up_tree_while_empty_with_sectional_storage + ); let mut cost = OperationCost::default(); let mut batch_operations: Vec = Vec::new(); @@ -139,6 +133,7 @@ impl GroveDb { None, &mut batch_operations, transaction, + grove_version, ) ); @@ -163,6 +158,7 @@ impl GroveDb { |_, _, _| Ok(false), split_removal_bytes_function, transaction, + grove_version, ) .map_ok(|_| ops_len as u16) } @@ -176,7 +172,16 @@ impl GroveDb { is_known_to_be_subtree_with_sum: Option<(bool, bool)>, mut current_batch_operations: Vec, transaction: TransactionArg, + grove_version: &GroveVersion, ) -> CostResult, Error> { + check_grovedb_v0_with_cost!( + "delete", + grove_version + .grovedb_versions + .operations + .delete_up_tree + .delete_operations_for_delete_up_tree_while_empty + ); self.add_delete_operations_for_delete_up_tree_while_empty( path, key, @@ -184,6 +189,7 @@ impl GroveDb { is_known_to_be_subtree_with_sum, &mut current_batch_operations, transaction, + grove_version, ) .map_ok(|ops| ops.unwrap_or_default()) } @@ -198,7 +204,16 @@ impl GroveDb { is_known_to_be_subtree_with_sum: Option<(bool, bool)>, current_batch_operations: &mut Vec, transaction: TransactionArg, + grove_version: &GroveVersion, ) -> CostResult>, Error> { + check_grovedb_v0_with_cost!( + "delete", + grove_version + .grovedb_versions + .operations + .delete_up_tree + .add_delete_operations_for_delete_up_tree_while_empty + ); let mut cost = OperationCost::default(); if let Some(stop_path_height) = options.stop_path_height { @@ -210,7 +225,7 @@ impl GroveDb { if options.validate_tree_at_path_exists { cost_return_on_error!( &mut cost, - self.check_subtree_exists_path_not_found(path.clone(), transaction) + self.check_subtree_exists_path_not_found(path.clone(), transaction, grove_version) ); } if let Some(delete_operation_this_level) = cost_return_on_error!( @@ -222,6 +237,7 @@ impl GroveDb { is_known_to_be_subtree_with_sum, current_batch_operations, transaction, + grove_version, ) ) { let mut delete_operations = vec![delete_operation_this_level.clone()]; @@ -240,6 +256,7 @@ impl GroveDb { None, // todo: maybe we can know this? current_batch_operations, transaction, + grove_version, ) ) { delete_operations.append(&mut delete_operations_upper_level); diff --git a/grovedb/src/operations/delete/mod.rs b/grovedb/src/operations/delete/mod.rs index d13fdd61..31d96b85 100644 --- a/grovedb/src/operations/delete/mod.rs +++ b/grovedb/src/operations/delete/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. - //! Delete operations and costs #[cfg(feature = "estimated_costs")] @@ -55,6 +27,9 @@ use grovedb_storage::{ rocksdb_storage::{PrefixedRocksDbStorageContext, PrefixedRocksDbTransactionContext}, Storage, StorageBatch, StorageContext, }; +use grovedb_version::{ + check_grovedb_v0_with_cost, error::GroveVersionError, version::GroveVersion, +}; #[cfg(feature = "full")] use crate::{ @@ -70,7 +45,7 @@ use crate::{raw_decode, util::merk_optional_tx_path_not_empty}; pub struct ClearOptions { /// Check for Subtrees pub check_for_subtrees: bool, - /// Allow deleting non empty trees if we check for subtrees + /// Allow deleting non-empty trees if we check for subtrees pub allow_deleting_subtrees: bool, /// If we check for subtrees, and we don't allow deleting and there are /// some, should we error? @@ -92,7 +67,7 @@ impl Default for ClearOptions { #[derive(Clone)] /// Delete options pub struct DeleteOptions { - /// Allow deleting non empty trees + /// Allow deleting non-empty trees pub allow_deleting_non_empty_trees: bool, /// Deleting non empty trees returns error pub deleting_non_empty_trees_returns_error: bool, @@ -132,11 +107,17 @@ impl GroveDb { key: &[u8], options: Option, transaction: TransactionArg, + grove_version: &GroveVersion, ) -> CostResult<(), Error> where B: AsRef<[u8]> + 'b, P: Into>, { + check_grovedb_v0_with_cost!( + "delete", + grove_version.grovedb_versions.operations.delete.delete + ); + let options = options.unwrap_or_default(); let batch = StorageBatch::new(); @@ -153,6 +134,7 @@ impl GroveDb { )) }, &batch, + grove_version, ) .map_ok(|_| ()); @@ -170,12 +152,13 @@ impl GroveDb { path: P, options: Option, transaction: TransactionArg, + grove_version: &GroveVersion, ) -> Result where B: AsRef<[u8]> + 'b, P: Into>, { - self.clear_subtree_with_costs(path, options, transaction) + self.clear_subtree_with_costs(path, options, transaction, grove_version) .unwrap() } @@ -188,11 +171,21 @@ impl GroveDb { path: P, options: Option, transaction: TransactionArg, + grove_version: &GroveVersion, ) -> CostResult where B: AsRef<[u8]> + 'b, P: Into>, { + check_grovedb_v0_with_cost!( + "clear_subtree", + grove_version + .grovedb_versions + .operations + .delete + .clear_subtree + ); + let subtree_path: SubtreePath = path.into(); let mut cost = OperationCost::default(); let batch = StorageBatch::new(); @@ -205,7 +198,8 @@ impl GroveDb { self.open_transactional_merk_at_path( subtree_path.clone(), transaction, - Some(&batch) + Some(&batch), + grove_version, ) ); @@ -220,7 +214,7 @@ impl GroveDb { while let Some((key, element_value)) = element_iterator.next_kv().unwrap_add_cost(&mut cost) { - let element = raw_decode(&element_value).unwrap(); + let element = raw_decode(&element_value, grove_version).unwrap(); if element.is_any_tree() { if options.allow_deleting_subtrees { cost_return_on_error!( @@ -234,6 +228,7 @@ impl GroveDb { ..Default::default() }), Some(transaction), + grove_version, ) ); } else if options.trying_to_clear_with_subtrees_returns_error { @@ -263,12 +258,17 @@ impl GroveDb { subtree_path.clone(), transaction, &batch, + grove_version, ) ); } else { let mut merk_to_clear = cost_return_on_error!( &mut cost, - self.open_non_transactional_merk_at_path(subtree_path.clone(), Some(&batch)) + self.open_non_transactional_merk_at_path( + subtree_path.clone(), + Some(&batch), + grove_version + ) ); if options.check_for_subtrees { @@ -282,7 +282,7 @@ impl GroveDb { while let Some((key, element_value)) = element_iterator.next_kv().unwrap_add_cost(&mut cost) { - let element = raw_decode(&element_value).unwrap(); + let element = raw_decode(&element_value, grove_version).unwrap(); if options.allow_deleting_subtrees { if element.is_any_tree() { cost_return_on_error!( @@ -295,7 +295,8 @@ impl GroveDb { deleting_non_empty_trees_returns_error: false, ..Default::default() }), - None + None, + grove_version, ) ); } @@ -323,6 +324,7 @@ impl GroveDb { merk_cache, subtree_path.clone(), &batch, + grove_version, ) ); } @@ -352,7 +354,17 @@ impl GroveDb { (StorageRemovedBytes, StorageRemovedBytes), Error, >, + grove_version: &GroveVersion, ) -> CostResult<(), Error> { + check_grovedb_v0_with_cost!( + "delete_with_sectional_storage_function", + grove_version + .grovedb_versions + .operations + .delete + .delete_with_sectional_storage_function + ); + let options = options.unwrap_or_default(); let batch = StorageBatch::new(); @@ -363,7 +375,7 @@ impl GroveDb { &options, transaction, &mut |value, removed_key_bytes, removed_value_bytes| { - let mut element = Element::deserialize(value.as_slice()) + let mut element = Element::deserialize(value.as_slice(), grove_version) .map_err(|e| MerkError::ClientCorruptionError(e.to_string()))?; let maybe_flags = element.get_flags_mut(); match maybe_flags { @@ -371,7 +383,7 @@ impl GroveDb { BasicStorageRemoval(removed_key_bytes), BasicStorageRemoval(removed_value_bytes), )), - Some(flags) => (split_removal_bytes_function)( + Some(flags) => split_removal_bytes_function( flags, removed_key_bytes, removed_value_bytes, @@ -380,6 +392,7 @@ impl GroveDb { } }, &batch, + grove_version, ) .map_ok(|_| ()); @@ -396,11 +409,21 @@ impl GroveDb { path: P, key: &[u8], transaction: TransactionArg, + grove_version: &GroveVersion, ) -> CostResult where B: AsRef<[u8]> + 'b, P: Into>, { + check_grovedb_v0_with_cost!( + "delete_if_empty_tree", + grove_version + .grovedb_versions + .operations + .delete + .delete_if_empty_tree + ); + let batch = StorageBatch::new(); let collect_costs = self.delete_if_empty_tree_with_sectional_storage_function( @@ -410,10 +433,11 @@ impl GroveDb { &mut |_, removed_key_bytes, removed_value_bytes| { Ok(( BasicStorageRemoval(removed_key_bytes), - (BasicStorageRemoval(removed_value_bytes)), + BasicStorageRemoval(removed_value_bytes), )) }, &batch, + grove_version, ); collect_costs.flat_map_ok(|r| { @@ -439,7 +463,17 @@ impl GroveDb { Error, >, batch: &StorageBatch, + grove_version: &GroveVersion, ) -> CostResult { + check_grovedb_v0_with_cost!( + "delete_if_empty_tree_with_sectional_storage_function", + grove_version + .grovedb_versions + .operations + .delete + .delete_if_empty_tree_with_sectional_storage_function + ); + let options = DeleteOptions { allow_deleting_non_empty_trees: false, deleting_non_empty_trees_returns_error: false, @@ -452,7 +486,7 @@ impl GroveDb { &options, transaction, &mut |value, removed_key_bytes, removed_value_bytes| { - let mut element = Element::deserialize(value.as_slice()) + let mut element = Element::deserialize(value.as_slice(), grove_version) .map_err(|e| MerkError::ClientCorruptionError(e.to_string()))?; let maybe_flags = element.get_flags_mut(); match maybe_flags { @@ -460,15 +494,14 @@ impl GroveDb { BasicStorageRemoval(removed_key_bytes), BasicStorageRemoval(removed_value_bytes), )), - Some(flags) => (split_removal_bytes_function)( - flags, - removed_key_bytes, - removed_value_bytes, - ) - .map_err(|e| MerkError::ClientCorruptionError(e.to_string())), + Some(flags) => { + split_removal_bytes_function(flags, removed_key_bytes, removed_value_bytes) + .map_err(|e| MerkError::ClientCorruptionError(e.to_string())) + } } }, batch, + grove_version, ) } @@ -481,7 +514,17 @@ impl GroveDb { is_known_to_be_subtree_with_sum: Option<(bool, bool)>, current_batch_operations: &[GroveDbOp], transaction: TransactionArg, + grove_version: &GroveVersion, ) -> CostResult, Error> { + check_grovedb_v0_with_cost!( + "delete_operation_for_delete_internal", + grove_version + .grovedb_versions + .operations + .delete + .delete_operation_for_delete_internal + ); + let mut cost = OperationCost::default(); if path.is_root() { @@ -494,14 +537,18 @@ impl GroveDb { if options.validate_tree_at_path_exists { cost_return_on_error!( &mut cost, - self.check_subtree_exists_path_not_found(path.clone(), transaction) + self.check_subtree_exists_path_not_found( + path.clone(), + transaction, + grove_version + ) ); } let (is_subtree, is_subtree_with_sum) = match is_known_to_be_subtree_with_sum { None => { let element = cost_return_on_error!( &mut cost, - self.get_raw(path.clone(), key.as_ref(), transaction) + self.get_raw(path.clone(), key.as_ref(), transaction, grove_version) ); match element { Element::Tree(..) => (true, false), @@ -537,6 +584,7 @@ impl GroveDb { None, transaction, subtree, + grove_version, { subtree .is_empty_tree_except(batch_deleted_keys) @@ -594,6 +642,7 @@ impl GroveDb { MerkError, >, batch: &StorageBatch, + grove_version: &GroveVersion, ) -> CostResult { if let Some(transaction) = transaction { self.delete_internal_on_transaction( @@ -603,9 +652,17 @@ impl GroveDb { transaction, sectioned_removal, batch, + grove_version, ) } else { - self.delete_internal_without_transaction(path, key, options, sectioned_removal, batch) + self.delete_internal_without_transaction( + path, + key, + options, + sectioned_removal, + batch, + grove_version, + ) } } @@ -624,16 +681,31 @@ impl GroveDb { MerkError, >, batch: &StorageBatch, + grove_version: &GroveVersion, ) -> CostResult { + check_grovedb_v0_with_cost!( + "delete_internal_on_transaction", + grove_version + .grovedb_versions + .operations + .delete + .delete_internal_on_transaction + ); + let mut cost = OperationCost::default(); let element = cost_return_on_error!( &mut cost, - self.get_raw(path.clone(), key.as_ref(), Some(transaction)) + self.get_raw(path.clone(), key.as_ref(), Some(transaction), grove_version) ); let mut subtree_to_delete_from = cost_return_on_error!( &mut cost, - self.open_transactional_merk_at_path(path.clone(), transaction, Some(batch)) + self.open_transactional_merk_at_path( + path.clone(), + transaction, + Some(batch), + grove_version + ) ); let uses_sum_tree = subtree_to_delete_from.is_sum_tree; if element.is_any_tree() { @@ -645,7 +717,8 @@ impl GroveDb { self.open_transactional_merk_at_path( subtree_merk_path_ref.clone(), transaction, - Some(batch) + Some(batch), + grove_version, ) ); let is_empty = subtree_of_tree_we_are_deleting @@ -665,7 +738,7 @@ impl GroveDb { } else if !is_empty { let subtrees_paths = cost_return_on_error!( &mut cost, - self.find_subtrees(&subtree_merk_path_ref, Some(transaction)) + self.find_subtrees(&subtree_merk_path_ref, Some(transaction), grove_version) ); for subtree_path in subtrees_paths { let p: SubtreePath<_> = subtree_path.as_slice().into(); @@ -696,6 +769,7 @@ impl GroveDb { subtree_to_delete_from.root_key(), element.is_sum_tree(), Some(&Element::value_defined_cost_for_serialized_value), + grove_version, ) .map_err(|_| { Error::CorruptedData("cannot open a subtree with given root key".to_owned()) @@ -710,7 +784,8 @@ impl GroveDb { Some(options.as_merk_options()), true, uses_sum_tree, - sectioned_removal + sectioned_removal, + grove_version, ) ); let mut merk_cache: HashMap< @@ -724,7 +799,8 @@ impl GroveDb { batch, merk_cache, &path, - transaction + transaction, + grove_version, ) ); } else { @@ -737,7 +813,8 @@ impl GroveDb { Some(options.as_merk_options()), true, uses_sum_tree, - sectioned_removal + sectioned_removal, + grove_version, ) ); let mut merk_cache: HashMap< @@ -747,7 +824,13 @@ impl GroveDb { merk_cache.insert(path.clone(), subtree_to_delete_from); cost_return_on_error!( &mut cost, - self.propagate_changes_with_transaction(merk_cache, path, transaction, batch) + self.propagate_changes_with_transaction( + merk_cache, + path, + transaction, + batch, + grove_version + ) ); } } else { @@ -760,6 +843,7 @@ impl GroveDb { false, uses_sum_tree, sectioned_removal, + grove_version, ) ); let mut merk_cache: HashMap, Merk> = @@ -767,7 +851,13 @@ impl GroveDb { merk_cache.insert(path.clone(), subtree_to_delete_from); cost_return_on_error!( &mut cost, - self.propagate_changes_with_transaction(merk_cache, path, transaction, batch) + self.propagate_changes_with_transaction( + merk_cache, + path, + transaction, + batch, + grove_version + ) ); } @@ -788,16 +878,28 @@ impl GroveDb { MerkError, >, batch: &StorageBatch, + grove_version: &GroveVersion, ) -> CostResult { + check_grovedb_v0_with_cost!( + "delete_internal_without_transaction", + grove_version + .grovedb_versions + .operations + .delete + .delete_internal_without_transaction + ); + let mut cost = OperationCost::default(); - let element = - cost_return_on_error!(&mut cost, self.get_raw(path.clone(), key.as_ref(), None)); + let element = cost_return_on_error!( + &mut cost, + self.get_raw(path.clone(), key.as_ref(), None, grove_version) + ); let mut merk_cache: HashMap, Merk> = HashMap::default(); let mut subtree_to_delete_from = cost_return_on_error!( &mut cost, - self.open_non_transactional_merk_at_path(path.clone(), Some(batch)) + self.open_non_transactional_merk_at_path(path.clone(), Some(batch), grove_version) ); let uses_sum_tree = subtree_to_delete_from.is_sum_tree; if element.is_any_tree() { @@ -806,7 +908,8 @@ impl GroveDb { &mut cost, self.open_non_transactional_merk_at_path( SubtreePath::from(&subtree_merk_path), - Some(batch) + Some(batch), + grove_version, ) ); let is_empty = subtree_of_tree_we_are_deleting @@ -827,14 +930,18 @@ impl GroveDb { if !is_empty { let subtrees_paths = cost_return_on_error!( &mut cost, - self.find_subtrees(&SubtreePath::from(&subtree_merk_path), None) + self.find_subtrees( + &SubtreePath::from(&subtree_merk_path), + None, + grove_version + ) ); // TODO: dumb traversal should not be tolerated for subtree_path in subtrees_paths.into_iter().rev() { let p: SubtreePath<_> = subtree_path.as_slice().into(); let mut inner_subtree_to_delete_from = cost_return_on_error!( &mut cost, - self.open_non_transactional_merk_at_path(p, Some(batch)) + self.open_non_transactional_merk_at_path(p, Some(batch), grove_version) ); cost_return_on_error!( &mut cost, @@ -855,6 +962,7 @@ impl GroveDb { true, uses_sum_tree, sectioned_removal, + grove_version, ) ); } @@ -868,13 +976,14 @@ impl GroveDb { false, uses_sum_tree, sectioned_removal, + grove_version, ) ); } merk_cache.insert(path.clone(), subtree_to_delete_from); cost_return_on_error!( &mut cost, - self.propagate_changes_without_transaction(merk_cache, path, batch) + self.propagate_changes_without_transaction(merk_cache, path, batch, grove_version) ); Ok(true).wrap_with_cost(cost) @@ -888,6 +997,7 @@ mod tests { storage_cost::{removal::StorageRemovedBytes::BasicStorageRemoval, StorageCost}, OperationCost, }; + use grovedb_version::version::GroveVersion; use pretty_assertions::assert_eq; use crate::{ @@ -900,8 +1010,9 @@ mod tests { #[test] fn test_empty_subtree_deletion_without_transaction() { + let grove_version = GroveVersion::latest(); let _element = Element::new_item(b"ayy".to_vec()); - let db = make_test_grovedb(); + let db = make_test_grovedb(grove_version); // Insert some nested subtrees db.insert( [TEST_LEAF].as_ref(), @@ -909,6 +1020,7 @@ mod tests { Element::empty_tree(), None, None, + grove_version, ) .unwrap() .expect("successful subtree 1 insert"); @@ -918,32 +1030,51 @@ mod tests { Element::empty_tree(), None, None, + grove_version, ) .unwrap() .expect("successful subtree 3 insert"); - let root_hash = db.root_hash(None).unwrap().unwrap(); - db.delete([TEST_LEAF].as_ref(), b"key1", None, None) + let root_hash = db.root_hash(None, grove_version).unwrap().unwrap(); + db.delete([TEST_LEAF].as_ref(), b"key1", None, None, grove_version) .unwrap() .expect("unable to delete subtree"); assert!(matches!( - db.get([TEST_LEAF, b"key1", b"key2"].as_ref(), b"key3", None) - .unwrap(), + db.get( + [TEST_LEAF, b"key1", b"key2"].as_ref(), + b"key3", + None, + grove_version + ) + .unwrap(), Err(Error::PathParentLayerNotFound(_)) )); // assert_eq!(db.subtrees.len().unwrap(), 3); // TEST_LEAF, ANOTHER_TEST_LEAF // TEST_LEAF.key4 stay - assert!(db.get(EMPTY_PATH, TEST_LEAF, None).unwrap().is_ok()); - assert!(db.get(EMPTY_PATH, ANOTHER_TEST_LEAF, None).unwrap().is_ok()); - assert!(db.get([TEST_LEAF].as_ref(), b"key4", None).unwrap().is_ok()); - assert_ne!(root_hash, db.root_hash(None).unwrap().unwrap()); + assert!(db + .get(EMPTY_PATH, TEST_LEAF, None, grove_version) + .unwrap() + .is_ok()); + assert!(db + .get(EMPTY_PATH, ANOTHER_TEST_LEAF, None, grove_version) + .unwrap() + .is_ok()); + assert!(db + .get([TEST_LEAF].as_ref(), b"key4", None, grove_version) + .unwrap() + .is_ok()); + assert_ne!( + root_hash, + db.root_hash(None, grove_version).unwrap().unwrap() + ); } #[test] fn test_empty_subtree_deletion_with_transaction() { + let grove_version = GroveVersion::latest(); let _element = Element::new_item(b"ayy".to_vec()); - let db = make_test_grovedb(); + let db = make_test_grovedb(grove_version); let transaction = db.start_transaction(); // Insert some nested subtrees @@ -953,6 +1084,7 @@ mod tests { Element::empty_tree(), None, Some(&transaction), + grove_version, ) .unwrap() .expect("successful subtree 1 insert"); @@ -962,34 +1094,47 @@ mod tests { Element::empty_tree(), None, Some(&transaction), + grove_version, ) .unwrap() .expect("successful subtree 3 insert"); - db.delete([TEST_LEAF].as_ref(), b"key1", None, Some(&transaction)) - .unwrap() - .expect("unable to delete subtree"); + db.delete( + [TEST_LEAF].as_ref(), + b"key1", + None, + Some(&transaction), + grove_version, + ) + .unwrap() + .expect("unable to delete subtree"); assert!(matches!( db.get( [TEST_LEAF, b"key1", b"key2"].as_ref(), b"key3", - Some(&transaction) + Some(&transaction), + grove_version ) .unwrap(), Err(Error::PathParentLayerNotFound(_)) )); transaction.commit().expect("cannot commit transaction"); assert!(matches!( - db.get([TEST_LEAF].as_ref(), b"key1", None).unwrap(), + db.get([TEST_LEAF].as_ref(), b"key1", None, grove_version) + .unwrap(), Err(Error::PathKeyNotFound(_)) )); - assert!(db.get([TEST_LEAF].as_ref(), b"key4", None).unwrap().is_ok()); + assert!(db + .get([TEST_LEAF].as_ref(), b"key4", None, grove_version) + .unwrap() + .is_ok()); } #[test] fn test_subtree_deletion_if_empty_with_transaction() { + let grove_version = GroveVersion::latest(); let element = Element::new_item(b"value".to_vec()); - let db = make_test_grovedb(); + let db = make_test_grovedb(grove_version); let transaction = db.start_transaction(); @@ -1000,6 +1145,7 @@ mod tests { Element::empty_tree(), None, Some(&transaction), + grove_version, ) .unwrap() .expect("successful subtree insert A on level 1"); @@ -1009,6 +1155,7 @@ mod tests { Element::empty_tree(), None, Some(&transaction), + grove_version, ) .unwrap() .expect("successful subtree insert A on level 2"); @@ -1018,6 +1165,7 @@ mod tests { Element::empty_tree(), None, Some(&transaction), + grove_version, ) .unwrap() .expect("successful subtree insert B on level 2"); @@ -1028,6 +1176,7 @@ mod tests { element, None, Some(&transaction), + grove_version, ) .unwrap() .expect("successful value insert"); @@ -1037,6 +1186,7 @@ mod tests { Element::empty_tree(), None, Some(&transaction), + grove_version, ) .unwrap() .expect("successful subtree insert B on level 1"); @@ -1055,7 +1205,12 @@ mod tests { let transaction = db.start_transaction(); let deleted = db - .delete_if_empty_tree([TEST_LEAF].as_ref(), b"level1-A", Some(&transaction)) + .delete_if_empty_tree( + [TEST_LEAF].as_ref(), + b"level1-A", + Some(&transaction), + grove_version, + ) .unwrap() .expect("unable to delete subtree"); assert!(!deleted); @@ -1069,6 +1224,7 @@ mod tests { ..Default::default() }, Some(&transaction), + grove_version, ) .unwrap() .expect("unable to delete subtree"); @@ -1078,7 +1234,8 @@ mod tests { db.get( [TEST_LEAF, b"level1-A", b"level2-A"].as_ref(), b"level3-A", - Some(&transaction) + Some(&transaction), + grove_version ) .unwrap(), Err(Error::PathParentLayerNotFound(_)) @@ -1088,23 +1245,30 @@ mod tests { db.get( [TEST_LEAF, b"level1-A"].as_ref(), b"level2-A", - Some(&transaction) + Some(&transaction), + grove_version ) .unwrap(), Err(Error::PathKeyNotFound(_)) )); assert!(matches!( - db.get([TEST_LEAF].as_ref(), b"level1-A", Some(&transaction)) - .unwrap(), + db.get( + [TEST_LEAF].as_ref(), + b"level1-A", + Some(&transaction), + grove_version + ) + .unwrap(), Ok(Element::Tree(..)), )); } #[test] fn test_subtree_deletion_if_empty_without_transaction() { + let grove_version = GroveVersion::latest(); let element = Element::new_item(b"value".to_vec()); - let db = make_test_grovedb(); + let db = make_test_grovedb(grove_version); // Insert some nested subtrees db.insert( @@ -1113,6 +1277,7 @@ mod tests { Element::empty_tree(), None, None, + grove_version, ) .unwrap() .expect("successful subtree insert A on level 1"); @@ -1122,6 +1287,7 @@ mod tests { Element::empty_tree(), None, None, + grove_version, ) .unwrap() .expect("successful subtree insert A on level 2"); @@ -1131,6 +1297,7 @@ mod tests { Element::empty_tree(), None, None, + grove_version, ) .unwrap() .expect("successful subtree insert B on level 2"); @@ -1141,6 +1308,7 @@ mod tests { element, None, None, + grove_version, ) .unwrap() .expect("successful value insert"); @@ -1150,6 +1318,7 @@ mod tests { Element::empty_tree(), None, None, + grove_version, ) .unwrap() .expect("successful subtree insert B on level 1"); @@ -1162,7 +1331,7 @@ mod tests { // Level 3: A: value let deleted = db - .delete_if_empty_tree([TEST_LEAF].as_ref(), b"level1-A", None) + .delete_if_empty_tree([TEST_LEAF].as_ref(), b"level1-A", None, grove_version) .unwrap() .expect("unable to delete subtree"); assert!(!deleted); @@ -1176,6 +1345,7 @@ mod tests { ..Default::default() }, None, + grove_version, ) .unwrap() .expect("unable to delete subtree"); @@ -1186,28 +1356,36 @@ mod tests { [TEST_LEAF, b"level1-A", b"level2-A"].as_ref(), b"level3-A", None, + grove_version ) .unwrap(), Err(Error::PathParentLayerNotFound(_)) )); assert!(matches!( - db.get([TEST_LEAF, b"level1-A"].as_ref(), b"level2-A", None) - .unwrap(), + db.get( + [TEST_LEAF, b"level1-A"].as_ref(), + b"level2-A", + None, + grove_version + ) + .unwrap(), Err(Error::PathKeyNotFound(_)) )); assert!(matches!( - db.get([TEST_LEAF].as_ref(), b"level1-A", None).unwrap(), + db.get([TEST_LEAF].as_ref(), b"level1-A", None, grove_version) + .unwrap(), Ok(Element::Tree(..)), )); } #[test] fn test_recurring_deletion_through_subtrees_with_transaction() { + let grove_version = GroveVersion::latest(); let element = Element::new_item(b"ayy".to_vec()); - let db = make_test_grovedb(); + let db = make_test_grovedb(grove_version); let transaction = db.start_transaction(); // Insert some nested subtrees @@ -1217,6 +1395,7 @@ mod tests { Element::empty_tree(), None, Some(&transaction), + grove_version, ) .unwrap() .expect("successful subtree 1 insert"); @@ -1226,6 +1405,7 @@ mod tests { Element::empty_tree(), None, Some(&transaction), + grove_version, ) .unwrap() .expect("successful subtree 2 insert"); @@ -1237,6 +1417,7 @@ mod tests { element, None, Some(&transaction), + grove_version, ) .unwrap() .expect("successful value insert"); @@ -1246,6 +1427,7 @@ mod tests { Element::empty_tree(), None, Some(&transaction), + grove_version, ) .unwrap() .expect("successful subtree 3 insert"); @@ -1259,6 +1441,7 @@ mod tests { ..Default::default() }), Some(&transaction), + grove_version, ) .unwrap() .expect("unable to delete subtree"); @@ -1266,26 +1449,29 @@ mod tests { db.get( [TEST_LEAF, b"key1", b"key2"].as_ref(), b"key3", - Some(&transaction) + Some(&transaction), + grove_version ) .unwrap(), Err(Error::PathParentLayerNotFound(_)) )); transaction.commit().expect("cannot commit transaction"); assert!(matches!( - db.get([TEST_LEAF].as_ref(), b"key1", None).unwrap(), + db.get([TEST_LEAF].as_ref(), b"key1", None, grove_version) + .unwrap(), Err(Error::PathKeyNotFound(_)) )); - db.get([TEST_LEAF].as_ref(), b"key4", None) + db.get([TEST_LEAF].as_ref(), b"key4", None, grove_version) .unwrap() .expect("expected to get key4"); } #[test] fn test_recurring_deletion_through_subtrees_without_transaction() { + let grove_version = GroveVersion::latest(); let element = Element::new_item(b"ayy".to_vec()); - let db = make_test_grovedb(); + let db = make_test_grovedb(grove_version); // Insert some nested subtrees db.insert( @@ -1294,6 +1480,7 @@ mod tests { Element::empty_tree(), None, None, + grove_version, ) .unwrap() .expect("successful subtree 1 insert"); @@ -1303,6 +1490,7 @@ mod tests { Element::empty_tree(), None, None, + grove_version, ) .unwrap() .expect("successful subtree 2 insert"); @@ -1314,6 +1502,7 @@ mod tests { element, None, None, + grove_version, ) .unwrap() .expect("successful value insert"); @@ -1323,6 +1512,7 @@ mod tests { Element::empty_tree(), None, None, + grove_version, ) .unwrap() .expect("successful subtree 3 insert"); @@ -1336,42 +1526,65 @@ mod tests { ..Default::default() }), None, + grove_version, ) .unwrap() .expect("unable to delete subtree"); assert!(matches!( - db.get([TEST_LEAF, b"key1", b"key2"].as_ref(), b"key3", None) - .unwrap(), + db.get( + [TEST_LEAF, b"key1", b"key2"].as_ref(), + b"key3", + None, + grove_version + ) + .unwrap(), Err(Error::PathParentLayerNotFound(_)) )); assert!(matches!( - db.get([TEST_LEAF].as_ref(), b"key1", None).unwrap(), + db.get([TEST_LEAF].as_ref(), b"key1", None, grove_version) + .unwrap(), Err(Error::PathKeyNotFound(_)) )); - assert!(db.get([TEST_LEAF].as_ref(), b"key4", None).unwrap().is_ok()); + assert!(db + .get([TEST_LEAF].as_ref(), b"key4", None, grove_version) + .unwrap() + .is_ok()); } #[test] fn test_item_deletion() { - let db = make_test_grovedb(); + let grove_version = GroveVersion::latest(); + let db = make_test_grovedb(grove_version); let element = Element::new_item(b"ayy".to_vec()); - db.insert([TEST_LEAF].as_ref(), b"key", element, None, None) - .unwrap() - .expect("successful insert"); - let root_hash = db.root_hash(None).unwrap().unwrap(); + db.insert( + [TEST_LEAF].as_ref(), + b"key", + element, + None, + None, + grove_version, + ) + .unwrap() + .expect("successful insert"); + let root_hash = db.root_hash(None, grove_version).unwrap().unwrap(); assert!(db - .delete([TEST_LEAF].as_ref(), b"key", None, None) + .delete([TEST_LEAF].as_ref(), b"key", None, None, grove_version) .unwrap() .is_ok()); assert!(matches!( - db.get([TEST_LEAF].as_ref(), b"key", None).unwrap(), + db.get([TEST_LEAF].as_ref(), b"key", None, grove_version) + .unwrap(), Err(Error::PathKeyNotFound(_)) )); - assert_ne!(root_hash, db.root_hash(None).unwrap().unwrap()); + assert_ne!( + root_hash, + db.root_hash(None, grove_version).unwrap().unwrap() + ); } #[test] fn test_delete_one_item_cost() { + let grove_version = GroveVersion::latest(); let db = make_empty_grovedb(); let tx = db.start_transaction(); @@ -1382,12 +1595,13 @@ mod tests { Element::new_item(b"cat".to_vec()), None, Some(&tx), + grove_version, ) .cost_as_result() .expect("expected to insert"); let cost = db - .delete(EMPTY_PATH, b"key1", None, Some(&tx)) + .delete(EMPTY_PATH, b"key1", None, Some(&tx), grove_version) .cost_as_result() .expect("expected to delete"); @@ -1440,6 +1654,7 @@ mod tests { #[test] fn test_delete_one_sum_item_cost() { + let grove_version = GroveVersion::latest(); let db = make_empty_grovedb(); let tx = db.start_transaction(); @@ -1449,6 +1664,7 @@ mod tests { Element::empty_sum_tree(), None, Some(&tx), + grove_version, ) .unwrap() .expect("expected to insert"); @@ -1460,12 +1676,19 @@ mod tests { Element::new_sum_item(15000), None, Some(&tx), + grove_version, ) .cost_as_result() .expect("expected to insert"); let cost = db - .delete([b"sum_tree".as_slice()].as_ref(), b"key1", None, Some(&tx)) + .delete( + [b"sum_tree".as_slice()].as_ref(), + b"key1", + None, + Some(&tx), + grove_version, + ) .cost_as_result() .expect("expected to delete"); @@ -1517,6 +1740,7 @@ mod tests { #[test] fn test_delete_one_item_in_sum_tree_cost() { + let grove_version = GroveVersion::latest(); let db = make_empty_grovedb(); let tx = db.start_transaction(); @@ -1526,6 +1750,7 @@ mod tests { Element::empty_sum_tree(), None, Some(&tx), + grove_version, ) .unwrap() .expect("expected to insert"); @@ -1537,12 +1762,19 @@ mod tests { Element::new_item(b"hello".to_vec()), None, Some(&tx), + grove_version, ) .cost_as_result() .expect("expected to insert"); let cost = db - .delete([b"sum_tree".as_slice()].as_ref(), b"key1", None, Some(&tx)) + .delete( + [b"sum_tree".as_slice()].as_ref(), + b"key1", + None, + Some(&tx), + grove_version, + ) .cost_as_result() .expect("expected to delete"); @@ -1595,9 +1827,10 @@ mod tests { #[test] fn test_subtree_clear() { + let grove_version = GroveVersion::latest(); let element = Element::new_item(b"ayy".to_vec()); - let db = make_test_grovedb(); + let db = make_test_grovedb(grove_version); // Insert some nested subtrees db.insert( @@ -1606,6 +1839,7 @@ mod tests { Element::empty_tree(), None, None, + grove_version, ) .unwrap() .expect("successful subtree 1 insert"); @@ -1615,6 +1849,7 @@ mod tests { Element::empty_tree(), None, None, + grove_version, ) .unwrap() .expect("successful subtree 2 insert"); @@ -1626,6 +1861,7 @@ mod tests { element, None, None, + grove_version, ) .unwrap() .expect("successful value insert"); @@ -1635,23 +1871,28 @@ mod tests { Element::empty_tree(), None, None, + grove_version, ) .unwrap() .expect("successful subtree 3 insert"); let key1_tree = db - .get([TEST_LEAF].as_ref(), b"key1", None) + .get([TEST_LEAF].as_ref(), b"key1", None, grove_version) .unwrap() .unwrap(); assert!(!matches!(key1_tree, Element::Tree(None, _))); let key1_merk = db - .open_non_transactional_merk_at_path([TEST_LEAF, b"key1"].as_ref().into(), None) + .open_non_transactional_merk_at_path( + [TEST_LEAF, b"key1"].as_ref().into(), + None, + grove_version, + ) .unwrap() .unwrap(); assert_ne!(key1_merk.root_hash().unwrap(), [0; 32]); - let root_hash_before_clear = db.root_hash(None).unwrap().unwrap(); - db.clear_subtree([TEST_LEAF, b"key1"].as_ref(), None, None) + let root_hash_before_clear = db.root_hash(None, grove_version).unwrap().unwrap(); + db.clear_subtree([TEST_LEAF, b"key1"].as_ref(), None, None, grove_version) .expect_err("unable to delete subtree"); let success = db @@ -1663,6 +1904,7 @@ mod tests { trying_to_clear_with_subtrees_returns_error: false, }), None, + grove_version, ) .expect("expected no error"); assert!(!success); @@ -1676,34 +1918,44 @@ mod tests { trying_to_clear_with_subtrees_returns_error: false, }), None, + grove_version, ) .expect("unable to delete subtree"); assert!(success); assert!(matches!( - db.get([TEST_LEAF, b"key1"].as_ref(), b"key2", None) + db.get([TEST_LEAF, b"key1"].as_ref(), b"key2", None, grove_version) .unwrap(), Err(Error::PathKeyNotFound(_)) )); assert!(matches!( - db.get([TEST_LEAF, b"key1", b"key2"].as_ref(), b"key3", None) - .unwrap(), + db.get( + [TEST_LEAF, b"key1", b"key2"].as_ref(), + b"key3", + None, + grove_version + ) + .unwrap(), Err(Error::PathParentLayerNotFound(_)) )); let key1_tree = db - .get([TEST_LEAF].as_ref(), b"key1", None) + .get([TEST_LEAF].as_ref(), b"key1", None, grove_version) .unwrap() .unwrap(); assert!(matches!(key1_tree, Element::Tree(None, _))); let key1_merk = db - .open_non_transactional_merk_at_path([TEST_LEAF, b"key1"].as_ref().into(), None) + .open_non_transactional_merk_at_path( + [TEST_LEAF, b"key1"].as_ref().into(), + None, + grove_version, + ) .unwrap() .unwrap(); assert_eq!(key1_merk.root_hash().unwrap(), [0; 32]); - let root_hash_after_clear = db.root_hash(None).unwrap().unwrap(); + let root_hash_after_clear = db.root_hash(None, grove_version).unwrap().unwrap(); assert_ne!(root_hash_before_clear, root_hash_after_clear); } } diff --git a/grovedb/src/operations/delete/worst_case.rs b/grovedb/src/operations/delete/worst_case.rs index a887a469..b2a50bb2 100644 --- a/grovedb/src/operations/delete/worst_case.rs +++ b/grovedb/src/operations/delete/worst_case.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. - //! Worst case delete costs use grovedb_costs::{ @@ -35,6 +7,9 @@ use grovedb_merk::{ estimated_costs::worst_case_costs::add_worst_case_cost_for_is_empty_tree_except, tree::kv::KV, }; use grovedb_storage::{worst_case_costs::WorstKeyLength, Storage}; +use grovedb_version::{ + check_grovedb_v0_with_cost, error::GroveVersionError, version::GroveVersion, +}; use intmap::IntMap; use crate::{ @@ -53,7 +28,16 @@ impl GroveDb { validate: bool, intermediate_tree_info: IntMap<(bool, u32)>, max_element_size: u32, + grove_version: &GroveVersion, ) -> CostResult, Error> { + check_grovedb_v0_with_cost!( + "delete", + grove_version + .grovedb_versions + .operations + .delete_up_tree + .worst_case_delete_operations_for_delete_up_tree_while_empty + ); let mut cost = OperationCost::default(); let stop_path_height = stop_path_height.unwrap_or_default(); @@ -116,14 +100,15 @@ impl GroveDb { ); let op = cost_return_on_error!( &mut cost, - Self::worst_case_delete_operation_for_delete_internal::( + Self::worst_case_delete_operation_for_delete::( &KeyInfoPath::from_vec(path_at_level.to_vec()), key_at_level, is_sum_tree, validate, check_if_tree, except_keys_count, - max_element_size + max_element_size, + grove_version ) ); ops.push(op); @@ -132,8 +117,8 @@ impl GroveDb { } } - /// Worst case costs for delete operation for delete internal - pub fn worst_case_delete_operation_for_delete_internal<'db, S: Storage<'db>>( + /// Worst case costs for delete operation for delete + pub fn worst_case_delete_operation_for_delete<'db, S: Storage<'db>>( path: &KeyInfoPath, key: &KeyInfo, parent_tree_is_sum_tree: bool, @@ -141,19 +126,40 @@ impl GroveDb { check_if_tree: bool, except_keys_count: u16, max_element_size: u32, + grove_version: &GroveVersion, ) -> CostResult { + check_grovedb_v0_with_cost!( + "worst_case_delete_operation_for_delete", + grove_version + .grovedb_versions + .operations + .delete + .worst_case_delete_operation_for_delete + ); let mut cost = OperationCost::default(); if validate { - GroveDb::add_worst_case_get_merk_at_path::(&mut cost, path, parent_tree_is_sum_tree); + cost_return_on_error_no_add!( + &cost, + GroveDb::add_worst_case_get_merk_at_path::( + &mut cost, + path, + parent_tree_is_sum_tree, + grove_version, + ) + ); } if check_if_tree { - GroveDb::add_worst_case_get_raw_cost::( - &mut cost, - path, - key, - max_element_size, - parent_tree_is_sum_tree, + cost_return_on_error_no_add!( + &cost, + GroveDb::add_worst_case_get_raw_cost::( + &mut cost, + path, + key, + max_element_size, + parent_tree_is_sum_tree, + grove_version, + ) ); } // in the worst case this is a tree diff --git a/grovedb/src/operations/get/average_case.rs b/grovedb/src/operations/get/average_case.rs index 4a6ee2ee..aca4426d 100644 --- a/grovedb/src/operations/get/average_case.rs +++ b/grovedb/src/operations/get/average_case.rs @@ -1,38 +1,12 @@ -// 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. - //! Average case get costs #[cfg(feature = "full")] use grovedb_costs::OperationCost; #[cfg(feature = "full")] use grovedb_storage::rocksdb_storage::RocksDbStorage; +use grovedb_version::{check_grovedb_v0, error::GroveVersionError, version::GroveVersion}; +use crate::Error; #[cfg(feature = "full")] use crate::{ batch::{key_info::KeyInfo, KeyInfoPath}, @@ -48,7 +22,16 @@ impl GroveDb { key: &KeyInfo, estimated_element_size: u32, in_parent_tree_using_sums: bool, - ) -> OperationCost { + grove_version: &GroveVersion, + ) -> Result { + check_grovedb_v0!( + "average_case_for_has_raw", + grove_version + .grovedb_versions + .operations + .get + .average_case_for_has_raw + ); let mut cost = OperationCost::default(); GroveDb::add_average_case_has_raw_cost::( &mut cost, @@ -56,8 +39,9 @@ impl GroveDb { key, estimated_element_size, in_parent_tree_using_sums, - ); - cost + grove_version, + )?; + Ok(cost) } /// Get the Operation Cost for a has query where we estimate that we @@ -68,7 +52,16 @@ impl GroveDb { estimated_flags_size: u32, is_sum_tree: bool, in_parent_tree_using_sums: bool, - ) -> OperationCost { + grove_version: &GroveVersion, + ) -> Result { + check_grovedb_v0!( + "average_case_for_has_raw_tree", + grove_version + .grovedb_versions + .operations + .get + .average_case_for_has_raw_tree + ); let mut cost = OperationCost::default(); GroveDb::add_average_case_has_raw_tree_cost::( &mut cost, @@ -77,8 +70,9 @@ impl GroveDb { estimated_flags_size, is_sum_tree, in_parent_tree_using_sums, - ); - cost + grove_version, + )?; + Ok(cost) } /// Get the Operation Cost for a get query that doesn't follow @@ -88,7 +82,16 @@ impl GroveDb { key: &KeyInfo, estimated_element_size: u32, in_parent_tree_using_sums: bool, - ) -> OperationCost { + grove_version: &GroveVersion, + ) -> Result { + check_grovedb_v0!( + "average_case_for_get_raw", + grove_version + .grovedb_versions + .operations + .get + .average_case_for_get_raw + ); let mut cost = OperationCost::default(); GroveDb::add_average_case_get_raw_cost::( &mut cost, @@ -96,8 +99,9 @@ impl GroveDb { key, estimated_element_size, in_parent_tree_using_sums, - ); - cost + grove_version, + )?; + Ok(cost) } /// Get the Operation Cost for a get query with the following parameters @@ -107,7 +111,16 @@ impl GroveDb { in_parent_tree_using_sums: bool, estimated_element_size: u32, estimated_references_sizes: Vec, - ) -> OperationCost { + grove_version: &GroveVersion, + ) -> Result { + check_grovedb_v0!( + "average_case_for_get", + grove_version + .grovedb_versions + .operations + .get + .average_case_for_get + ); let mut cost = OperationCost::default(); GroveDb::add_average_case_get_cost::( &mut cost, @@ -116,8 +129,9 @@ impl GroveDb { in_parent_tree_using_sums, estimated_element_size, estimated_references_sizes, - ); - cost + grove_version, + )?; + Ok(cost) } /// Get the Operation Cost for a get query with the following parameters @@ -127,7 +141,16 @@ impl GroveDb { estimated_flags_size: u32, is_sum_tree: bool, in_parent_tree_using_sums: bool, - ) -> OperationCost { + grove_version: &GroveVersion, + ) -> Result { + check_grovedb_v0!( + "average_case_for_get", + grove_version + .grovedb_versions + .operations + .get + .average_case_for_get_tree + ); let mut cost = OperationCost::default(); GroveDb::add_average_case_get_raw_tree_cost::( &mut cost, @@ -136,7 +159,8 @@ impl GroveDb { estimated_flags_size, is_sum_tree, in_parent_tree_using_sums, - ); - cost + grove_version, + )?; + Ok(cost) } } diff --git a/grovedb/src/operations/get/mod.rs b/grovedb/src/operations/get/mod.rs index 4cc9f949..b6289699 100644 --- a/grovedb/src/operations/get/mod.rs +++ b/grovedb/src/operations/get/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. - //! Get operations and costs #[cfg(feature = "estimated_costs")] @@ -46,6 +18,9 @@ use grovedb_costs::{cost_return_on_error, CostResult, CostsExt, OperationCost}; use grovedb_path::SubtreePath; #[cfg(feature = "full")] use grovedb_storage::StorageContext; +use grovedb_version::{ + check_grovedb_v0_with_cost, error::GroveVersionError, version::GroveVersion, +}; #[cfg(feature = "full")] use crate::{ @@ -68,12 +43,15 @@ impl GroveDb { path: P, key: &[u8], transaction: TransactionArg, + grove_version: &GroveVersion, ) -> CostResult where B: AsRef<[u8]> + 'b, P: Into>, { - self.get_caching_optional(path.into(), key, true, transaction) + check_grovedb_v0_with_cost!("get", grove_version.grovedb_versions.operations.get.get); + + self.get_caching_optional(path.into(), key, true, transaction, grove_version) } /// Get an element from the backing store @@ -84,12 +62,28 @@ impl GroveDb { key: &[u8], allow_cache: bool, transaction: TransactionArg, + grove_version: &GroveVersion, ) -> CostResult { + check_grovedb_v0_with_cost!( + "get_caching_optional", + grove_version + .grovedb_versions + .operations + .get + .get_caching_optional + ); + let mut cost = OperationCost::default(); match cost_return_on_error!( &mut cost, - self.get_raw_caching_optional(path.clone(), key, allow_cache, transaction) + self.get_raw_caching_optional( + path.clone(), + key, + allow_cache, + transaction, + grove_version + ) ) { Element::Reference(reference_path, ..) => { let path_owned = cost_return_on_error!( @@ -97,8 +91,13 @@ impl GroveDb { path_from_reference_path_type(reference_path, &path.to_vec(), Some(key)) .wrap_with_cost(OperationCost::default()) ); - self.follow_reference(path_owned.as_slice().into(), allow_cache, transaction) - .add_cost(cost) + self.follow_reference( + path_owned.as_slice().into(), + allow_cache, + transaction, + grove_version, + ) + .add_cost(cost) } other => Ok(other).wrap_with_cost(cost), } @@ -112,7 +111,17 @@ impl GroveDb { path: SubtreePath, allow_cache: bool, transaction: TransactionArg, + grove_version: &GroveVersion, ) -> CostResult { + check_grovedb_v0_with_cost!( + "follow_reference", + grove_version + .grovedb_versions + .operations + .get + .follow_reference + ); + let mut cost = OperationCost::default(); let mut hops_left = MAX_REFERENCE_HOPS; @@ -128,19 +137,25 @@ impl GroveDb { if let Some((key, path_slice)) = current_path.split_last() { current_element = cost_return_on_error!( &mut cost, - self.get_raw_caching_optional(path_slice.into(), key, allow_cache, transaction) - .map_err(|e| match e { - Error::PathParentLayerNotFound(p) => { - Error::CorruptedReferencePathParentLayerNotFound(p) - } - Error::PathKeyNotFound(p) => { - Error::CorruptedReferencePathKeyNotFound(p) - } - Error::PathNotFound(p) => { - Error::CorruptedReferencePathNotFound(p) - } - _ => e, - }) + self.get_raw_caching_optional( + path_slice.into(), + key, + allow_cache, + transaction, + grove_version + ) + .map_err(|e| match e { + Error::PathParentLayerNotFound(p) => { + Error::CorruptedReferencePathParentLayerNotFound(p) + } + Error::PathKeyNotFound(p) => { + Error::CorruptedReferencePathKeyNotFound(p) + } + Error::PathNotFound(p) => { + Error::CorruptedReferencePathNotFound(p) + } + _ => e, + }) ) } else { return Err(Error::CorruptedPath("empty path".to_string())).wrap_with_cost(cost); @@ -168,8 +183,14 @@ impl GroveDb { path: SubtreePath, key: &[u8], transaction: TransactionArg, + grove_version: &GroveVersion, ) -> CostResult { - self.get_raw_caching_optional(path, key, true, transaction) + check_grovedb_v0_with_cost!( + "get_raw", + grove_version.grovedb_versions.operations.get.get_raw + ); + + self.get_raw_caching_optional(path, key, true, transaction, grove_version) } /// Get tree item without following references @@ -179,11 +200,27 @@ impl GroveDb { key: &[u8], allow_cache: bool, transaction: TransactionArg, + grove_version: &GroveVersion, ) -> CostResult { + check_grovedb_v0_with_cost!( + "get_raw_caching_optional", + grove_version + .grovedb_versions + .operations + .get + .get_raw_caching_optional + ); + if let Some(transaction) = transaction { - self.get_raw_on_transaction_caching_optional(path, key, allow_cache, transaction) + self.get_raw_on_transaction_caching_optional( + path, + key, + allow_cache, + transaction, + grove_version, + ) } else { - self.get_raw_without_transaction_caching_optional(path, key, allow_cache) + self.get_raw_without_transaction_caching_optional(path, key, allow_cache, grove_version) } } @@ -195,8 +232,18 @@ impl GroveDb { path: SubtreePath, key: &[u8], transaction: TransactionArg, + grove_version: &GroveVersion, ) -> CostResult, Error> { - self.get_raw_optional_caching_optional(path, key, true, transaction) + check_grovedb_v0_with_cost!( + "get_raw_optional", + grove_version + .grovedb_versions + .operations + .get + .get_raw_optional + ); + + self.get_raw_optional_caching_optional(path, key, true, transaction, grove_version) } /// Get tree item without following references @@ -206,16 +253,32 @@ impl GroveDb { key: &[u8], allow_cache: bool, transaction: TransactionArg, + grove_version: &GroveVersion, ) -> CostResult, Error> { + check_grovedb_v0_with_cost!( + "get_raw_optional_caching_optional", + grove_version + .grovedb_versions + .operations + .get + .get_raw_optional_caching_optional + ); + if let Some(transaction) = transaction { self.get_raw_optional_on_transaction_caching_optional( path, key, allow_cache, transaction, + grove_version, ) } else { - self.get_raw_optional_without_transaction_caching_optional(path, key, allow_cache) + self.get_raw_optional_without_transaction_caching_optional( + path, + key, + allow_cache, + grove_version, + ) } } @@ -226,12 +289,13 @@ impl GroveDb { key: &[u8], allow_cache: bool, transaction: &Transaction, + grove_version: &GroveVersion, ) -> CostResult { let mut cost = OperationCost::default(); let merk_to_get_from = cost_return_on_error!( &mut cost, - self.open_transactional_merk_at_path(path, transaction, None) + self.open_transactional_merk_at_path(path, transaction, None, grove_version) .map_err(|e| match e { Error::InvalidParentLayerPath(s) => { Error::PathParentLayerNotFound(s) @@ -240,7 +304,7 @@ impl GroveDb { }) ); - Element::get(&merk_to_get_from, key, allow_cache).add_cost(cost) + Element::get(&merk_to_get_from, key, allow_cache, grove_version).add_cost(cost) } /// Get tree item without following references @@ -250,10 +314,11 @@ impl GroveDb { key: &[u8], allow_cache: bool, transaction: &Transaction, + grove_version: &GroveVersion, ) -> CostResult, Error> { let mut cost = OperationCost::default(); let merk_result = self - .open_transactional_merk_at_path(path, transaction, None) + .open_transactional_merk_at_path(path, transaction, None, grove_version) .map_err(|e| match e { Error::InvalidParentLayerPath(s) => Error::PathParentLayerNotFound(s), _ => e, @@ -270,7 +335,7 @@ impl GroveDb { ); if let Some(merk_to_get_from) = merk { - Element::get_optional(&merk_to_get_from, key, allow_cache).add_cost(cost) + Element::get_optional(&merk_to_get_from, key, allow_cache, grove_version).add_cost(cost) } else { Ok(None).wrap_with_cost(cost) } @@ -282,12 +347,13 @@ impl GroveDb { path: SubtreePath, key: &[u8], allow_cache: bool, + grove_version: &GroveVersion, ) -> CostResult { let mut cost = OperationCost::default(); let merk_to_get_from = cost_return_on_error!( &mut cost, - self.open_non_transactional_merk_at_path(path, None) + self.open_non_transactional_merk_at_path(path, None, grove_version) .map_err(|e| match e { Error::InvalidParentLayerPath(s) => { Error::PathParentLayerNotFound(s) @@ -296,7 +362,7 @@ impl GroveDb { }) ); - Element::get(&merk_to_get_from, key, allow_cache).add_cost(cost) + Element::get(&merk_to_get_from, key, allow_cache, grove_version).add_cost(cost) } /// Get tree item without following references @@ -305,11 +371,12 @@ impl GroveDb { path: SubtreePath, key: &[u8], allow_cache: bool, + grove_version: &GroveVersion, ) -> CostResult, Error> { let mut cost = OperationCost::default(); let merk_result = self - .open_non_transactional_merk_at_path(path, None) + .open_non_transactional_merk_at_path(path, None, grove_version) .map_err(|e| match e { Error::InvalidParentLayerPath(s) => Error::PathParentLayerNotFound(s), _ => e, @@ -326,7 +393,7 @@ impl GroveDb { ); if let Some(merk_to_get_from) = merk { - Element::get_optional(&merk_to_get_from, key, allow_cache).add_cost(cost) + Element::get_optional(&merk_to_get_from, key, allow_cache, grove_version).add_cost(cost) } else { Ok(None).wrap_with_cost(cost) } @@ -339,11 +406,17 @@ impl GroveDb { path: P, key: &[u8], transaction: TransactionArg, + grove_version: &GroveVersion, ) -> CostResult where B: AsRef<[u8]> + 'b, P: Into>, { + check_grovedb_v0_with_cost!( + "has_raw", + grove_version.grovedb_versions.operations.get.has_raw + ); + // Merk's items should be written into data storage and checked accordingly storage_context_optional_tx!(self.db, path.into(), None, transaction, storage, { storage.flat_map(|s| s.get(key).map_err(|e| e.into()).map_ok(|x| x.is_some())) @@ -355,6 +428,7 @@ impl GroveDb { path: SubtreePath, transaction: TransactionArg, error_fn: impl FnOnce() -> Error, + grove_version: &GroveVersion, ) -> CostResult<(), Error> { let mut cost = OperationCost::default(); @@ -362,17 +436,22 @@ impl GroveDb { let element = if let Some(transaction) = transaction { let merk_to_get_from = cost_return_on_error!( &mut cost, - self.open_transactional_merk_at_path(parent_path, transaction, None) + self.open_transactional_merk_at_path( + parent_path, + transaction, + None, + grove_version + ) ); - Element::get(&merk_to_get_from, parent_key, true) + Element::get(&merk_to_get_from, parent_key, true, grove_version) } else { let merk_to_get_from = cost_return_on_error!( &mut cost, - self.open_non_transactional_merk_at_path(parent_path, None) + self.open_non_transactional_merk_at_path(parent_path, None, grove_version) ); - Element::get(&merk_to_get_from, parent_key, true) + Element::get(&merk_to_get_from, parent_key, true, grove_version) } .unwrap_add_cost(&mut cost); match element { @@ -390,19 +469,25 @@ impl GroveDb { &self, path: SubtreePath<'b, B>, transaction: TransactionArg, + grove_version: &GroveVersion, ) -> CostResult<(), Error> where B: AsRef<[u8]> + 'b, { - self.check_subtree_exists(path.clone(), transaction, || { - Error::PathNotFound(format!( - "subtree doesn't exist at path {:?}", - path.to_vec() - .into_iter() - .map(hex::encode) - .collect::>() - )) - }) + self.check_subtree_exists( + path.clone(), + transaction, + || { + Error::PathNotFound(format!( + "subtree doesn't exist at path {:?}", + path.to_vec() + .into_iter() + .map(hex::encode) + .collect::>() + )) + }, + grove_version, + ) } /// Check subtree exists with invalid path error @@ -410,9 +495,22 @@ impl GroveDb { &self, path: SubtreePath, transaction: TransactionArg, + grove_version: &GroveVersion, ) -> CostResult<(), Error> { - self.check_subtree_exists(path, transaction, || { - Error::InvalidPath("subtree doesn't exist".to_owned()) - }) + check_grovedb_v0_with_cost!( + "check_subtree_exists_invalid_path", + grove_version + .grovedb_versions + .operations + .get + .check_subtree_exists_invalid_path + ); + + self.check_subtree_exists( + path, + transaction, + || Error::InvalidPath("subtree doesn't exist".to_owned()), + grove_version, + ) } } diff --git a/grovedb/src/operations/get/query.rs b/grovedb/src/operations/get/query.rs index 6ba914ef..81046dbf 100644 --- a/grovedb/src/operations/get/query.rs +++ b/grovedb/src/operations/get/query.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. - //! Query operations use grovedb_costs::cost_return_on_error_default; @@ -33,6 +5,9 @@ use grovedb_costs::cost_return_on_error_default; use grovedb_costs::{ cost_return_on_error, cost_return_on_error_no_add, CostResult, CostsExt, OperationCost, }; +use grovedb_version::{ + check_grovedb_v0, check_grovedb_v0_with_cost, error::GroveVersionError, version::GroveVersion, +}; #[cfg(feature = "full")] use integer_encoding::VarInt; @@ -69,7 +44,17 @@ impl GroveDb { decrease_limit_on_range_with_no_sub_elements: bool, error_if_intermediate_path_tree_not_present: bool, transaction: TransactionArg, + grove_version: &GroveVersion, ) -> CostResult>, Error> { + check_grovedb_v0_with_cost!( + "query_encoded_many", + grove_version + .grovedb_versions + .operations + .query + .query_encoded_many + ); + let mut cost = OperationCost::default(); let elements = cost_return_on_error!( @@ -80,7 +65,8 @@ impl GroveDb { decrease_limit_on_range_with_no_sub_elements, error_if_intermediate_path_tree_not_present, QueryResultType::QueryElementResultType, - transaction + transaction, + grove_version ) ); let results_wrapped = elements @@ -98,6 +84,7 @@ impl GroveDb { absolute_path.as_slice().into(), allow_cache, transaction, + grove_version, ) .unwrap_add_cost(&mut cost)?; @@ -132,11 +119,23 @@ impl GroveDb { error_if_intermediate_path_tree_not_present: bool, result_type: QueryResultType, transaction: TransactionArg, + grove_version: &GroveVersion, ) -> CostResult where { + check_grovedb_v0_with_cost!( + "query_many_raw", + grove_version + .grovedb_versions + .operations + .query + .query_many_raw + ); let mut cost = OperationCost::default(); - let query = cost_return_on_error_no_add!(&cost, PathQuery::merge(path_queries.to_vec())); + let query = cost_return_on_error_no_add!( + &cost, + PathQuery::merge(path_queries.to_vec(), grove_version) + ); let (result, _) = cost_return_on_error!( &mut cost, self.query_raw( @@ -145,26 +144,36 @@ where { decrease_limit_on_range_with_no_sub_elements, error_if_intermediate_path_tree_not_present, result_type, - transaction + transaction, + grove_version ) ); Ok(result).wrap_with_cost(cost) } - /// Prove a path query as either verbose or non verbose + /// Prove a path query as either verbose or non-verbose pub fn get_proved_path_query( &self, path_query: &PathQuery, prove_options: Option, transaction: TransactionArg, + grove_version: &GroveVersion, ) -> CostResult, Error> { + check_grovedb_v0_with_cost!( + "get_proved_path_query", + grove_version + .grovedb_versions + .operations + .query + .get_proved_path_query + ); if transaction.is_some() { Err(Error::NotSupported( "transactions are not currently supported".to_string(), )) .wrap_with_cost(Default::default()) } else { - self.prove_query(path_query, prove_options) + self.prove_query(path_query, prove_options, grove_version) } } @@ -174,7 +183,16 @@ where { allow_cache: bool, cost: &mut OperationCost, transaction: TransactionArg, + grove_version: &GroveVersion, ) -> Result { + check_grovedb_v0!( + "follow_element", + grove_version + .grovedb_versions + .operations + .query + .follow_element + ); match element { Element::Reference(reference_path, ..) => { match reference_path { @@ -189,6 +207,7 @@ where { absolute_path.as_slice().into(), allow_cache, transaction, + grove_version, ) .unwrap_add_cost(cost)?; @@ -217,7 +236,12 @@ where { error_if_intermediate_path_tree_not_present: bool, result_type: QueryResultType, transaction: TransactionArg, + grove_version: &GroveVersion, ) -> CostResult<(QueryResultElements, u16), Error> { + check_grovedb_v0_with_cost!( + "query", + grove_version.grovedb_versions.operations.query.query + ); let mut cost = OperationCost::default(); let (elements, skipped) = cost_return_on_error!( @@ -228,7 +252,8 @@ where { decrease_limit_on_range_with_no_sub_elements, error_if_intermediate_path_tree_not_present, result_type, - transaction + transaction, + grove_version ) ); @@ -236,7 +261,7 @@ where { .into_iterator() .map(|result_item| { result_item.map_element(|element| { - self.follow_element(element, allow_cache, &mut cost, transaction) + self.follow_element(element, allow_cache, &mut cost, transaction, grove_version) }) }) .collect::, Error>>(); @@ -254,7 +279,16 @@ where { decrease_limit_on_range_with_no_sub_elements: bool, error_if_intermediate_path_tree_not_present: bool, transaction: TransactionArg, + grove_version: &GroveVersion, ) -> CostResult<(Vec>, u16), Error> { + check_grovedb_v0_with_cost!( + "query_item_value", + grove_version + .grovedb_versions + .operations + .query + .query_item_value + ); let mut cost = OperationCost::default(); let (elements, skipped) = cost_return_on_error!( @@ -265,7 +299,8 @@ where { decrease_limit_on_range_with_no_sub_elements, error_if_intermediate_path_tree_not_present, QueryResultType::QueryElementResultType, - transaction + transaction, + grove_version ) ); @@ -287,6 +322,7 @@ where { absolute_path.as_slice().into(), allow_cache, transaction, + grove_version, ) .unwrap_add_cost(&mut cost)?; @@ -329,7 +365,16 @@ where { decrease_limit_on_range_with_no_sub_elements: bool, error_if_intermediate_path_tree_not_present: bool, transaction: TransactionArg, + grove_version: &GroveVersion, ) -> CostResult<(Vec, u16), Error> { + check_grovedb_v0_with_cost!( + "query_item_value_or_sum", + grove_version + .grovedb_versions + .operations + .query + .query_item_value_or_sum + ); let mut cost = OperationCost::default(); let (elements, skipped) = cost_return_on_error!( @@ -340,7 +385,8 @@ where { decrease_limit_on_range_with_no_sub_elements, error_if_intermediate_path_tree_not_present, QueryResultType::QueryElementResultType, - transaction + transaction, + grove_version ) ); @@ -362,6 +408,7 @@ where { absolute_path.as_slice().into(), allow_cache, transaction, + grove_version, ) .unwrap_add_cost(&mut cost)?; @@ -416,7 +463,12 @@ where { decrease_limit_on_range_with_no_sub_elements: bool, error_if_intermediate_path_tree_not_present: bool, transaction: TransactionArg, + grove_version: &GroveVersion, ) -> CostResult<(Vec, u16), Error> { + check_grovedb_v0_with_cost!( + "query_sums", + grove_version.grovedb_versions.operations.query.query_sums + ); let mut cost = OperationCost::default(); let (elements, skipped) = cost_return_on_error!( @@ -427,7 +479,8 @@ where { decrease_limit_on_range_with_no_sub_elements, error_if_intermediate_path_tree_not_present, QueryResultType::QueryElementResultType, - transaction + transaction, + grove_version ) ); @@ -449,6 +502,7 @@ where { absolute_path.as_slice().into(), allow_cache, transaction, + grove_version, ) .unwrap_add_cost(&mut cost)?; @@ -493,7 +547,12 @@ where { error_if_intermediate_path_tree_not_present: bool, result_type: QueryResultType, transaction: TransactionArg, + grove_version: &GroveVersion, ) -> CostResult<(QueryResultElements, u16), Error> { + check_grovedb_v0_with_cost!( + "query_raw", + grove_version.grovedb_versions.operations.query.query_raw + ); Element::get_path_query( &self.db, path_query, @@ -505,6 +564,7 @@ where { }, result_type, transaction, + grove_version, ) } @@ -517,7 +577,16 @@ where { decrease_limit_on_range_with_no_sub_elements: bool, error_if_intermediate_path_tree_not_present: bool, transaction: TransactionArg, + grove_version: &GroveVersion, ) -> CostResult, Error> { + check_grovedb_v0_with_cost!( + "query_keys_optional", + grove_version + .grovedb_versions + .operations + .query + .query_keys_optional + ); let max_results = cost_return_on_error_default!(path_query.query.limit.ok_or( Error::NotSupported("limits must be set in query_keys_optional".to_string()) )) as usize; @@ -529,8 +598,10 @@ where { } let mut cost = OperationCost::default(); - let terminal_keys = - cost_return_on_error_no_add!(&cost, path_query.terminal_keys(max_results)); + let terminal_keys = cost_return_on_error_no_add!( + &cost, + path_query.terminal_keys(max_results, grove_version) + ); let (elements, _) = cost_return_on_error!( &mut cost, @@ -540,7 +611,8 @@ where { decrease_limit_on_range_with_no_sub_elements, error_if_intermediate_path_tree_not_present, QueryResultType::QueryPathKeyElementTrioResultType, - transaction + transaction, + grove_version ) ); @@ -564,7 +636,16 @@ where { decrease_limit_on_range_with_no_sub_elements: bool, error_if_intermediate_path_tree_not_present: bool, transaction: TransactionArg, + grove_version: &GroveVersion, ) -> CostResult, Error> { + check_grovedb_v0_with_cost!( + "query_raw_keys_optional", + grove_version + .grovedb_versions + .operations + .query + .query_raw_keys_optional + ); let max_results = cost_return_on_error_default!(path_query.query.limit.ok_or( Error::NotSupported("limits must be set in query_raw_keys_optional".to_string()) )) as usize; @@ -576,8 +657,10 @@ where { } let mut cost = OperationCost::default(); - let terminal_keys = - cost_return_on_error_no_add!(&cost, path_query.terminal_keys(max_results)); + let terminal_keys = cost_return_on_error_no_add!( + &cost, + path_query.terminal_keys(max_results, grove_version) + ); let (elements, _) = cost_return_on_error!( &mut cost, @@ -587,7 +670,8 @@ where { decrease_limit_on_range_with_no_sub_elements, error_if_intermediate_path_tree_not_present, QueryResultType::QueryPathKeyElementTrioResultType, - transaction + transaction, + grove_version ) ); @@ -610,6 +694,7 @@ mod tests { use std::collections::HashMap; use grovedb_merk::proofs::{query::query_item::QueryItem, Query}; + use grovedb_version::version::GroveVersion; use pretty_assertions::assert_eq; use crate::{ @@ -620,7 +705,8 @@ mod tests { #[test] fn test_query_raw_keys_options() { - let db = make_test_grovedb(); + let grove_version = GroveVersion::latest(); + let db = make_test_grovedb(grove_version); db.insert( [TEST_LEAF].as_ref(), @@ -628,6 +714,7 @@ mod tests { Element::new_item(b"hello".to_vec()), None, None, + grove_version, ) .unwrap() .expect("should insert subtree successfully"); @@ -637,6 +724,7 @@ mod tests { Element::new_item(b"hello too".to_vec()), None, None, + grove_version, ) .unwrap() .expect("should insert subtree successfully"); @@ -646,6 +734,7 @@ mod tests { Element::new_item(b"bye".to_vec()), None, None, + grove_version, ) .unwrap() .expect("should insert subtree successfully"); @@ -657,7 +746,7 @@ mod tests { let path = vec![TEST_LEAF.to_vec()]; let path_query = PathQuery::new(path.clone(), SizedQuery::new(query, Some(5), None)); let raw_result = db - .query_raw_keys_optional(&path_query, true, true, true, None) + .query_raw_keys_optional(&path_query, true, true, true, None, GroveVersion::latest()) .unwrap() .expect("should get successfully"); @@ -677,7 +766,8 @@ mod tests { #[test] fn test_query_raw_keys_options_with_range() { - let db = make_test_grovedb(); + let grove_version = GroveVersion::latest(); + let db = make_test_grovedb(grove_version); db.insert( [TEST_LEAF].as_ref(), @@ -685,6 +775,7 @@ mod tests { Element::new_item(b"hello".to_vec()), None, None, + grove_version, ) .unwrap() .expect("should insert subtree successfully"); @@ -694,6 +785,7 @@ mod tests { Element::new_item(b"hello too".to_vec()), None, None, + grove_version, ) .unwrap() .expect("should insert subtree successfully"); @@ -703,6 +795,7 @@ mod tests { Element::new_item(b"bye".to_vec()), None, None, + grove_version, ) .unwrap() .expect("should insert subtree successfully"); @@ -713,7 +806,7 @@ mod tests { let path = vec![TEST_LEAF.to_vec()]; let path_query = PathQuery::new(path.clone(), SizedQuery::new(query, Some(5), None)); let raw_result = db - .query_raw_keys_optional(&path_query, true, true, true, None) + .query_raw_keys_optional(&path_query, true, true, true, None, GroveVersion::latest()) .unwrap() .expect("should get successfully"); @@ -734,7 +827,8 @@ mod tests { #[test] fn test_query_raw_keys_options_with_range_inclusive() { - let db = make_test_grovedb(); + let grove_version = GroveVersion::latest(); + let db = make_test_grovedb(grove_version); db.insert( [TEST_LEAF].as_ref(), @@ -742,6 +836,7 @@ mod tests { Element::new_item(b"hello".to_vec()), None, None, + grove_version, ) .unwrap() .expect("should insert subtree successfully"); @@ -751,6 +846,7 @@ mod tests { Element::new_item(b"hello too".to_vec()), None, None, + grove_version, ) .unwrap() .expect("should insert subtree successfully"); @@ -760,6 +856,7 @@ mod tests { Element::new_item(b"bye".to_vec()), None, None, + grove_version, ) .unwrap() .expect("should insert subtree successfully"); @@ -770,7 +867,7 @@ mod tests { let path = vec![TEST_LEAF.to_vec()]; let path_query = PathQuery::new(path.clone(), SizedQuery::new(query, Some(5), None)); let raw_result = db - .query_raw_keys_optional(&path_query, true, true, true, None) + .query_raw_keys_optional(&path_query, true, true, true, None, GroveVersion::latest()) .unwrap() .expect("should get successfully"); @@ -794,7 +891,8 @@ mod tests { #[test] fn test_query_raw_keys_options_with_range_bounds() { - let db = make_test_grovedb(); + let grove_version = GroveVersion::latest(); + let db = make_test_grovedb(grove_version); db.insert( [TEST_LEAF].as_ref(), @@ -802,6 +900,7 @@ mod tests { Element::new_item(b"empty".to_vec()), None, None, + grove_version, ) .unwrap() .expect("should insert subtree successfully"); @@ -811,6 +910,7 @@ mod tests { Element::new_item(b"hello".to_vec()), None, None, + grove_version, ) .unwrap() .expect("should insert subtree successfully"); @@ -820,6 +920,7 @@ mod tests { Element::new_item(b"hello too".to_vec()), None, None, + grove_version, ) .unwrap() .expect("should insert subtree successfully"); @@ -829,6 +930,7 @@ mod tests { Element::new_item(b"bye".to_vec()), None, None, + grove_version, ) .unwrap() .expect("should insert subtree successfully"); @@ -838,7 +940,7 @@ mod tests { let path = vec![TEST_LEAF.to_vec()]; let path_query = PathQuery::new(path, SizedQuery::new(query, Some(4), None)); - db.query_raw_keys_optional(&path_query, true, true, true, None) + db.query_raw_keys_optional(&path_query, true, true, true, None, GroveVersion::latest()) .unwrap() .expect_err("range a should error"); @@ -847,7 +949,7 @@ mod tests { query.insert_key(b"5".to_vec()); // 3 let path = vec![TEST_LEAF.to_vec()]; let path_query = PathQuery::new(path, SizedQuery::new(query, Some(3), None)); - db.query_raw_keys_optional(&path_query, true, true, true, None) + db.query_raw_keys_optional(&path_query, true, true, true, None, GroveVersion::latest()) .unwrap() .expect("range b should not error"); @@ -856,7 +958,7 @@ mod tests { query.insert_key(b"5".to_vec()); // 4 let path = vec![TEST_LEAF.to_vec()]; let path_query = PathQuery::new(path, SizedQuery::new(query, Some(3), None)); - db.query_raw_keys_optional(&path_query, true, true, true, None) + db.query_raw_keys_optional(&path_query, true, true, true, None, GroveVersion::latest()) .unwrap() .expect_err("range c should error"); @@ -865,7 +967,7 @@ mod tests { query.insert_key(b"5".to_vec()); // 3 let path = vec![TEST_LEAF.to_vec()]; let path_query = PathQuery::new(path, SizedQuery::new(query, Some(2), None)); - db.query_raw_keys_optional(&path_query, true, true, true, None) + db.query_raw_keys_optional(&path_query, true, true, true, None, GroveVersion::latest()) .unwrap() .expect_err("range d should error"); @@ -873,14 +975,15 @@ mod tests { query.insert_range(b"z".to_vec()..b"10".to_vec()); let path = vec![TEST_LEAF.to_vec()]; let path_query = PathQuery::new(path, SizedQuery::new(query, Some(1000), None)); - db.query_raw_keys_optional(&path_query, true, true, true, None) + db.query_raw_keys_optional(&path_query, true, true, true, None, GroveVersion::latest()) .unwrap() .expect_err("range using 2 bytes should error"); } #[test] fn test_query_raw_keys_options_with_empty_start_range() { - let db = make_test_grovedb(); + let grove_version = GroveVersion::latest(); + let db = make_test_grovedb(grove_version); db.insert( [TEST_LEAF].as_ref(), @@ -888,6 +991,7 @@ mod tests { Element::new_item(b"empty".to_vec()), None, None, + grove_version, ) .unwrap() .expect("should insert subtree successfully"); @@ -897,6 +1001,7 @@ mod tests { Element::new_item(b"hello".to_vec()), None, None, + grove_version, ) .unwrap() .expect("should insert subtree successfully"); @@ -906,6 +1011,7 @@ mod tests { Element::new_item(b"hello too".to_vec()), None, None, + grove_version, ) .unwrap() .expect("should insert subtree successfully"); @@ -915,6 +1021,7 @@ mod tests { Element::new_item(b"bye".to_vec()), None, None, + grove_version, ) .unwrap() .expect("should insert subtree successfully"); @@ -924,7 +1031,7 @@ mod tests { let path = vec![TEST_LEAF.to_vec()]; let path_query = PathQuery::new(path.clone(), SizedQuery::new(query, Some(1000), None)); let raw_result = db - .query_raw_keys_optional(&path_query, true, true, true, None) + .query_raw_keys_optional(&path_query, true, true, true, None, GroveVersion::latest()) .unwrap() .expect("range starting with null should not error"); @@ -952,17 +1059,26 @@ mod tests { #[test] fn test_query_raw_keys_options_with_subquery_path() { - let db = make_test_grovedb(); + let grove_version = GroveVersion::latest(); + let db = make_test_grovedb(grove_version); - db.insert([TEST_LEAF].as_ref(), b"", Element::empty_tree(), None, None) - .unwrap() - .expect("should insert subtree successfully"); + db.insert( + [TEST_LEAF].as_ref(), + b"", + Element::empty_tree(), + None, + None, + grove_version, + ) + .unwrap() + .expect("should insert subtree successfully"); db.insert( [TEST_LEAF, b""].as_ref(), b"", Element::new_item(b"null in null".to_vec()), None, None, + grove_version, ) .unwrap() .expect("should insert subtree successfully"); @@ -972,6 +1088,7 @@ mod tests { Element::new_item(b"1 in null".to_vec()), None, None, + grove_version, ) .unwrap() .expect("should insert subtree successfully"); @@ -981,6 +1098,7 @@ mod tests { Element::empty_tree(), None, None, + grove_version, ) .unwrap() .expect("should insert subtree successfully"); @@ -990,6 +1108,7 @@ mod tests { Element::new_item(b"1 in 2".to_vec()), None, None, + grove_version, ) .unwrap() .expect("should insert subtree successfully"); @@ -999,6 +1118,7 @@ mod tests { Element::new_item(b"5 in 2".to_vec()), None, None, + grove_version, ) .unwrap() .expect("should insert subtree successfully"); @@ -1007,7 +1127,7 @@ mod tests { query.insert_range(b"".to_vec()..b"c".to_vec()); let path = vec![TEST_LEAF.to_vec()]; let path_query = PathQuery::new(path, SizedQuery::new(query, Some(1000), None)); - db.query_keys_optional(&path_query, true, true, true, None) + db.query_keys_optional(&path_query, true, true, true, None, GroveVersion::latest()) .unwrap() .expect_err("range should error because we didn't subquery"); @@ -1017,7 +1137,7 @@ mod tests { let path = vec![TEST_LEAF.to_vec()]; let path_query = PathQuery::new(path, SizedQuery::new(query, Some(1000), None)); let raw_result = db - .query_raw_keys_optional(&path_query, true, true, true, None) + .query_raw_keys_optional(&path_query, true, true, true, None, GroveVersion::latest()) .unwrap() .expect("query with subquery should not error"); @@ -1038,7 +1158,7 @@ mod tests { assert_eq!( raw_result.get(&(vec![TEST_LEAF.to_vec(), b"4".to_vec()], b"1".to_vec())), Some(&None) - ); // because we are subquerying 1 + ); // because we are sub-querying 1 assert_eq!( raw_result.get(&(vec![TEST_LEAF.to_vec(), b"4".to_vec()], b"4".to_vec())), None @@ -1056,17 +1176,26 @@ mod tests { #[test] fn test_query_raw_keys_options_with_subquery() { - let db = make_test_grovedb(); + let grove_version = GroveVersion::latest(); + let db = make_test_grovedb(grove_version); - db.insert([TEST_LEAF].as_ref(), b"", Element::empty_tree(), None, None) - .unwrap() - .expect("should insert subtree successfully"); + db.insert( + [TEST_LEAF].as_ref(), + b"", + Element::empty_tree(), + None, + None, + grove_version, + ) + .unwrap() + .expect("should insert subtree successfully"); db.insert( [TEST_LEAF, b""].as_ref(), b"", Element::new_item(b"null in null".to_vec()), None, None, + grove_version, ) .unwrap() .expect("should insert subtree successfully"); @@ -1076,6 +1205,7 @@ mod tests { Element::new_item(b"1 in null".to_vec()), None, None, + grove_version, ) .unwrap() .expect("should insert subtree successfully"); @@ -1085,6 +1215,7 @@ mod tests { Element::empty_tree(), None, None, + grove_version, ) .unwrap() .expect("should insert subtree successfully"); @@ -1094,6 +1225,7 @@ mod tests { Element::new_item(b"1 in 2".to_vec()), None, None, + grove_version, ) .unwrap() .expect("should insert subtree successfully"); @@ -1103,6 +1235,7 @@ mod tests { Element::new_item(b"5 in 2".to_vec()), None, None, + grove_version, ) .unwrap() .expect("should insert subtree successfully"); @@ -1112,6 +1245,7 @@ mod tests { Element::new_item(b"2 in 2".to_vec()), None, None, + grove_version, ) .unwrap() .expect("should insert subtree successfully"); @@ -1125,7 +1259,7 @@ mod tests { let path = vec![TEST_LEAF.to_vec()]; let path_query = PathQuery::new(path, SizedQuery::new(query, Some(1000), None)); let raw_result = db - .query_raw_keys_optional(&path_query, true, true, true, None) + .query_raw_keys_optional(&path_query, true, true, true, None, GroveVersion::latest()) .unwrap() .expect("query with subquery should not error"); @@ -1147,11 +1281,11 @@ mod tests { assert_eq!( raw_result.get(&(vec![TEST_LEAF.to_vec(), b"4".to_vec()], b"1".to_vec())), Some(&None) - ); // because we are subquerying 1 + ); // because we are sub-querying 1 assert_eq!( raw_result.get(&(vec![TEST_LEAF.to_vec(), b"4".to_vec()], b"2".to_vec())), Some(&None) - ); // because we are subquerying 1 + ); // because we are sub-querying 1 assert_eq!( raw_result.get(&(vec![TEST_LEAF.to_vec(), b"4".to_vec()], b"4".to_vec())), None @@ -1177,17 +1311,26 @@ mod tests { #[test] fn test_query_raw_keys_options_with_subquery_having_intermediate_paths_missing() { - let db = make_test_grovedb(); + let grove_version = GroveVersion::latest(); + let db = make_test_grovedb(grove_version); - db.insert([TEST_LEAF].as_ref(), b"", Element::empty_tree(), None, None) - .unwrap() - .expect("should insert subtree successfully"); + db.insert( + [TEST_LEAF].as_ref(), + b"", + Element::empty_tree(), + None, + None, + grove_version, + ) + .unwrap() + .expect("should insert subtree successfully"); db.insert( [TEST_LEAF].as_ref(), b"1", Element::empty_tree(), None, None, + grove_version, ) .unwrap() .expect("should insert subtree successfully"); @@ -1197,6 +1340,7 @@ mod tests { Element::empty_tree(), None, None, + grove_version, ) .unwrap() .expect("should insert subtree successfully"); @@ -1206,6 +1350,7 @@ mod tests { Element::empty_tree(), None, None, + grove_version, ) .unwrap() .expect("should insert subtree successfully"); @@ -1215,6 +1360,7 @@ mod tests { Element::empty_tree(), None, None, + grove_version, ) .unwrap() .expect("should insert subtree successfully"); @@ -1224,6 +1370,7 @@ mod tests { Element::empty_tree(), None, None, + grove_version, ) .unwrap() .expect("should insert subtree successfully"); @@ -1233,6 +1380,7 @@ mod tests { Element::new_item(b"found_me".to_vec()), None, None, + grove_version, ) .unwrap() .expect("should insert subtree successfully"); @@ -1242,6 +1390,7 @@ mod tests { Element::new_item(b"1 in 2".to_vec()), None, None, + grove_version, ) .unwrap() .expect("should insert subtree successfully"); @@ -1251,6 +1400,7 @@ mod tests { Element::new_item(b"5 in 2".to_vec()), None, None, + grove_version, ) .unwrap() .expect("should insert subtree successfully"); @@ -1260,6 +1410,7 @@ mod tests { Element::new_item(b"2 in 2".to_vec()), None, None, + grove_version, ) .unwrap() .expect("should insert subtree successfully"); @@ -1274,7 +1425,7 @@ mod tests { let path = vec![TEST_LEAF.to_vec()]; let path_query = PathQuery::new(path, SizedQuery::new(query, Some(1000), None)); - db.query_raw_keys_optional(&path_query, true, true, true, None) + db.query_raw_keys_optional(&path_query, true, true, true, None, GroveVersion::latest()) .unwrap() .expect_err( "query with subquery should error if error_if_intermediate_path_tree_not_present \ @@ -1282,7 +1433,7 @@ mod tests { ); let raw_result = db - .query_raw_keys_optional(&path_query, true, true, false, None) + .query_raw_keys_optional(&path_query, true, true, false, None, GroveVersion::latest()) .unwrap() .expect("query with subquery should not error"); @@ -1357,17 +1508,26 @@ mod tests { #[test] fn test_query_raw_keys_options_with_subquery_and_subquery_path() { - let db = make_test_grovedb(); + let grove_version = GroveVersion::latest(); + let db = make_test_grovedb(grove_version); - db.insert([TEST_LEAF].as_ref(), b"", Element::empty_tree(), None, None) - .unwrap() - .expect("should insert subtree successfully"); + db.insert( + [TEST_LEAF].as_ref(), + b"", + Element::empty_tree(), + None, + None, + grove_version, + ) + .unwrap() + .expect("should insert subtree successfully"); db.insert( [TEST_LEAF, b""].as_ref(), b"", Element::new_item(b"null in null".to_vec()), None, None, + grove_version, ) .unwrap() .expect("should insert subtree successfully"); @@ -1377,6 +1537,7 @@ mod tests { Element::empty_tree(), None, None, + grove_version, ) .unwrap() .expect("should insert subtree successfully"); @@ -1386,6 +1547,7 @@ mod tests { Element::new_item(b"2 in null/1".to_vec()), None, None, + grove_version, ) .unwrap() .expect("should insert subtree successfully"); @@ -1395,6 +1557,7 @@ mod tests { Element::empty_tree(), None, None, + grove_version, ) .unwrap() .expect("should insert subtree successfully"); @@ -1404,6 +1567,7 @@ mod tests { Element::empty_tree(), None, None, + grove_version, ) .unwrap() .expect("should insert subtree successfully"); @@ -1413,6 +1577,7 @@ mod tests { Element::empty_tree(), None, None, + grove_version, ) .unwrap() .expect("should insert subtree successfully"); @@ -1422,6 +1587,7 @@ mod tests { Element::new_item(b"2 in 2/1".to_vec()), None, None, + grove_version, ) .unwrap() .expect("should insert subtree successfully"); @@ -1431,6 +1597,7 @@ mod tests { Element::new_item(b"5 in 2/1".to_vec()), None, None, + grove_version, ) .unwrap() .expect("should insert subtree successfully"); @@ -1453,7 +1620,7 @@ mod tests { let path = vec![TEST_LEAF.to_vec()]; let path_query = PathQuery::new(path, SizedQuery::new(query, Some(1000), None)); let raw_result = db - .query_raw_keys_optional(&path_query, true, true, true, None) + .query_raw_keys_optional(&path_query, true, true, true, None, GroveVersion::latest()) .unwrap() .expect("query with subquery should not error"); @@ -1517,17 +1684,26 @@ mod tests { #[test] fn test_query_raw_keys_options_with_subquery_and_conditional_subquery() { - let db = make_test_grovedb(); + let grove_version = GroveVersion::latest(); + let db = make_test_grovedb(grove_version); - db.insert([TEST_LEAF].as_ref(), b"", Element::empty_tree(), None, None) - .unwrap() - .expect("should insert subtree successfully"); + db.insert( + [TEST_LEAF].as_ref(), + b"", + Element::empty_tree(), + None, + None, + grove_version, + ) + .unwrap() + .expect("should insert subtree successfully"); db.insert( [TEST_LEAF, b""].as_ref(), b"", Element::new_item(b"null in null".to_vec()), None, None, + grove_version, ) .unwrap() .expect("should insert subtree successfully"); @@ -1537,6 +1713,7 @@ mod tests { Element::empty_tree(), None, None, + grove_version, ) .unwrap() .expect("should insert subtree successfully"); @@ -1546,6 +1723,7 @@ mod tests { Element::new_item(b"2 in null/1".to_vec()), None, None, + grove_version, ) .unwrap() .expect("should insert subtree successfully"); @@ -1555,6 +1733,7 @@ mod tests { Element::empty_tree(), None, None, + grove_version, ) .unwrap() .expect("should insert subtree successfully"); @@ -1564,6 +1743,7 @@ mod tests { Element::empty_tree(), None, None, + grove_version, ) .unwrap() .expect("should insert subtree successfully"); @@ -1573,6 +1753,7 @@ mod tests { Element::empty_tree(), None, None, + grove_version, ) .unwrap() .expect("should insert subtree successfully"); @@ -1582,6 +1763,7 @@ mod tests { Element::new_item(b"2 in 2/1".to_vec()), None, None, + grove_version, ) .unwrap() .expect("should insert subtree successfully"); @@ -1591,6 +1773,7 @@ mod tests { Element::new_item(b"5 in 2/1".to_vec()), None, None, + grove_version, ) .unwrap() .expect("should insert subtree successfully"); @@ -1620,7 +1803,7 @@ mod tests { let path = vec![TEST_LEAF.to_vec()]; let path_query = PathQuery::new(path, SizedQuery::new(query, Some(1000), None)); let raw_result = db - .query_raw_keys_optional(&path_query, true, true, true, None) + .query_raw_keys_optional(&path_query, true, true, true, None, GroveVersion::latest()) .unwrap() .expect("query with subquery should not error"); @@ -1685,26 +1868,36 @@ mod tests { #[test] fn test_query_keys_options_with_subquery_and_conditional_subquery_and_reference() { - let db = make_test_grovedb(); + let grove_version = GroveVersion::latest(); + let db = make_test_grovedb(grove_version); db.insert( [ANOTHER_TEST_LEAF].as_ref(), b"5", Element::new_item(b"ref result".to_vec()), None, None, + grove_version, ) .unwrap() .expect("should insert subtree successfully"); - db.insert([TEST_LEAF].as_ref(), b"", Element::empty_tree(), None, None) - .unwrap() - .expect("should insert subtree successfully"); + db.insert( + [TEST_LEAF].as_ref(), + b"", + Element::empty_tree(), + None, + None, + grove_version, + ) + .unwrap() + .expect("should insert subtree successfully"); db.insert( [TEST_LEAF, b""].as_ref(), b"", Element::new_item(b"null in null".to_vec()), None, None, + grove_version, ) .unwrap() .expect("should insert subtree successfully"); @@ -1714,6 +1907,7 @@ mod tests { Element::empty_tree(), None, None, + grove_version, ) .unwrap() .expect("should insert subtree successfully"); @@ -1723,6 +1917,7 @@ mod tests { Element::new_item(b"2 in null/1".to_vec()), None, None, + grove_version, ) .unwrap() .expect("should insert subtree successfully"); @@ -1732,6 +1927,7 @@ mod tests { Element::empty_tree(), None, None, + grove_version, ) .unwrap() .expect("should insert subtree successfully"); @@ -1741,6 +1937,7 @@ mod tests { Element::empty_tree(), None, None, + grove_version, ) .unwrap() .expect("should insert subtree successfully"); @@ -1750,6 +1947,7 @@ mod tests { Element::empty_tree(), None, None, + grove_version, ) .unwrap() .expect("should insert subtree successfully"); @@ -1759,6 +1957,7 @@ mod tests { Element::new_item(b"2 in 2/1".to_vec()), None, None, + grove_version, ) .unwrap() .expect("should insert subtree successfully"); @@ -1771,6 +1970,7 @@ mod tests { ), None, None, + grove_version, ) .unwrap() .expect("should insert subtree successfully"); @@ -1800,7 +2000,7 @@ mod tests { let path = vec![TEST_LEAF.to_vec()]; let path_query = PathQuery::new(path, SizedQuery::new(query, Some(1000), None)); let result = db - .query_keys_optional(&path_query, true, true, true, None) + .query_keys_optional(&path_query, true, true, true, None, GroveVersion::latest()) .unwrap() .expect("query with subquery should not error"); diff --git a/grovedb/src/operations/get/worst_case.rs b/grovedb/src/operations/get/worst_case.rs index 126f2b5b..7554a911 100644 --- a/grovedb/src/operations/get/worst_case.rs +++ b/grovedb/src/operations/get/worst_case.rs @@ -1,38 +1,12 @@ -// 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. - //! Worst case get costs #[cfg(feature = "full")] use grovedb_costs::OperationCost; #[cfg(feature = "full")] use grovedb_storage::rocksdb_storage::RocksDbStorage; +use grovedb_version::{check_grovedb_v0, error::GroveVersionError, version::GroveVersion}; +use crate::Error; #[cfg(feature = "full")] use crate::{ batch::{key_info::KeyInfo, KeyInfoPath}, @@ -47,7 +21,16 @@ impl GroveDb { key: &KeyInfo, max_element_size: u32, in_parent_tree_using_sums: bool, - ) -> OperationCost { + grove_version: &GroveVersion, + ) -> Result { + check_grovedb_v0!( + "worst_case_for_has_raw", + grove_version + .grovedb_versions + .operations + .get + .worst_case_for_has_raw + ); let mut cost = OperationCost::default(); GroveDb::add_worst_case_has_raw_cost::( &mut cost, @@ -55,8 +38,9 @@ impl GroveDb { key, max_element_size, in_parent_tree_using_sums, - ); - cost + grove_version, + )?; + Ok(cost) } /// Worst case cost for get raw @@ -65,7 +49,16 @@ impl GroveDb { key: &KeyInfo, max_element_size: u32, in_parent_tree_using_sums: bool, - ) -> OperationCost { + grove_version: &GroveVersion, + ) -> Result { + check_grovedb_v0!( + "worst_case_for_get_raw", + grove_version + .grovedb_versions + .operations + .get + .worst_case_for_get_raw + ); let mut cost = OperationCost::default(); GroveDb::add_worst_case_get_raw_cost::( &mut cost, @@ -73,8 +66,9 @@ impl GroveDb { key, max_element_size, in_parent_tree_using_sums, - ); - cost + grove_version, + )?; + Ok(cost) } /// Worst case cost for get @@ -84,7 +78,16 @@ impl GroveDb { max_element_size: u32, max_references_sizes: Vec, in_parent_tree_using_sums: bool, - ) -> OperationCost { + grove_version: &GroveVersion, + ) -> Result { + check_grovedb_v0!( + "worst_case_for_get", + grove_version + .grovedb_versions + .operations + .get + .worst_case_for_get + ); let mut cost = OperationCost::default(); GroveDb::add_worst_case_get_cost::( &mut cost, @@ -93,7 +96,8 @@ impl GroveDb { max_element_size, in_parent_tree_using_sums, max_references_sizes, - ); - cost + grove_version, + )?; + Ok(cost) } } diff --git a/grovedb/src/operations/insert/mod.rs b/grovedb/src/operations/insert/mod.rs index 5670a939..b7e00fc1 100644 --- a/grovedb/src/operations/insert/mod.rs +++ b/grovedb/src/operations/insert/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. - //! Insert operations #[cfg(feature = "full")] @@ -43,6 +15,9 @@ use grovedb_storage::rocksdb_storage::{ PrefixedRocksDbStorageContext, PrefixedRocksDbTransactionContext, }; use grovedb_storage::{Storage, StorageBatch}; +use grovedb_version::{ + check_grovedb_v0_with_cost, error::GroveVersionError, version::GroveVersion, +}; #[cfg(feature = "full")] use crate::{ @@ -97,11 +72,17 @@ impl GroveDb { element: Element, options: Option, transaction: TransactionArg, + grove_version: &GroveVersion, ) -> CostResult<(), Error> where B: AsRef<[u8]> + 'b, P: Into>, { + check_grovedb_v0_with_cost!( + "insert", + grove_version.grovedb_versions.operations.insert.insert + ); + let subtree_path: SubtreePath = path.into(); let batch = StorageBatch::new(); @@ -113,6 +94,7 @@ impl GroveDb { options.unwrap_or_default(), transaction, &batch, + grove_version, ) } else { self.insert_without_transaction( @@ -121,6 +103,7 @@ impl GroveDb { element, options.unwrap_or_default(), &batch, + grove_version, ) }; @@ -139,7 +122,17 @@ impl GroveDb { options: InsertOptions, transaction: &'db Transaction, batch: &StorageBatch, + grove_version: &GroveVersion, ) -> CostResult<(), Error> { + check_grovedb_v0_with_cost!( + "insert_on_transaction", + grove_version + .grovedb_versions + .operations + .insert + .insert_on_transaction + ); + let mut cost = OperationCost::default(); let mut merk_cache: HashMap, Merk> = @@ -153,13 +146,20 @@ impl GroveDb { element, options, transaction, - batch + batch, + grove_version ) ); merk_cache.insert(path.clone(), merk); cost_return_on_error!( &mut cost, - self.propagate_changes_with_transaction(merk_cache, path, transaction, batch) + self.propagate_changes_with_transaction( + merk_cache, + path, + transaction, + batch, + grove_version + ) ); Ok(()).wrap_with_cost(cost) @@ -172,7 +172,17 @@ impl GroveDb { element: Element, options: InsertOptions, batch: &StorageBatch, + grove_version: &GroveVersion, ) -> CostResult<(), Error> { + check_grovedb_v0_with_cost!( + "insert_without_transaction", + grove_version + .grovedb_versions + .operations + .insert + .insert_without_transaction + ); + let mut cost = OperationCost::default(); let mut merk_cache: HashMap, Merk> = @@ -180,13 +190,20 @@ impl GroveDb { let merk = cost_return_on_error!( &mut cost, - self.add_element_without_transaction(&path.to_vec(), key, element, options, batch) + self.add_element_without_transaction( + &path.to_vec(), + key, + element, + options, + batch, + grove_version + ) ); merk_cache.insert(path.clone(), merk); cost_return_on_error!( &mut cost, - self.propagate_changes_without_transaction(merk_cache, path, batch) + self.propagate_changes_without_transaction(merk_cache, path, batch, grove_version) ); Ok(()).wrap_with_cost(cost) @@ -205,12 +222,27 @@ impl GroveDb { options: InsertOptions, transaction: &'db Transaction, batch: &'db StorageBatch, + grove_version: &GroveVersion, ) -> CostResult>, Error> { + check_grovedb_v0_with_cost!( + "add_element_on_transaction", + grove_version + .grovedb_versions + .operations + .insert + .add_element_on_transaction + ); + let mut cost = OperationCost::default(); let mut subtree_to_insert_into = cost_return_on_error!( &mut cost, - self.open_transactional_merk_at_path(path.clone(), transaction, Some(batch)) + self.open_transactional_merk_at_path( + path.clone(), + transaction, + Some(batch), + grove_version + ) ); // if we don't allow a tree override then we should check @@ -221,7 +253,8 @@ impl GroveDb { .get( key, true, - Some(&Element::value_defined_cost_for_serialized_value) + Some(&Element::value_defined_cost_for_serialized_value), + grove_version, ) .map_err(|e| Error::CorruptedData(e.to_string())) ); @@ -235,9 +268,11 @@ impl GroveDb { if options.validate_insertion_does_not_override_tree { let element = cost_return_on_error_no_add!( &cost, - Element::deserialize(element_bytes.as_slice()).map_err(|_| { - Error::CorruptedData(String::from("unable to deserialize element")) - }) + Element::deserialize(element_bytes.as_slice(), grove_version).map_err( + |_| { + Error::CorruptedData(String::from("unable to deserialize element")) + } + ) ); if element.is_any_tree() { return Err(Error::OverrideNotAllowed( @@ -264,13 +299,19 @@ impl GroveDb { self.open_transactional_merk_at_path( referenced_path.into(), transaction, - Some(batch) + Some(batch), + grove_version, ) ); let referenced_element_value_hash_opt = cost_return_on_error!( &mut cost, - Element::get_value_hash(&subtree_for_reference, referenced_key, true) + Element::get_value_hash( + &subtree_for_reference, + referenced_key, + true, + grove_version + ) ); let referenced_element_value_hash = cost_return_on_error!( @@ -298,6 +339,7 @@ impl GroveDb { key, referenced_element_value_hash, Some(options.as_merk_options()), + grove_version, ) ); } @@ -314,7 +356,8 @@ impl GroveDb { &mut subtree_to_insert_into, key, NULL_HASH, - Some(options.as_merk_options()) + Some(options.as_merk_options()), + grove_version ) ); } @@ -325,7 +368,8 @@ impl GroveDb { element.insert( &mut subtree_to_insert_into, key, - Some(options.as_merk_options()) + Some(options.as_merk_options()), + grove_version ) ); } @@ -346,11 +390,21 @@ impl GroveDb { element: Element, options: InsertOptions, batch: &'db StorageBatch, + grove_version: &GroveVersion, ) -> CostResult, Error> { + check_grovedb_v0_with_cost!( + "add_element_without_transaction", + grove_version + .grovedb_versions + .operations + .insert + .add_element_without_transaction + ); + let mut cost = OperationCost::default(); let mut subtree_to_insert_into = cost_return_on_error!( &mut cost, - self.open_non_transactional_merk_at_path(path.into(), Some(batch)) + self.open_non_transactional_merk_at_path(path.into(), Some(batch), grove_version) ); if options.checks_for_override() { @@ -360,7 +414,8 @@ impl GroveDb { .get( key, true, - Some(&Element::value_defined_cost_for_serialized_value) + Some(&Element::value_defined_cost_for_serialized_value), + grove_version ) .map_err(|e| Error::CorruptedData(e.to_string())) ); @@ -374,9 +429,11 @@ impl GroveDb { if options.validate_insertion_does_not_override_tree { let element = cost_return_on_error_no_add!( &cost, - Element::deserialize(element_bytes.as_slice()).map_err(|_| { - Error::CorruptedData(String::from("unable to deserialize element")) - }) + Element::deserialize(element_bytes.as_slice(), grove_version).map_err( + |_| { + Error::CorruptedData(String::from("unable to deserialize element")) + } + ) ); if element.is_any_tree() { return Err(Error::OverrideNotAllowed( @@ -400,13 +457,22 @@ impl GroveDb { let (referenced_key, referenced_path) = reference_path.split_last().unwrap(); let subtree_for_reference = cost_return_on_error!( &mut cost, - self.open_non_transactional_merk_at_path(referenced_path.into(), Some(batch)) + self.open_non_transactional_merk_at_path( + referenced_path.into(), + Some(batch), + grove_version + ) ); // when there is no transaction, we don't want to use caching let referenced_element_value_hash_opt = cost_return_on_error!( &mut cost, - Element::get_value_hash(&subtree_for_reference, referenced_key, false) + Element::get_value_hash( + &subtree_for_reference, + referenced_key, + false, + grove_version + ) ); let referenced_element_value_hash = cost_return_on_error!( @@ -433,7 +499,8 @@ impl GroveDb { &mut subtree_to_insert_into, key, referenced_element_value_hash, - Some(options.as_merk_options()) + Some(options.as_merk_options()), + grove_version ) ); } @@ -450,7 +517,8 @@ impl GroveDb { &mut subtree_to_insert_into, key, NULL_HASH, - Some(options.as_merk_options()) + Some(options.as_merk_options()), + grove_version ) ); } @@ -461,7 +529,8 @@ impl GroveDb { element.insert( &mut subtree_to_insert_into, key, - Some(options.as_merk_options()) + Some(options.as_merk_options()), + grove_version ) ); } @@ -477,21 +546,31 @@ impl GroveDb { key: &[u8], element: Element, transaction: TransactionArg, + grove_version: &GroveVersion, ) -> CostResult where B: AsRef<[u8]> + 'b, P: Into>, { + check_grovedb_v0_with_cost!( + "insert_if_not_exists", + grove_version + .grovedb_versions + .operations + .insert + .insert_if_not_exists + ); + let mut cost = OperationCost::default(); let subtree_path: SubtreePath<_> = path.into(); if cost_return_on_error!( &mut cost, - self.has_raw(subtree_path.clone(), key, transaction) + self.has_raw(subtree_path.clone(), key, transaction, grove_version) ) { Ok(false).wrap_with_cost(cost) } else { - self.insert(subtree_path, key, element, None, transaction) + self.insert(subtree_path, key, element, None, transaction, grove_version) .map_ok(|_| true) .add_cost(cost) } @@ -506,17 +585,27 @@ impl GroveDb { key: &[u8], element: Element, transaction: TransactionArg, + grove_version: &GroveVersion, ) -> CostResult<(bool, Option), Error> where B: AsRef<[u8]> + 'b, P: Into>, { + check_grovedb_v0_with_cost!( + "insert_if_changed_value", + grove_version + .grovedb_versions + .operations + .insert + .insert_if_changed_value + ); + let mut cost = OperationCost::default(); let subtree_path: SubtreePath = path.into(); let previous_element = cost_return_on_error!( &mut cost, - self.get_raw_optional(subtree_path.clone(), key, transaction) + self.get_raw_optional(subtree_path.clone(), key, transaction, grove_version) ); let needs_insert = match &previous_element { None => true, @@ -525,7 +614,7 @@ impl GroveDb { if !needs_insert { Ok((false, None)).wrap_with_cost(cost) } else { - self.insert(subtree_path, key, element, None, transaction) + self.insert(subtree_path, key, element, None, transaction, grove_version) .map_ok(|_| (true, previous_element)) .add_cost(cost) } @@ -539,6 +628,7 @@ mod tests { storage_cost::{removal::StorageRemovedBytes::NoStorageRemoval, StorageCost}, OperationCost, }; + use grovedb_version::version::GroveVersion; use pretty_assertions::assert_eq; use crate::{ @@ -549,13 +639,21 @@ mod tests { #[test] fn test_non_root_insert_item_without_transaction() { - let db = make_test_grovedb(); + let grove_version = GroveVersion::latest(); + let db = make_test_grovedb(grove_version); let element = Element::new_item(b"ayy".to_vec()); - db.insert([TEST_LEAF].as_ref(), b"key", element.clone(), None, None) - .unwrap() - .expect("successful insert"); + db.insert( + [TEST_LEAF].as_ref(), + b"key", + element.clone(), + None, + None, + grove_version, + ) + .unwrap() + .expect("successful insert"); assert_eq!( - db.get([TEST_LEAF].as_ref(), b"key", None) + db.get([TEST_LEAF].as_ref(), b"key", None, grove_version) .unwrap() .expect("successful get"), element @@ -564,7 +662,8 @@ mod tests { #[test] fn test_non_root_insert_subtree_then_insert_item_without_transaction() { - let db = make_test_grovedb(); + let grove_version = GroveVersion::latest(); + let db = make_test_grovedb(grove_version); let element = Element::new_item(b"ayy".to_vec()); // Insert a subtree first @@ -574,6 +673,7 @@ mod tests { Element::empty_tree(), None, None, + grove_version, ) .unwrap() .expect("successful subtree insert"); @@ -584,11 +684,12 @@ mod tests { element.clone(), None, None, + grove_version, ) .unwrap() .expect("successful value insert"); assert_eq!( - db.get([TEST_LEAF, b"key1"].as_ref(), b"key2", None) + db.get([TEST_LEAF, b"key1"].as_ref(), b"key2", None, grove_version) .unwrap() .expect("successful get"), element @@ -597,13 +698,16 @@ mod tests { #[test] fn test_non_root_insert_item_with_transaction() { + let grove_version = GroveVersion::latest(); let item_key = b"key3"; - let db = make_test_grovedb(); + let db = make_test_grovedb(grove_version); let transaction = db.start_transaction(); // Check that there's no such key in the DB - let result = db.get([TEST_LEAF].as_ref(), item_key, None).unwrap(); + let result = db + .get([TEST_LEAF].as_ref(), item_key, None, grove_version) + .unwrap(); assert!(matches!(result, Err(Error::PathKeyNotFound(_)))); let element1 = Element::new_item(b"ayy".to_vec()); @@ -614,17 +718,25 @@ mod tests { element1, None, Some(&transaction), + grove_version, ) .unwrap() .expect("cannot insert an item into GroveDB"); // The key was inserted inside the transaction, so it shouldn't be // possible to get it back without committing or using transaction - let result = db.get([TEST_LEAF].as_ref(), item_key, None).unwrap(); + let result = db + .get([TEST_LEAF].as_ref(), item_key, None, grove_version) + .unwrap(); assert!(matches!(result, Err(Error::PathKeyNotFound(_)))); // Check that the element can be retrieved when transaction is passed let result_with_transaction = db - .get([TEST_LEAF].as_ref(), item_key, Some(&transaction)) + .get( + [TEST_LEAF].as_ref(), + item_key, + Some(&transaction), + grove_version, + ) .unwrap() .expect("Expected to work"); assert_eq!(result_with_transaction, Element::new_item(b"ayy".to_vec())); @@ -634,7 +746,7 @@ mod tests { // Check that the change was committed let result = db - .get([TEST_LEAF].as_ref(), item_key, None) + .get([TEST_LEAF].as_ref(), item_key, None, grove_version) .unwrap() .expect("Expected transaction to work"); assert_eq!(result, Element::new_item(b"ayy".to_vec())); @@ -642,13 +754,16 @@ mod tests { #[test] fn test_non_root_insert_subtree_with_transaction() { + let grove_version = GroveVersion::latest(); let subtree_key = b"subtree_key"; - let db = make_test_grovedb(); + let db = make_test_grovedb(grove_version); let transaction = db.start_transaction(); // Check that there's no such key in the DB - let result = db.get([TEST_LEAF].as_ref(), subtree_key, None).unwrap(); + let result = db + .get([TEST_LEAF].as_ref(), subtree_key, None, grove_version) + .unwrap(); assert!(matches!(result, Err(Error::PathKeyNotFound(_)))); db.insert( @@ -657,15 +772,23 @@ mod tests { Element::empty_tree(), None, Some(&transaction), + grove_version, ) .unwrap() .expect("cannot insert an item into GroveDB"); - let result = db.get([TEST_LEAF].as_ref(), subtree_key, None).unwrap(); + let result = db + .get([TEST_LEAF].as_ref(), subtree_key, None, grove_version) + .unwrap(); assert!(matches!(result, Err(Error::PathKeyNotFound(_)))); let result_with_transaction = db - .get([TEST_LEAF].as_ref(), subtree_key, Some(&transaction)) + .get( + [TEST_LEAF].as_ref(), + subtree_key, + Some(&transaction), + grove_version, + ) .unwrap() .expect("Expected to work"); assert_eq!(result_with_transaction, Element::empty_tree()); @@ -673,7 +796,7 @@ mod tests { db.commit_transaction(transaction).unwrap().unwrap(); let result = db - .get([TEST_LEAF].as_ref(), subtree_key, None) + .get([TEST_LEAF].as_ref(), subtree_key, None, grove_version) .unwrap() .expect("Expected transaction to work"); assert_eq!(result, Element::empty_tree()); @@ -681,15 +804,28 @@ mod tests { #[test] fn test_insert_if_not_exists() { - let db = make_test_grovedb(); + let grove_version = GroveVersion::latest(); + let db = make_test_grovedb(grove_version); // Insert twice at the same path assert!(db - .insert_if_not_exists([TEST_LEAF].as_ref(), b"key1", Element::empty_tree(), None) + .insert_if_not_exists( + [TEST_LEAF].as_ref(), + b"key1", + Element::empty_tree(), + None, + grove_version + ) .unwrap() .expect("Provided valid path")); assert!(!db - .insert_if_not_exists([TEST_LEAF].as_ref(), b"key1", Element::empty_tree(), None) + .insert_if_not_exists( + [TEST_LEAF].as_ref(), + b"key1", + Element::empty_tree(), + None, + grove_version + ) .unwrap() .expect("Provided valid path")); @@ -700,6 +836,7 @@ mod tests { b"key1", Element::empty_tree(), None, + grove_version, ) .unwrap(); assert!(matches!(result, Err(Error::InvalidParentLayerPath(_)))); @@ -707,6 +844,7 @@ mod tests { #[test] fn test_one_insert_item_cost() { + let grove_version = GroveVersion::latest(); let db = make_empty_grovedb(); let tx = db.start_transaction(); @@ -717,6 +855,7 @@ mod tests { Element::new_item(b"cat".to_vec()), None, Some(&tx), + grove_version, ) .cost_as_result() .expect("should insert"); @@ -766,12 +905,20 @@ mod tests { #[test] fn test_one_insert_sum_item_in_sum_tree_cost() { + let grove_version = GroveVersion::latest(); let db = make_empty_grovedb(); let tx = db.start_transaction(); - db.insert(EMPTY_PATH, b"s", Element::empty_sum_tree(), None, Some(&tx)) - .unwrap() - .expect("expected to add upper tree"); + db.insert( + EMPTY_PATH, + b"s", + Element::empty_sum_tree(), + None, + Some(&tx), + grove_version, + ) + .unwrap() + .expect("expected to add upper tree"); let cost = db .insert( @@ -780,6 +927,7 @@ mod tests { Element::new_sum_item(5), None, Some(&tx), + grove_version, ) .cost_as_result() .expect("should insert"); @@ -824,12 +972,20 @@ mod tests { #[test] fn test_one_insert_sum_item_under_sum_item_cost() { + let grove_version = GroveVersion::latest(); let db = make_empty_grovedb(); let tx = db.start_transaction(); - db.insert(EMPTY_PATH, b"s", Element::empty_sum_tree(), None, Some(&tx)) - .unwrap() - .expect("expected to add upper tree"); + db.insert( + EMPTY_PATH, + b"s", + Element::empty_sum_tree(), + None, + Some(&tx), + grove_version, + ) + .unwrap() + .expect("expected to add upper tree"); db.insert( [b"s".as_slice()].as_ref(), @@ -837,6 +993,7 @@ mod tests { Element::new_sum_item(5), None, Some(&tx), + grove_version, ) .unwrap() .expect("should insert"); @@ -848,6 +1005,7 @@ mod tests { Element::new_sum_item(6), None, Some(&tx), + grove_version, ) .cost_as_result() .expect("should insert"); @@ -897,12 +1055,20 @@ mod tests { #[test] fn test_one_insert_bigger_sum_item_under_sum_item_cost() { + let grove_version = GroveVersion::latest(); let db = make_empty_grovedb(); let tx = db.start_transaction(); - db.insert(EMPTY_PATH, b"s", Element::empty_sum_tree(), None, Some(&tx)) - .unwrap() - .expect("expected to add upper tree"); + db.insert( + EMPTY_PATH, + b"s", + Element::empty_sum_tree(), + None, + Some(&tx), + grove_version, + ) + .unwrap() + .expect("expected to add upper tree"); db.insert( [b"s".as_slice()].as_ref(), @@ -910,6 +1076,7 @@ mod tests { Element::new_sum_item(126), None, Some(&tx), + grove_version, ) .unwrap() .expect("should insert"); @@ -922,6 +1089,7 @@ mod tests { Element::new_sum_item(32768), None, Some(&tx), + grove_version, ) .cost_as_result() .expect("should insert"); @@ -966,6 +1134,7 @@ mod tests { #[test] fn test_one_insert_item_cost_with_flags() { + let grove_version = GroveVersion::latest(); let db = make_empty_grovedb(); let tx = db.start_transaction(); @@ -976,6 +1145,7 @@ mod tests { Element::new_item_with_flags(b"cat".to_vec(), Some(b"dog".to_vec())), None, Some(&tx), + grove_version, ) .cost; // Explanation for 183 storage_written_bytes @@ -1025,11 +1195,19 @@ mod tests { #[test] fn test_one_insert_empty_tree_cost() { + let grove_version = GroveVersion::latest(); let db = make_empty_grovedb(); let tx = db.start_transaction(); let cost = db - .insert(EMPTY_PATH, b"key1", Element::empty_tree(), None, Some(&tx)) + .insert( + EMPTY_PATH, + b"key1", + Element::empty_tree(), + None, + Some(&tx), + grove_version, + ) .cost; // Explanation for 183 storage_written_bytes @@ -1077,6 +1255,7 @@ mod tests { #[test] fn test_one_insert_empty_sum_tree_cost() { + let grove_version = GroveVersion::latest(); let db = make_empty_grovedb(); let tx = db.start_transaction(); @@ -1087,6 +1266,7 @@ mod tests { Element::empty_sum_tree(), None, Some(&tx), + grove_version, ) .cost; // Explanation for 183 storage_written_bytes @@ -1136,6 +1316,7 @@ mod tests { #[test] fn test_one_insert_empty_tree_cost_with_flags() { + let grove_version = GroveVersion::latest(); let db = make_empty_grovedb(); let tx = db.start_transaction(); @@ -1146,6 +1327,7 @@ mod tests { Element::empty_tree_with_flags(Some(b"cat".to_vec())), None, Some(&tx), + grove_version, ) .cost; // Explanation for 183 storage_written_bytes @@ -1198,12 +1380,20 @@ mod tests { #[test] fn test_one_insert_item_cost_under_tree() { + let grove_version = GroveVersion::latest(); let db = make_empty_grovedb(); let tx = db.start_transaction(); - db.insert(EMPTY_PATH, b"tree", Element::empty_tree(), None, Some(&tx)) - .unwrap() - .unwrap(); + db.insert( + EMPTY_PATH, + b"tree", + Element::empty_tree(), + None, + Some(&tx), + grove_version, + ) + .unwrap() + .unwrap(); let cost = db .insert( @@ -1212,6 +1402,7 @@ mod tests { Element::new_item(b"test".to_vec()), None, Some(&tx), + grove_version, ) .cost_as_result() .unwrap(); @@ -1269,6 +1460,7 @@ mod tests { #[test] fn test_one_insert_item_with_apple_flags_cost() { + let grove_version = GroveVersion::latest(); let db = make_empty_grovedb(); let tx = db.start_transaction(); @@ -1279,6 +1471,7 @@ mod tests { Element::new_item_with_flags(b"test".to_vec(), Some(b"apple".to_vec())), None, Some(&tx), + grove_version, ) .cost_as_result() .unwrap(); @@ -1332,12 +1525,20 @@ mod tests { #[test] fn test_one_insert_item_with_flags_cost_under_tree() { + let grove_version = GroveVersion::latest(); let db = make_empty_grovedb(); let tx = db.start_transaction(); - db.insert(EMPTY_PATH, b"tree", Element::empty_tree(), None, Some(&tx)) - .unwrap() - .unwrap(); + db.insert( + EMPTY_PATH, + b"tree", + Element::empty_tree(), + None, + Some(&tx), + grove_version, + ) + .unwrap() + .unwrap(); let cost = db .insert( @@ -1346,6 +1547,7 @@ mod tests { Element::new_item_with_flags(b"test".to_vec(), Some(b"apple".to_vec())), None, Some(&tx), + grove_version, ) .cost_as_result() .unwrap(); @@ -1417,6 +1619,7 @@ mod tests { #[test] fn test_one_insert_item_with_flags_cost_under_tree_with_flags() { + let grove_version = GroveVersion::latest(); let db = make_empty_grovedb(); let tx = db.start_transaction(); @@ -1426,6 +1629,7 @@ mod tests { Element::empty_tree_with_flags(Some(b"cat".to_vec())), None, Some(&tx), + grove_version, ) .unwrap() .unwrap(); @@ -1437,6 +1641,7 @@ mod tests { Element::new_item_with_flags(b"test".to_vec(), Some(b"apple".to_vec())), None, Some(&tx), + grove_version, ) .cost_as_result() .unwrap(); @@ -1510,6 +1715,7 @@ mod tests { #[test] fn test_one_update_item_same_cost_at_root() { + let grove_version = GroveVersion::latest(); let db = make_empty_grovedb(); let tx = db.start_transaction(); @@ -1519,6 +1725,7 @@ mod tests { Element::new_item(b"cat".to_vec()), None, Some(&tx), + grove_version, ) .unwrap() .unwrap(); @@ -1530,6 +1737,7 @@ mod tests { Element::new_item(b"dog".to_vec()), None, Some(&tx), + grove_version, ) .cost_as_result() .expect("expected to insert"); @@ -1576,12 +1784,20 @@ mod tests { #[test] fn test_one_update_same_cost_in_underlying_tree() { + let grove_version = GroveVersion::latest(); let db = make_empty_grovedb(); let tx = db.start_transaction(); - db.insert(EMPTY_PATH, b"tree", Element::empty_tree(), None, Some(&tx)) - .unwrap() - .unwrap(); + db.insert( + EMPTY_PATH, + b"tree", + Element::empty_tree(), + None, + Some(&tx), + grove_version, + ) + .unwrap() + .unwrap(); db.insert( [b"tree".as_slice()].as_ref(), @@ -1589,6 +1805,7 @@ mod tests { Element::new_item(b"cat".to_vec()), None, Some(&tx), + grove_version, ) .unwrap() .unwrap(); @@ -1600,6 +1817,7 @@ mod tests { Element::new_item(b"dog".to_vec()), None, Some(&tx), + grove_version, ) .cost_as_result() .expect("expected to insert"); @@ -1620,6 +1838,7 @@ mod tests { #[test] fn test_one_update_same_cost_in_underlying_sum_tree_bigger_sum_item() { + let grove_version = GroveVersion::latest(); let db = make_empty_grovedb(); let tx = db.start_transaction(); @@ -1629,6 +1848,7 @@ mod tests { Element::empty_sum_tree(), None, Some(&tx), + grove_version, ) .unwrap() .unwrap(); @@ -1639,6 +1859,7 @@ mod tests { Element::new_sum_item(15), None, Some(&tx), + grove_version, ) .unwrap() .unwrap(); @@ -1650,6 +1871,7 @@ mod tests { Element::new_sum_item(1000000), None, Some(&tx), + grove_version, ) .cost_as_result() .expect("expected to insert"); @@ -1671,6 +1893,7 @@ mod tests { #[test] fn test_one_update_same_cost_in_underlying_sum_tree_bigger_sum_item_parent_sum_tree_already_big( ) { + let grove_version = GroveVersion::latest(); let db = make_empty_grovedb(); let tx = db.start_transaction(); @@ -1680,6 +1903,7 @@ mod tests { Element::empty_sum_tree(), None, Some(&tx), + grove_version, ) .unwrap() .unwrap(); @@ -1690,6 +1914,7 @@ mod tests { Element::new_sum_item(1000000), None, Some(&tx), + grove_version, ) .unwrap() .unwrap(); @@ -1700,6 +1925,7 @@ mod tests { Element::new_sum_item(15), None, Some(&tx), + grove_version, ) .unwrap() .unwrap(); @@ -1711,6 +1937,7 @@ mod tests { Element::new_sum_item(1000000), None, Some(&tx), + grove_version, ) .cost_as_result() .expect("expected to insert"); @@ -1731,6 +1958,7 @@ mod tests { #[test] fn test_one_update_same_cost_in_underlying_sum_tree_smaller_sum_item() { + let grove_version = GroveVersion::latest(); let db = make_empty_grovedb(); let tx = db.start_transaction(); @@ -1740,6 +1968,7 @@ mod tests { Element::empty_sum_tree(), None, Some(&tx), + grove_version, ) .unwrap() .unwrap(); @@ -1750,6 +1979,7 @@ mod tests { Element::new_sum_item(1000000), None, Some(&tx), + grove_version, ) .unwrap() .unwrap(); @@ -1761,6 +1991,7 @@ mod tests { Element::new_sum_item(15), None, Some(&tx), + grove_version, ) .cost_as_result() .expect("expected to insert"); @@ -1781,12 +2012,20 @@ mod tests { #[test] fn test_one_update_bigger_cost() { + let grove_version = GroveVersion::latest(); let db = make_empty_grovedb(); let tx = db.start_transaction(); - db.insert(EMPTY_PATH, b"tree", Element::empty_tree(), None, Some(&tx)) - .unwrap() - .unwrap(); + db.insert( + EMPTY_PATH, + b"tree", + Element::empty_tree(), + None, + Some(&tx), + grove_version, + ) + .unwrap() + .unwrap(); db.insert( [b"tree".as_slice()].as_ref(), @@ -1794,6 +2033,7 @@ mod tests { Element::new_item(b"test".to_vec()), None, Some(&tx), + grove_version, ) .unwrap() .unwrap(); @@ -1805,6 +2045,7 @@ mod tests { Element::new_item(b"test1".to_vec()), None, Some(&tx), + grove_version, ) .cost_as_result() .expect("expected to insert"); @@ -1825,12 +2066,20 @@ mod tests { #[test] fn test_one_update_tree_bigger_cost_with_flags() { + let grove_version = GroveVersion::latest(); let db = make_empty_grovedb(); let tx = db.start_transaction(); - db.insert(EMPTY_PATH, b"tree", Element::empty_tree(), None, Some(&tx)) - .unwrap() - .unwrap(); + db.insert( + EMPTY_PATH, + b"tree", + Element::empty_tree(), + None, + Some(&tx), + grove_version, + ) + .unwrap() + .unwrap(); db.insert( [b"tree".as_slice()].as_ref(), @@ -1838,6 +2087,7 @@ mod tests { Element::new_tree(None), None, Some(&tx), + grove_version, ) .unwrap() .unwrap(); @@ -1853,6 +2103,7 @@ mod tests { base_root_storage_is_free: true, }), Some(&tx), + grove_version, ) .cost_as_result() .expect("expected to insert"); diff --git a/grovedb/src/operations/is_empty_tree.rs b/grovedb/src/operations/is_empty_tree.rs index 40abd62f..07c34999 100644 --- a/grovedb/src/operations/is_empty_tree.rs +++ b/grovedb/src/operations/is_empty_tree.rs @@ -1,36 +1,11 @@ -// 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. - //! Check if empty tree operations #[cfg(feature = "full")] use grovedb_costs::{cost_return_on_error, CostResult, CostsExt, OperationCost}; use grovedb_path::SubtreePath; +#[cfg(feature = "full")] +use grovedb_version::error::GroveVersionError; +use grovedb_version::{check_grovedb_v0_with_cost, version::GroveVersion}; #[cfg(feature = "full")] use crate::{util::merk_optional_tx, Element, Error, GroveDb, TransactionArg}; @@ -42,20 +17,32 @@ impl GroveDb { &self, path: P, transaction: TransactionArg, + grove_version: &GroveVersion, ) -> CostResult where B: AsRef<[u8]> + 'b, P: Into>, { + check_grovedb_v0_with_cost!( + "is_empty_tree", + grove_version.grovedb_versions.operations.get.is_empty_tree + ); let mut cost = OperationCost::default(); let path: SubtreePath = path.into(); cost_return_on_error!( &mut cost, - self.check_subtree_exists_path_not_found(path.clone(), transaction) + self.check_subtree_exists_path_not_found(path.clone(), transaction, grove_version) ); - merk_optional_tx!(&mut cost, self.db, path, None, transaction, subtree, { - Ok(subtree.is_empty_tree().unwrap_add_cost(&mut cost)).wrap_with_cost(cost) - }) + merk_optional_tx!( + &mut cost, + self.db, + path, + None, + transaction, + subtree, + grove_version, + { Ok(subtree.is_empty_tree().unwrap_add_cost(&mut cost)).wrap_with_cost(cost) } + ) } } diff --git a/grovedb/src/operations/proof/generate.rs b/grovedb/src/operations/proof/generate.rs index fe5866e8..a5297eaf 100644 --- a/grovedb/src/operations/proof/generate.rs +++ b/grovedb/src/operations/proof/generate.rs @@ -12,6 +12,9 @@ use grovedb_merk::{ Merk, ProofWithoutEncodingResult, }; use grovedb_storage::StorageContext; +use grovedb_version::{ + check_grovedb_v0_with_cost, error::GroveVersionError, version::GroveVersion, +}; #[cfg(feature = "proof_debug")] use crate::query_result_type::QueryResultType; @@ -31,12 +34,21 @@ impl GroveDb { &self, query: Vec<&PathQuery>, prove_options: Option, + grove_version: &GroveVersion, ) -> CostResult, Error> { + check_grovedb_v0_with_cost!( + "prove_query_many", + grove_version + .grovedb_versions + .operations + .proof + .prove_query_many + ); if query.len() > 1 { - let query = cost_return_on_error_default!(PathQuery::merge(query)); - self.prove_query(&query, prove_options) + let query = cost_return_on_error_default!(PathQuery::merge(query, grove_version)); + self.prove_query(&query, prove_options, grove_version) } else { - self.prove_query(query[0], prove_options) + self.prove_query(query[0], prove_options, grove_version) } } @@ -48,8 +60,13 @@ impl GroveDb { &self, query: &PathQuery, prove_options: Option, + grove_version: &GroveVersion, ) -> CostResult, Error> { - self.prove_internal_serialized(query, prove_options) + check_grovedb_v0_with_cost!( + "prove_query_many", + grove_version.grovedb_versions.operations.proof.prove_query + ); + self.prove_internal_serialized(query, prove_options, grove_version) } /// Generates a proof and serializes it @@ -57,10 +74,13 @@ impl GroveDb { &self, path_query: &PathQuery, prove_options: Option, + grove_version: &GroveVersion, ) -> CostResult, Error> { let mut cost = OperationCost::default(); - let proof = - cost_return_on_error!(&mut cost, self.prove_internal(path_query, prove_options)); + let proof = cost_return_on_error!( + &mut cost, + self.prove_internal(path_query, prove_options, grove_version) + ); #[cfg(feature = "proof_debug")] { println!("constructed proof is {}", proof); @@ -81,6 +101,7 @@ impl GroveDb { &self, path_query: &PathQuery, prove_options: Option, + grove_version: &GroveVersion, ) -> CostResult { let mut cost = OperationCost::default(); @@ -113,7 +134,8 @@ impl GroveDb { prove_options.decrease_limit_on_empty_sub_query_result, false, QueryResultType::QueryPathKeyElementTrioResultType, - None + None, + grove_version, ) ) .0; @@ -128,7 +150,8 @@ impl GroveDb { prove_options.decrease_limit_on_empty_sub_query_result, false, QueryResultType::QueryPathKeyElementTrioResultType, - None + None, + grove_version, ) ) .0 @@ -141,7 +164,13 @@ impl GroveDb { let root_layer = cost_return_on_error!( &mut cost, - self.prove_subqueries(vec![], path_query, &mut limit, &prove_options) + self.prove_subqueries( + vec![], + path_query, + &mut limit, + &prove_options, + grove_version + ) ); Ok(GroveDBProofV0 { @@ -160,26 +189,29 @@ impl GroveDb { path_query: &PathQuery, overall_limit: &mut Option, prove_options: &ProveOptions, + grove_version: &GroveVersion, ) -> CostResult { let mut cost = OperationCost::default(); let query = cost_return_on_error_no_add!( &cost, path_query - .query_items_at_path(path.as_slice()) - .ok_or(Error::CorruptedPath(format!( - "prove subqueries: path {} should be part of path_query {}", - path.iter() - .map(|a| hex_to_ascii(a)) - .collect::>() - .join("/"), - path_query - ))) + .query_items_at_path(path.as_slice(), grove_version) + .and_then(|query_items| { + query_items.ok_or(Error::CorruptedPath(format!( + "prove subqueries: path {} should be part of path_query {}", + path.iter() + .map(|a| hex_to_ascii(a)) + .collect::>() + .join("/"), + path_query + ))) + }) ); let subtree = cost_return_on_error!( &mut cost, - self.open_non_transactional_merk_at_path(path.as_slice().into(), None) + self.open_non_transactional_merk_at_path(path.as_slice().into(), None, grove_version) ); let limit = if path.len() < path_query.path.len() { @@ -191,7 +223,13 @@ impl GroveDb { let mut merk_proof = cost_return_on_error!( &mut cost, - self.generate_merk_proof(&subtree, &query.items, query.left_to_right, limit) + self.generate_merk_proof( + &subtree, + &query.items, + query.left_to_right, + limit, + grove_version + ) ); #[cfg(feature = "proof_debug")] @@ -223,7 +261,7 @@ impl GroveDb { Node::KV(key, value) | Node::KVValueHash(key, value, ..) if !done_with_results => { - let elem = Element::deserialize(value); + let elem = Element::deserialize(value, grove_version); match elem { Ok(Element::Reference(reference_path, ..)) => { let absolute_path = cost_return_on_error!( @@ -241,11 +279,13 @@ impl GroveDb { self.follow_reference( absolute_path.as_slice().into(), true, - None + None, + grove_version ) ); - let serialized_referenced_elem = referenced_elem.serialize(); + let serialized_referenced_elem = + referenced_elem.serialize(grove_version); if serialized_referenced_elem.is_err() { return Err(Error::CorruptedData(String::from( "unable to serialize element", @@ -300,6 +340,7 @@ impl GroveDb { path_query, overall_limit, prove_options, + grove_version, ) ); @@ -379,12 +420,13 @@ impl GroveDb { query_items: &[QueryItem], left_to_right: bool, limit: Option, + grove_version: &GroveVersion, ) -> CostResult where S: StorageContext<'a> + 'a, { subtree - .prove_unchecked_query_items(query_items, limit, left_to_right) + .prove_unchecked_query_items(query_items, limit, left_to_right, grove_version) .map_ok(|(proof, limit)| ProofWithoutEncodingResult::new(proof, limit)) .map_err(|e| { Error::InternalError(format!( diff --git a/grovedb/src/operations/proof/util.rs b/grovedb/src/operations/proof/util.rs index 50480c13..d6b34ecc 100644 --- a/grovedb/src/operations/proof/util.rs +++ b/grovedb/src/operations/proof/util.rs @@ -4,6 +4,7 @@ use grovedb_merk::{ proofs::query::{Key, Path, ProvedKeyOptionalValue, ProvedKeyValue}, CryptoHash, Error, }; +use grovedb_version::version::GroveVersion; use crate::Element; @@ -313,14 +314,14 @@ pub fn path_as_slices_hex_to_ascii(path: &[&[u8]]) -> String { pub fn optional_element_hex_to_ascii(hex_value: Option<&Vec>) -> String { match hex_value { None => "None".to_string(), - Some(hex_value) => Element::deserialize(hex_value) + Some(hex_value) => Element::deserialize(hex_value, GroveVersion::latest()) .map(|e| e.to_string()) .unwrap_or_else(|_| hex::encode(hex_value)), } } pub fn element_hex_to_ascii(hex_value: &[u8]) -> String { - Element::deserialize(hex_value) + Element::deserialize(hex_value, GroveVersion::latest()) .map(|e| e.to_string()) .unwrap_or_else(|_| hex::encode(hex_value)) } diff --git a/grovedb/src/operations/proof/verify.rs b/grovedb/src/operations/proof/verify.rs index 4e0375e3..31cd9ae5 100644 --- a/grovedb/src/operations/proof/verify.rs +++ b/grovedb/src/operations/proof/verify.rs @@ -8,6 +8,10 @@ use grovedb_merk::{ tree::{combine_hash, value_hash}, CryptoHash, }; +use grovedb_version::{ + check_grovedb_v0, error::GroveVersionError, version::GroveVersion, TryFromVersioned, + TryIntoVersioned, +}; #[cfg(feature = "proof_debug")] use crate::operations::proof::util::{ @@ -27,7 +31,16 @@ impl GroveDb { proof: &[u8], query: &PathQuery, options: VerifyOptions, + grove_version: &GroveVersion, ) -> Result<(CryptoHash, Vec), Error> { + check_grovedb_v0!( + "verify_query_with_options", + grove_version + .grovedb_versions + .operations + .proof + .verify_query_with_options + ); if options.absence_proofs_for_non_existing_searched_keys { // must have a limit query.query.limit.ok_or(Error::NotSupported( @@ -49,7 +62,8 @@ impl GroveDb { .map_err(|e| Error::CorruptedData(format!("unable to decode proof: {}", e)))? .0; - let (root_hash, result) = Self::verify_proof_internal(&grovedb_proof, query, options)?; + let (root_hash, result) = + Self::verify_proof_internal(&grovedb_proof, query, options, grove_version)?; Ok((root_hash, result)) } @@ -57,7 +71,16 @@ impl GroveDb { pub fn verify_query_raw( proof: &[u8], query: &PathQuery, + grove_version: &GroveVersion, ) -> Result<(CryptoHash, ProvedPathKeyValues), Error> { + check_grovedb_v0!( + "verify_query_raw", + grove_version + .grovedb_versions + .operations + .proof + .verify_query_raw + ); let config = bincode::config::standard() .with_big_endian() .with_no_limit(); @@ -73,6 +96,7 @@ impl GroveDb { verify_proof_succinctness: false, include_empty_trees_in_result: true, }, + grove_version, )?; Ok((root_hash, result)) @@ -82,16 +106,20 @@ impl GroveDb { proof: &GroveDBProof, query: &PathQuery, options: VerifyOptions, + grove_version: &GroveVersion, ) -> Result<(CryptoHash, Vec), Error> { match proof { - GroveDBProof::V0(proof_v0) => Self::verify_proof_internal_v0(proof_v0, query, options), + GroveDBProof::V0(proof_v0) => { + Self::verify_proof_v0_internal(proof_v0, query, options, grove_version) + } } } - fn verify_proof_internal_v0( + fn verify_proof_v0_internal( proof: &GroveDBProofV0, query: &PathQuery, options: VerifyOptions, + grove_version: &GroveVersion, ) -> Result<(CryptoHash, Vec), Error> { let mut result = Vec::new(); let mut limit = query.query.limit; @@ -103,6 +131,7 @@ impl GroveDb { &[], &mut result, &options, + grove_version, )?; if options.absence_proofs_for_non_existing_searched_keys { @@ -111,7 +140,7 @@ impl GroveDb { "limits must be set in verify_query_with_absence_proof".to_string(), ))? as usize; - let terminal_keys = query.terminal_keys(max_results)?; + let terminal_keys = query.terminal_keys(max_results, grove_version)?; // convert the result set to a btree map let mut result_set_as_map: BTreeMap> = result @@ -167,10 +196,11 @@ impl GroveDb { proof: &GroveDBProof, query: &PathQuery, options: VerifyOptions, + grove_version: &GroveVersion, ) -> Result<(CryptoHash, ProvedPathKeyValues), Error> { match proof { GroveDBProof::V0(proof_v0) => { - Self::verify_proof_raw_internal_v0(proof_v0, query, options) + Self::verify_proof_raw_internal_v0(proof_v0, query, options, grove_version) } } } @@ -179,6 +209,7 @@ impl GroveDb { proof: &GroveDBProofV0, query: &PathQuery, options: VerifyOptions, + grove_version: &GroveVersion, ) -> Result<(CryptoHash, ProvedPathKeyValues), Error> { let mut result = Vec::new(); let mut limit = query.query.limit; @@ -190,6 +221,7 @@ impl GroveDb { &[], &mut result, &options, + grove_version, )?; Ok((root_hash, result)) } @@ -202,23 +234,31 @@ impl GroveDb { current_path: &[&[u8]], result: &mut Vec, options: &VerifyOptions, + grove_version: &GroveVersion, ) -> Result where - T: TryFrom, - Error: From<>::Error>, + T: TryFromVersioned, + Error: From<>::Error>, { - let internal_query = - query - .query_items_at_path(current_path) - .ok_or(Error::CorruptedPath(format!( - "verify raw: path {} should be part of path_query {}", - current_path - .iter() - .map(hex::encode) - .collect::>() - .join("/"), - query - )))?; + check_grovedb_v0!( + "verify_layer_proof", + grove_version + .grovedb_versions + .operations + .proof + .verify_layer_proof + ); + let internal_query = query + .query_items_at_path(current_path, grove_version)? + .ok_or(Error::CorruptedPath(format!( + "verify raw: path {} should be part of path_query {}", + current_path + .iter() + .map(hex::encode) + .collect::>() + .join("/"), + query + )))?; let level_query = Query { items: internal_query.items.to_vec(), @@ -258,7 +298,7 @@ impl GroveDb { let key = &proved_key_value.key; let hash = &proved_key_value.proof; if let Some(value_bytes) = &proved_key_value.value { - let element = Element::deserialize(value_bytes)?; + let element = Element::deserialize(value_bytes, grove_version)?; verified_keys.insert(key.clone()); @@ -278,6 +318,7 @@ impl GroveDb { &path, result, options, + grove_version, )?; let combined_root_hash = combine_hash(value_hash(value_bytes).value(), &lower_hash) @@ -321,7 +362,7 @@ impl GroveDb { &path_key_optional_value, limit_left ); } - result.push(path_key_optional_value.try_into()?); + result.push(path_key_optional_value.try_into_versioned(grove_version)?); limit_left.as_mut().map(|limit| *limit -= 1); if limit_left == &Some(0) { @@ -348,7 +389,12 @@ impl GroveDb { pub fn verify_query( proof: &[u8], query: &PathQuery, + grove_version: &GroveVersion, ) -> Result<(CryptoHash, Vec), Error> { + check_grovedb_v0!( + "verify_query", + grove_version.grovedb_versions.operations.proof.verify_query + ); Self::verify_query_with_options( proof, query, @@ -357,13 +403,23 @@ impl GroveDb { verify_proof_succinctness: true, include_empty_trees_in_result: false, }, + grove_version, ) } pub fn verify_subset_query( proof: &[u8], query: &PathQuery, + grove_version: &GroveVersion, ) -> Result<(CryptoHash, Vec), Error> { + check_grovedb_v0!( + "verify_subset_query", + grove_version + .grovedb_versions + .operations + .proof + .verify_subset_query + ); Self::verify_query_with_options( proof, query, @@ -372,13 +428,23 @@ impl GroveDb { verify_proof_succinctness: false, include_empty_trees_in_result: false, }, + grove_version, ) } pub fn verify_query_with_absence_proof( proof: &[u8], query: &PathQuery, + grove_version: &GroveVersion, ) -> Result<(CryptoHash, Vec), Error> { + check_grovedb_v0!( + "verify_query_with_absence_proof", + grove_version + .grovedb_versions + .operations + .proof + .verify_query_with_absence_proof + ); Self::verify_query_with_options( proof, query, @@ -387,13 +453,23 @@ impl GroveDb { verify_proof_succinctness: true, include_empty_trees_in_result: false, }, + grove_version, ) } pub fn verify_subset_query_with_absence_proof( proof: &[u8], query: &PathQuery, + grove_version: &GroveVersion, ) -> Result<(CryptoHash, Vec), Error> { + check_grovedb_v0!( + "verify_subset_query_with_absence_proof", + grove_version + .grovedb_versions + .operations + .proof + .verify_subset_query_with_absence_proof + ); Self::verify_query_with_options( proof, query, @@ -402,6 +478,7 @@ impl GroveDb { verify_proof_succinctness: false, include_empty_trees_in_result: false, }, + grove_version, ) } @@ -415,13 +492,23 @@ impl GroveDb { proof: &[u8], first_query: &PathQuery, chained_path_queries: Vec, + grove_version: &GroveVersion, ) -> Result<(CryptoHash, Vec>), Error> where C: Fn(Vec) -> Option, { + check_grovedb_v0!( + "verify_query_with_chained_path_queries", + grove_version + .grovedb_versions + .operations + .proof + .verify_query_with_chained_path_queries + ); let mut results = vec![]; - let (last_root_hash, elements) = Self::verify_subset_query(proof, first_query)?; + let (last_root_hash, elements) = + Self::verify_subset_query(proof, first_query, grove_version)?; results.push(elements); // we should iterate over each chained path queries @@ -429,7 +516,8 @@ impl GroveDb { let new_path_query = path_query_generator(results[results.len() - 1].clone()).ok_or( Error::InvalidInput("one of the path query generators returns no path query"), )?; - let (new_root_hash, new_elements) = Self::verify_subset_query(proof, &new_path_query)?; + let (new_root_hash, new_elements) = + Self::verify_subset_query(proof, &new_path_query, grove_version)?; if new_root_hash != last_root_hash { return Err(Error::InvalidProof(format!( "root hash for different path queries do no match, first is {}, this one is {}", diff --git a/grovedb/src/query/mod.rs b/grovedb/src/query/mod.rs index 7b4fe42a..f140bb05 100644 --- a/grovedb/src/query/mod.rs +++ b/grovedb/src/query/mod.rs @@ -11,6 +11,7 @@ use grovedb_merk::proofs::query::query_item::QueryItem; use grovedb_merk::proofs::query::{Key, SubqueryBranch}; #[cfg(any(feature = "full", feature = "verify"))] use grovedb_merk::proofs::Query; +use grovedb_version::{check_grovedb_v0, error::GroveVersionError, version::GroveVersion}; use indexmap::IndexMap; use crate::operations::proof::util::hex_to_ascii; @@ -134,7 +135,18 @@ impl PathQuery { } /// Gets the path of all terminal keys - pub fn terminal_keys(&self, max_results: usize) -> Result, Error> { + pub fn terminal_keys( + &self, + max_results: usize, + grove_version: &GroveVersion, + ) -> Result, Error> { + check_grovedb_v0!( + "merge", + grove_version + .grovedb_versions + .path_query_methods + .terminal_keys + ); let mut result: Vec<(Vec>, Vec)> = vec![]; self.query .query @@ -144,7 +156,14 @@ impl PathQuery { } /// Combines multiple path queries into one equivalent path query - pub fn merge(mut path_queries: Vec<&PathQuery>) -> Result { + pub fn merge( + mut path_queries: Vec<&PathQuery>, + grove_version: &GroveVersion, + ) -> Result { + check_grovedb_v0!( + "merge", + grove_version.grovedb_versions.path_query_methods.merge + ); if path_queries.is_empty() { return Err(Error::InvalidInput( "merge function requires at least 1 path query", @@ -276,7 +295,18 @@ impl PathQuery { } } - pub fn query_items_at_path(&self, path: &[&[u8]]) -> Option { + pub fn query_items_at_path( + &self, + path: &[&[u8]], + grove_version: &GroveVersion, + ) -> Result, Error> { + check_grovedb_v0!( + "query_items_at_path", + grove_version + .grovedb_versions + .path_query_methods + .query_items_at_path + ); fn recursive_query_items<'b>( query: &'b Query, path: &[&[u8]], @@ -386,7 +416,7 @@ impl PathQuery { let self_path_len = self.path.len(); let given_path_len = path.len(); - match given_path_len.cmp(&self_path_len) { + Ok(match given_path_len.cmp(&self_path_len) { Ordering::Less => { if path.iter().zip(&self.path).all(|(a, b)| *a == b.as_slice()) { Some(SinglePathSubquery::from_key_when_in_path( @@ -407,11 +437,11 @@ impl PathQuery { } Ordering::Greater => { if !self.path.iter().zip(path).all(|(a, b)| a.as_slice() == *b) { - return None; + return Ok(None); } recursive_query_items(&self.query.query, &path[self_path_len..]) } - } + }) } } @@ -551,6 +581,7 @@ mod tests { query::{query_item::QueryItem, SubqueryBranch}, Query, }; + use grovedb_version::version::GroveVersion; use indexmap::IndexMap; use crate::{ @@ -562,7 +593,8 @@ mod tests { #[test] fn test_same_path_different_query_merge() { - let temp_db = make_deep_tree(); + let grove_version = GroveVersion::latest(); + let temp_db = make_deep_tree(grove_version); // starting with no subquery, just a single path and a key query let mut query_one = Query::new(); @@ -570,9 +602,13 @@ mod tests { let path_query_one = PathQuery::new_unsized(vec![TEST_LEAF.to_vec(), b"innertree".to_vec()], query_one); - let proof = temp_db.prove_query(&path_query_one, None).unwrap().unwrap(); - let (_, result_set_one) = GroveDb::verify_query_raw(proof.as_slice(), &path_query_one) - .expect("should execute proof"); + let proof = temp_db + .prove_query(&path_query_one, None, grove_version) + .unwrap() + .unwrap(); + let (_, result_set_one) = + GroveDb::verify_query_raw(proof.as_slice(), &path_query_one, grove_version) + .expect("should execute proof"); assert_eq!(result_set_one.len(), 1); let mut query_two = Query::new(); @@ -580,38 +616,49 @@ mod tests { let path_query_two = PathQuery::new_unsized(vec![TEST_LEAF.to_vec(), b"innertree".to_vec()], query_two); - let proof = temp_db.prove_query(&path_query_two, None).unwrap().unwrap(); - let (_, result_set_two) = GroveDb::verify_query_raw(proof.as_slice(), &path_query_two) - .expect("should execute proof"); + let proof = temp_db + .prove_query(&path_query_two, None, grove_version) + .unwrap() + .unwrap(); + let (_, result_set_two) = + GroveDb::verify_query_raw(proof.as_slice(), &path_query_two, grove_version) + .expect("should execute proof"); assert_eq!(result_set_two.len(), 1); - let merged_path_query = PathQuery::merge(vec![&path_query_one, &path_query_two]) - .expect("should merge path queries"); + let merged_path_query = + PathQuery::merge(vec![&path_query_one, &path_query_two], grove_version) + .expect("should merge path queries"); let proof = temp_db - .prove_query(&merged_path_query, None) + .prove_query(&merged_path_query, None, grove_version) .unwrap() .unwrap(); - let (_, result_set_tree) = GroveDb::verify_query_raw(proof.as_slice(), &merged_path_query) - .expect("should execute proof"); + let (_, result_set_tree) = + GroveDb::verify_query_raw(proof.as_slice(), &merged_path_query, grove_version) + .expect("should execute proof"); assert_eq!(result_set_tree.len(), 2); } #[test] fn test_different_same_length_path_with_different_query_merge() { + let grove_version = GroveVersion::latest(); // Tests for // [a, c, Q] // [a, m, Q] - let temp_db = make_deep_tree(); + let temp_db = make_deep_tree(grove_version); let mut query_one = Query::new(); query_one.insert_key(b"key1".to_vec()); let path_query_one = PathQuery::new_unsized(vec![TEST_LEAF.to_vec(), b"innertree".to_vec()], query_one); - let proof = temp_db.prove_query(&path_query_one, None).unwrap().unwrap(); - let (_, result_set_one) = GroveDb::verify_query_raw(proof.as_slice(), &path_query_one) - .expect("should execute proof"); + let proof = temp_db + .prove_query(&path_query_one, None, grove_version) + .unwrap() + .unwrap(); + let (_, result_set_one) = + GroveDb::verify_query_raw(proof.as_slice(), &path_query_one, grove_version) + .expect("should execute proof"); assert_eq!(result_set_one.len(), 1); let mut query_two = Query::new(); @@ -619,28 +666,33 @@ mod tests { let path_query_two = PathQuery::new_unsized(vec![TEST_LEAF.to_vec(), b"innertree4".to_vec()], query_two); - let proof = temp_db.prove_query(&path_query_two, None).unwrap().unwrap(); - let (_, result_set_two) = GroveDb::verify_query_raw(proof.as_slice(), &path_query_two) - .expect("should execute proof"); + let proof = temp_db + .prove_query(&path_query_two, None, grove_version) + .unwrap() + .unwrap(); + let (_, result_set_two) = + GroveDb::verify_query_raw(proof.as_slice(), &path_query_two, grove_version) + .expect("should execute proof"); assert_eq!(result_set_two.len(), 1); - let merged_path_query = PathQuery::merge(vec![&path_query_one, &path_query_two]) - .expect("expect to merge path queries"); + let merged_path_query = + PathQuery::merge(vec![&path_query_one, &path_query_two], grove_version) + .expect("expect to merge path queries"); assert_eq!(merged_path_query.path, vec![TEST_LEAF.to_vec()]); assert_eq!(merged_path_query.query.query.items.len(), 2); let proof = temp_db - .prove_query(&merged_path_query, None) + .prove_query(&merged_path_query, None, grove_version) .unwrap() .unwrap(); let (_, result_set_merged) = - GroveDb::verify_query_raw(proof.as_slice(), &merged_path_query) + GroveDb::verify_query_raw(proof.as_slice(), &merged_path_query, grove_version) .expect("should execute proof"); assert_eq!(result_set_merged.len(), 2); let keys = [b"key1".to_vec(), b"key4".to_vec()]; let values = [b"value1".to_vec(), b"value4".to_vec()]; - let elements = values.map(|x| Element::new_item(x).serialize().unwrap()); + let elements = values.map(|x| Element::new_item(x).serialize(grove_version).unwrap()); let expected_result_set: Vec<(Vec, Vec)> = keys.into_iter().zip(elements).collect(); compare_result_tuples(result_set_merged, expected_result_set); @@ -656,9 +708,13 @@ mod tests { query_one.clone(), ); - let proof = temp_db.prove_query(&path_query_one, None).unwrap().unwrap(); - let (_, result_set_one) = GroveDb::verify_query_raw(proof.as_slice(), &path_query_one) - .expect("should execute proof"); + let proof = temp_db + .prove_query(&path_query_one, None, grove_version) + .unwrap() + .unwrap(); + let (_, result_set_one) = + GroveDb::verify_query_raw(proof.as_slice(), &path_query_one, grove_version) + .expect("should execute proof"); assert_eq!(result_set_one.len(), 3); let mut query_two = Query::new(); @@ -673,9 +729,13 @@ mod tests { query_two.clone(), ); - let proof = temp_db.prove_query(&path_query_two, None).unwrap().unwrap(); - let (_, result_set_two) = GroveDb::verify_query_raw(proof.as_slice(), &path_query_two) - .expect("should execute proof"); + let proof = temp_db + .prove_query(&path_query_two, None, grove_version) + .unwrap() + .unwrap(); + let (_, result_set_two) = + GroveDb::verify_query_raw(proof.as_slice(), &path_query_two, grove_version) + .expect("should execute proof"); assert_eq!(result_set_two.len(), 2); let mut query_three = Query::new(); @@ -691,11 +751,12 @@ mod tests { ); let proof = temp_db - .prove_query(&path_query_three, None) + .prove_query(&path_query_three, None, grove_version) .unwrap() .unwrap(); - let (_, result_set_two) = GroveDb::verify_query_raw(proof.as_slice(), &path_query_three) - .expect("should execute proof"); + let (_, result_set_two) = + GroveDb::verify_query_raw(proof.as_slice(), &path_query_three, grove_version) + .expect("should execute proof"); assert_eq!(result_set_two.len(), 2); #[rustfmt::skip] @@ -725,9 +786,11 @@ mod tests { } - let merged_path_query = - PathQuery::merge(vec![&path_query_one, &path_query_two, &path_query_three]) - .expect("expect to merge path queries"); + let merged_path_query = PathQuery::merge( + vec![&path_query_one, &path_query_two, &path_query_three], + grove_version, + ) + .expect("expect to merge path queries"); assert_eq!(merged_path_query.path, vec![b"deep_leaf".to_vec()]); assert_eq!(merged_path_query.query.query.items.len(), 2); let conditional_subquery_branches = merged_path_query @@ -824,17 +887,18 @@ mod tests { true, QueryResultType::QueryPathKeyElementTrioResultType, None, + grove_version, ) .value .expect("expected to get results"); assert_eq!(result_set_merged.len(), 7); let proof = temp_db - .prove_query(&merged_path_query, None) + .prove_query(&merged_path_query, None, grove_version) .unwrap() .unwrap(); let (_, proved_result_set_merged) = - GroveDb::verify_query_raw(proof.as_slice(), &merged_path_query) + GroveDb::verify_query_raw(proof.as_slice(), &merged_path_query, grove_version) .expect("should execute proof"); assert_eq!(proved_result_set_merged.len(), 7); @@ -856,14 +920,15 @@ mod tests { b"value10".to_vec(), b"value11".to_vec(), ]; - let elements = values.map(|x| Element::new_item(x).serialize().unwrap()); + let elements = values.map(|x| Element::new_item(x).serialize(grove_version).unwrap()); let expected_result_set: Vec<(Vec, Vec)> = keys.into_iter().zip(elements).collect(); compare_result_tuples(proved_result_set_merged, expected_result_set); } #[test] fn test_different_length_paths_merge() { - let temp_db = make_deep_tree(); + let grove_version = GroveVersion::latest(); + let temp_db = make_deep_tree(grove_version); let mut query_one = Query::new(); query_one.insert_all(); @@ -877,9 +942,13 @@ mod tests { query_one, ); - let proof = temp_db.prove_query(&path_query_one, None).unwrap().unwrap(); - let (_, result_set_one) = GroveDb::verify_query_raw(proof.as_slice(), &path_query_one) - .expect("should execute proof"); + let proof = temp_db + .prove_query(&path_query_one, None, grove_version) + .unwrap() + .unwrap(); + let (_, result_set_one) = + GroveDb::verify_query_raw(proof.as_slice(), &path_query_one, grove_version) + .expect("should execute proof"); assert_eq!(result_set_one.len(), 6); let mut query_two = Query::new(); @@ -894,21 +963,26 @@ mod tests { query_two, ); - let proof = temp_db.prove_query(&path_query_two, None).unwrap().unwrap(); - let (_, result_set_two) = GroveDb::verify_query_raw(proof.as_slice(), &path_query_two) - .expect("should execute proof"); + let proof = temp_db + .prove_query(&path_query_two, None, grove_version) + .unwrap() + .unwrap(); + let (_, result_set_two) = + GroveDb::verify_query_raw(proof.as_slice(), &path_query_two, grove_version) + .expect("should execute proof"); assert_eq!(result_set_two.len(), 2); - let merged_path_query = PathQuery::merge(vec![&path_query_one, &path_query_two]) - .expect("expect to merge path queries"); + let merged_path_query = + PathQuery::merge(vec![&path_query_one, &path_query_two], grove_version) + .expect("expect to merge path queries"); assert_eq!(merged_path_query.path, vec![b"deep_leaf".to_vec()]); let proof = temp_db - .prove_query(&merged_path_query, None) + .prove_query(&merged_path_query, None, grove_version) .unwrap() .unwrap(); let (_, result_set_merged) = - GroveDb::verify_query_raw(proof.as_slice(), &merged_path_query) + GroveDb::verify_query_raw(proof.as_slice(), &merged_path_query, grove_version) .expect("should execute proof"); assert_eq!(result_set_merged.len(), 8); @@ -932,23 +1006,28 @@ mod tests { b"value10".to_vec(), b"value11".to_vec(), ]; - let elements = values.map(|x| Element::new_item(x).serialize().unwrap()); + let elements = values.map(|x| Element::new_item(x).serialize(grove_version).unwrap()); let expected_result_set: Vec<(Vec, Vec)> = keys.into_iter().zip(elements).collect(); compare_result_tuples(result_set_merged, expected_result_set); } #[test] fn test_same_path_and_different_path_query_merge() { - let temp_db = make_deep_tree(); + let grove_version = GroveVersion::latest(); + let temp_db = make_deep_tree(grove_version); let mut query_one = Query::new(); query_one.insert_key(b"key1".to_vec()); let path_query_one = PathQuery::new_unsized(vec![TEST_LEAF.to_vec(), b"innertree".to_vec()], query_one); - let proof = temp_db.prove_query(&path_query_one, None).unwrap().unwrap(); - let (_, result_set) = GroveDb::verify_query_raw(proof.as_slice(), &path_query_one) - .expect("should execute proof"); + let proof = temp_db + .prove_query(&path_query_one, None, grove_version) + .unwrap() + .unwrap(); + let (_, result_set) = + GroveDb::verify_query_raw(proof.as_slice(), &path_query_one, grove_version) + .expect("should execute proof"); assert_eq!(result_set.len(), 1); let mut query_two = Query::new(); @@ -956,9 +1035,13 @@ mod tests { let path_query_two = PathQuery::new_unsized(vec![TEST_LEAF.to_vec(), b"innertree".to_vec()], query_two); - let proof = temp_db.prove_query(&path_query_two, None).unwrap().unwrap(); - let (_, result_set) = GroveDb::verify_query_raw(proof.as_slice(), &path_query_two) - .expect("should execute proof"); + let proof = temp_db + .prove_query(&path_query_two, None, grove_version) + .unwrap() + .unwrap(); + let (_, result_set) = + GroveDb::verify_query_raw(proof.as_slice(), &path_query_two, grove_version) + .expect("should execute proof"); assert_eq!(result_set.len(), 1); let mut query_three = Query::new(); @@ -969,42 +1052,51 @@ mod tests { ); let proof = temp_db - .prove_query(&path_query_three, None) + .prove_query(&path_query_three, None, grove_version) .unwrap() .unwrap(); - let (_, result_set) = GroveDb::verify_query_raw(proof.as_slice(), &path_query_three) - .expect("should execute proof"); + let (_, result_set) = + GroveDb::verify_query_raw(proof.as_slice(), &path_query_three, grove_version) + .expect("should execute proof"); assert_eq!(result_set.len(), 2); - let merged_path_query = - PathQuery::merge(vec![&path_query_one, &path_query_two, &path_query_three]) - .expect("should merge three queries"); + let merged_path_query = PathQuery::merge( + vec![&path_query_one, &path_query_two, &path_query_three], + grove_version, + ) + .expect("should merge three queries"); let proof = temp_db - .prove_query(&merged_path_query, None) + .prove_query(&merged_path_query, None, grove_version) .unwrap() .unwrap(); - let (_, result_set) = GroveDb::verify_query_raw(proof.as_slice(), &merged_path_query) - .expect("should execute proof"); + let (_, result_set) = + GroveDb::verify_query_raw(proof.as_slice(), &merged_path_query, grove_version) + .expect("should execute proof"); assert_eq!(result_set.len(), 4); } #[test] fn test_equal_path_merge() { + let grove_version = GroveVersion::latest(); // [a, b, Q] // [a, b, Q2] // We should be able to merge this if Q and Q2 have no subqueries. - let temp_db = make_deep_tree(); + let temp_db = make_deep_tree(grove_version); let mut query_one = Query::new(); query_one.insert_key(b"key1".to_vec()); let path_query_one = PathQuery::new_unsized(vec![TEST_LEAF.to_vec(), b"innertree".to_vec()], query_one); - let proof = temp_db.prove_query(&path_query_one, None).unwrap().unwrap(); - let (_, result_set) = GroveDb::verify_query_raw(proof.as_slice(), &path_query_one) - .expect("should execute proof"); + let proof = temp_db + .prove_query(&path_query_one, None, grove_version) + .unwrap() + .unwrap(); + let (_, result_set) = + GroveDb::verify_query_raw(proof.as_slice(), &path_query_one, grove_version) + .expect("should execute proof"); assert_eq!(result_set.len(), 1); let mut query_two = Query::new(); @@ -1012,20 +1104,26 @@ mod tests { let path_query_two = PathQuery::new_unsized(vec![TEST_LEAF.to_vec(), b"innertree".to_vec()], query_two); - let proof = temp_db.prove_query(&path_query_two, None).unwrap().unwrap(); - let (_, result_set) = GroveDb::verify_query_raw(proof.as_slice(), &path_query_two) - .expect("should execute proof"); + let proof = temp_db + .prove_query(&path_query_two, None, grove_version) + .unwrap() + .unwrap(); + let (_, result_set) = + GroveDb::verify_query_raw(proof.as_slice(), &path_query_two, grove_version) + .expect("should execute proof"); assert_eq!(result_set.len(), 1); - let merged_path_query = PathQuery::merge(vec![&path_query_one, &path_query_two]) - .expect("should merge three queries"); + let merged_path_query = + PathQuery::merge(vec![&path_query_one, &path_query_two], grove_version) + .expect("should merge three queries"); let proof = temp_db - .prove_query(&merged_path_query, None) + .prove_query(&merged_path_query, None, grove_version) .unwrap() .unwrap(); - let (_, result_set) = GroveDb::verify_query_raw(proof.as_slice(), &merged_path_query) - .expect("should execute proof"); + let (_, result_set) = + GroveDb::verify_query_raw(proof.as_slice(), &merged_path_query, grove_version) + .expect("should execute proof"); assert_eq!(result_set.len(), 2); // [a, b, Q] @@ -1038,9 +1136,13 @@ mod tests { query_one, ); - let proof = temp_db.prove_query(&path_query_one, None).unwrap().unwrap(); - let (_, result_set) = GroveDb::verify_query_raw(proof.as_slice(), &path_query_one) - .expect("should execute proof"); + let proof = temp_db + .prove_query(&path_query_one, None, grove_version) + .unwrap() + .unwrap(); + let (_, result_set) = + GroveDb::verify_query_raw(proof.as_slice(), &path_query_one, grove_version) + .expect("should execute proof"); assert_eq!(result_set.len(), 2); let mut query_one = Query::new(); @@ -1055,9 +1157,13 @@ mod tests { query_one, ); - let proof = temp_db.prove_query(&path_query_two, None).unwrap().unwrap(); - let (_, result_set) = GroveDb::verify_query_raw(proof.as_slice(), &path_query_two) - .expect("should execute proof"); + let proof = temp_db + .prove_query(&path_query_two, None, grove_version) + .unwrap() + .unwrap(); + let (_, result_set) = + GroveDb::verify_query_raw(proof.as_slice(), &path_query_two, grove_version) + .expect("should execute proof"); assert_eq!(result_set.len(), 3); #[rustfmt::skip] @@ -1087,8 +1193,9 @@ mod tests { } - let merged_path_query = PathQuery::merge(vec![&path_query_one, &path_query_two]) - .expect("expected to be able to merge path_query"); + let merged_path_query = + PathQuery::merge(vec![&path_query_one, &path_query_two], grove_version) + .expect("expected to be able to merge path_query"); // we expect the common path to be the path of both before merge assert_eq!( @@ -1133,22 +1240,25 @@ mod tests { true, QueryResultType::QueryPathKeyElementTrioResultType, None, + grove_version, ) .value .expect("expected to get results"); assert_eq!(result_set_merged.len(), 4); let proof = temp_db - .prove_query(&merged_path_query, None) + .prove_query(&merged_path_query, None, grove_version) .unwrap() .unwrap(); - let (_, result_set) = GroveDb::verify_query_raw(proof.as_slice(), &merged_path_query) - .expect("should execute proof"); + let (_, result_set) = + GroveDb::verify_query_raw(proof.as_slice(), &merged_path_query, grove_version) + .expect("should execute proof"); assert_eq!(result_set.len(), 4); } #[test] fn test_path_query_items_with_subquery_and_inner_subquery_path() { + let grove_version = GroveVersion::latest(); // Constructing the keys and paths let root_path_key_1 = b"root_path_key_1".to_vec(); let root_path_key_2 = b"root_path_key_2".to_vec(); @@ -1193,7 +1303,8 @@ mod tests { { let path = vec![root_path_key_1.as_slice()]; let first = path_query - .query_items_at_path(&path) + .query_items_at_path(&path, grove_version) + .expect("expected valid version") .expect("expected query items"); assert_eq!( @@ -1211,7 +1322,8 @@ mod tests { let path = vec![root_path_key_1.as_slice(), root_path_key_2.as_slice()]; let second = path_query - .query_items_at_path(&path) + .query_items_at_path(&path, grove_version) + .expect("expected valid version") .expect("expected query items"); assert_eq!( @@ -1234,7 +1346,8 @@ mod tests { ]; let third = path_query - .query_items_at_path(&path) + .query_items_at_path(&path, grove_version) + .expect("expected valid version") .expect("expected query items"); assert_eq!( @@ -1257,7 +1370,8 @@ mod tests { ]; let fourth = path_query - .query_items_at_path(&path) + .query_items_at_path(&path, grove_version) + .expect("expected valid version") .expect("expected query items"); assert_eq!( @@ -1281,7 +1395,8 @@ mod tests { ]; let fifth = path_query - .query_items_at_path(&path) + .query_items_at_path(&path, grove_version) + .expect("expected valid version") .expect("expected query items"); assert_eq!( @@ -1307,7 +1422,8 @@ mod tests { ]; let sixth = path_query - .query_items_at_path(&path) + .query_items_at_path(&path, grove_version) + .expect("expected valid version") .expect("expected query items"); assert_eq!( @@ -1324,6 +1440,7 @@ mod tests { #[test] fn test_path_query_items_with_subquery_path() { + let grove_version = GroveVersion::latest(); // Constructing the keys and paths let root_path_key = b"higher".to_vec(); let dash_key = b"dash".to_vec(); @@ -1351,7 +1468,8 @@ mod tests { { let path = vec![root_path_key.as_slice()]; let first = path_query - .query_items_at_path(&path) + .query_items_at_path(&path, grove_version) + .expect("expected valid version") .expect("expected query items"); assert_eq!( @@ -1369,7 +1487,8 @@ mod tests { let path = vec![root_path_key.as_slice(), dash_key.as_slice()]; let second = path_query - .query_items_at_path(&path) + .query_items_at_path(&path, grove_version) + .expect("expected valid version") .expect("expected query items"); assert_eq!( @@ -1386,6 +1505,7 @@ mod tests { #[test] fn test_conditional_subquery_refusing_elements() { + let grove_version = GroveVersion::latest(); let empty_vec: Vec = vec![]; let zero_vec: Vec = vec![0]; @@ -1419,7 +1539,8 @@ mod tests { let path = vec![TEST_LEAF, empty_vec.as_slice()]; let second = path_query - .query_items_at_path(&path) + .query_items_at_path(&path, grove_version) + .expect("expected valid version") .expect("expected query items"); assert_eq!( @@ -1436,6 +1557,7 @@ mod tests { #[test] fn test_complex_path_query_with_conditional_subqueries() { + let grove_version = GroveVersion::latest(); let identity_id = hex::decode("8b8948a6801501bbe0431e3d994dcf71cf5a2a0939fe51b0e600076199aba4fb") .unwrap(); @@ -1515,7 +1637,8 @@ mod tests { { let path = vec![]; let first = path_query - .query_items_at_path(&path) + .query_items_at_path(&path, grove_version) + .expect("expected valid version") .expect("expected query items"); assert_eq!( @@ -1534,7 +1657,8 @@ mod tests { { let path = vec![key_20.as_slice()]; let query = path_query - .query_items_at_path(&path) + .query_items_at_path(&path, grove_version) + .expect("expected valid version") .expect("expected query items"); assert_eq!( @@ -1551,7 +1675,8 @@ mod tests { { let path = vec![key_20.as_slice(), identity_id.as_slice()]; let query = path_query - .query_items_at_path(&path) + .query_items_at_path(&path, grove_version) + .expect("expected valid version") .expect("expected query items"); assert_eq!( @@ -1570,7 +1695,8 @@ mod tests { { let path = vec![key_20.as_slice(), identity_id.as_slice(), key_80.as_slice()]; let query = path_query - .query_items_at_path(&path) + .query_items_at_path(&path, grove_version) + .expect("expected valid version") .expect("expected query items"); assert_eq!( diff --git a/grovedb/src/query_result_type.rs b/grovedb/src/query_result_type.rs index 6bf8bd5b..02035238 100644 --- a/grovedb/src/query_result_type.rs +++ b/grovedb/src/query_result_type.rs @@ -7,6 +7,7 @@ use std::{ }; pub use grovedb_merk::proofs::query::{Key, Path, PathKey}; +use grovedb_version::{version::GroveVersion, TryFromVersioned}; use crate::{ operations::proof::util::{ @@ -503,11 +504,14 @@ pub type PathKeyElementTrio = (Path, Key, Element); pub type PathKeyOptionalElementTrio = (Path, Key, Option); #[cfg(any(feature = "full", feature = "verify"))] -impl TryFrom for PathKeyOptionalElementTrio { +impl TryFromVersioned for PathKeyOptionalElementTrio { type Error = Error; - fn try_from(proved_path_key_value: ProvedPathKeyValue) -> Result { - let element = Element::deserialize(proved_path_key_value.value.as_slice())?; + fn try_from_versioned( + proved_path_key_value: ProvedPathKeyValue, + grove_version: &GroveVersion, + ) -> Result { + let element = Element::deserialize(proved_path_key_value.value.as_slice(), grove_version)?; Ok(( proved_path_key_value.path, proved_path_key_value.key, @@ -517,13 +521,16 @@ impl TryFrom for PathKeyOptionalElementTrio { } #[cfg(any(feature = "full", feature = "verify"))] -impl TryFrom for PathKeyOptionalElementTrio { +impl TryFromVersioned for PathKeyOptionalElementTrio { type Error = Error; - fn try_from(proved_path_key_value: ProvedPathKeyOptionalValue) -> Result { + fn try_from_versioned( + proved_path_key_value: ProvedPathKeyOptionalValue, + grove_version: &GroveVersion, + ) -> Result { let element = proved_path_key_value .value - .map(|e| Element::deserialize(e.as_slice())) + .map(|e| Element::deserialize(e.as_slice(), grove_version)) .transpose()?; Ok(( proved_path_key_value.path, @@ -536,6 +543,8 @@ impl TryFrom for PathKeyOptionalElementTrio { #[cfg(feature = "full")] #[cfg(test)] mod tests { + use grovedb_version::{version::GroveVersion, TryIntoVersioned}; + use crate::{ operations::proof::util::ProvedPathKeyValue, query_result_type::PathKeyOptionalElementTrio, Element, @@ -543,6 +552,7 @@ mod tests { #[test] fn test_single_proved_path_key_value_to_path_key_optional_element() { + let grove_version = GroveVersion::latest(); let path = vec![b"1".to_vec(), b"2".to_vec()]; let proved_path_key_value = ProvedPathKeyValue { path: path.clone(), @@ -551,7 +561,7 @@ mod tests { proof: [0; 32], }; let path_key_element_trio: PathKeyOptionalElementTrio = proved_path_key_value - .try_into() + .try_into_versioned(grove_version) .expect("should convert to path key optional element trio"); assert_eq!( path_key_element_trio, diff --git a/grovedb/src/reference_path.rs b/grovedb/src/reference_path.rs index 09fc1684..aa01d400 100644 --- a/grovedb/src/reference_path.rs +++ b/grovedb/src/reference_path.rs @@ -351,6 +351,7 @@ impl ReferencePathType { #[cfg(test)] mod tests { use grovedb_merk::proofs::Query; + use grovedb_version::version::GroveVersion; use crate::{ reference_path::{path_from_reference_path_type, ReferencePathType}, @@ -465,7 +466,8 @@ mod tests { #[test] fn test_query_many_with_different_reference_types() { - let db = make_deep_tree(); + let grove_version = GroveVersion::latest(); + let db = make_deep_tree(grove_version); db.insert( [TEST_LEAF, b"innertree4"].as_ref(), @@ -477,6 +479,7 @@ mod tests { ])), None, None, + grove_version, ) .unwrap() .expect("should insert successfully"); @@ -490,6 +493,7 @@ mod tests { )), None, None, + grove_version, ) .unwrap() .expect("should insert successfully"); @@ -503,6 +507,7 @@ mod tests { )), None, None, + grove_version, ) .unwrap() .expect("should insert successfully"); @@ -513,7 +518,7 @@ mod tests { let path_query = PathQuery::new_unsized(vec![TEST_LEAF.to_vec(), b"innertree4".to_vec()], query); let result = db - .query_item_value(&path_query, true, true, true, None) + .query_item_value(&path_query, true, true, true, None, grove_version) .unwrap() .expect("should query items"); assert_eq!(result.0.len(), 5); @@ -529,12 +534,12 @@ mod tests { ); let proof = db - .prove_query(&path_query, None) + .prove_query(&path_query, None, grove_version) .unwrap() .expect("should generate proof"); - let (hash, result) = - GroveDb::verify_query_raw(&proof, &path_query).expect("should verify proof"); - assert_eq!(hash, db.root_hash(None).unwrap().unwrap()); + let (hash, result) = GroveDb::verify_query_raw(&proof, &path_query, grove_version) + .expect("should verify proof"); + assert_eq!(hash, db.root_hash(None, grove_version).unwrap().unwrap()); assert_eq!(result.len(), 5); } } diff --git a/grovedb/src/replication.rs b/grovedb/src/replication.rs index b6533868..876fe62c 100644 --- a/grovedb/src/replication.rs +++ b/grovedb/src/replication.rs @@ -14,6 +14,7 @@ use grovedb_path::SubtreePath; use grovedb_storage::rocksdb_storage::RocksDbStorage; #[rustfmt::skip] use grovedb_storage::rocksdb_storage::storage_context::context_immediate::PrefixedRocksDbImmediateStorageContext; +use grovedb_version::{check_grovedb_v0, error::GroveVersionError, version::GroveVersion}; use crate::{replication, Error, GroveDb, Transaction, TransactionArg}; @@ -88,7 +89,7 @@ impl fmt::Debug for SubtreesMetadata { " prefix:{:?} -> path:{:?}", hex::encode(prefix), metadata_path_str - ); + )?; } Ok(()) } @@ -166,10 +167,23 @@ impl GroveDb { // tx: Transaction. Function returns the data by opening merks at given tx. // TODO: Add a SubTreePath as param and start searching from that path instead // of root (as it is now) - pub fn get_subtrees_metadata(&self, tx: TransactionArg) -> Result { - let mut subtrees_metadata = crate::replication::SubtreesMetadata::new(); + pub fn get_subtrees_metadata( + &self, + tx: TransactionArg, + grove_version: &GroveVersion, + ) -> Result { + check_grovedb_v0!( + "is_empty_tree", + grove_version + .grovedb_versions + .replication + .get_subtrees_metadata + ); + let mut subtrees_metadata = SubtreesMetadata::new(); - let subtrees_root = self.find_subtrees(&SubtreePath::empty(), tx).value?; + let subtrees_root = self + .find_subtrees(&SubtreePath::empty(), tx, grove_version) + .value?; for subtree in subtrees_root.into_iter() { let subtree_path: Vec<&[u8]> = subtree.iter().map(|vec| vec.as_slice()).collect(); let path: &[&[u8]] = &subtree_path; @@ -181,13 +195,14 @@ impl GroveDb { (Some((parent_path, _)), Some(parent_key)) => match tx { None => { let parent_merk = self - .open_non_transactional_merk_at_path(parent_path, None) + .open_non_transactional_merk_at_path(parent_path, None, grove_version) .value?; if let Ok(Some((elem_value, elem_value_hash))) = parent_merk .get_value_and_value_hash( parent_key, true, - None::<&fn(&[u8]) -> Option>, + None::<&fn(&[u8], &GroveVersion) -> Option>, + grove_version, ) .value { @@ -200,13 +215,14 @@ impl GroveDb { } Some(t) => { let parent_merk = self - .open_transactional_merk_at_path(parent_path, t, None) + .open_transactional_merk_at_path(parent_path, t, None, grove_version) .value?; if let Ok(Some((elem_value, elem_value_hash))) = parent_merk .get_value_and_value_hash( parent_key, true, - None::<&fn(&[u8]) -> Option>, + None::<&fn(&[u8], &GroveVersion) -> Option>, + grove_version, ) .value { @@ -248,7 +264,12 @@ impl GroveDb { global_chunk_id: &[u8], tx: TransactionArg, version: u16, + grove_version: &GroveVersion, ) -> Result, Error> { + check_grovedb_v0!( + "fetch_chunk", + grove_version.grovedb_versions.replication.fetch_chunk + ); // For now, only CURRENT_STATE_SYNC_VERSION is supported if version != CURRENT_STATE_SYNC_VERSION { return Err(Error::CorruptedData( @@ -256,11 +277,11 @@ impl GroveDb { )); } - let root_app_hash = self.root_hash(tx).value?; + let root_app_hash = self.root_hash(tx, grove_version).value?; let (chunk_prefix, chunk_id) = replication::util_split_global_chunk_id(global_chunk_id, &root_app_hash)?; - let subtrees_metadata = self.get_subtrees_metadata(tx)?; + let subtrees_metadata = self.get_subtrees_metadata(tx, grove_version)?; match subtrees_metadata.data.get(&chunk_prefix) { Some(path_data) => { @@ -271,7 +292,7 @@ impl GroveDb { match tx { None => { let merk = self - .open_non_transactional_merk_at_path(path.into(), None) + .open_non_transactional_merk_at_path(path.into(), None, grove_version) .value?; if merk.is_empty_tree().unwrap() { @@ -281,7 +302,7 @@ impl GroveDb { let chunk_producer_res = ChunkProducer::new(&merk); match chunk_producer_res { Ok(mut chunk_producer) => { - let chunk_res = chunk_producer.chunk(&chunk_id); + let chunk_res = chunk_producer.chunk(&chunk_id, grove_version); match chunk_res { Ok((chunk, _)) => match util_encode_vec_ops(chunk) { Ok(op_bytes) => Ok(op_bytes), @@ -301,7 +322,7 @@ impl GroveDb { } Some(t) => { let merk = self - .open_transactional_merk_at_path(path.into(), t, None) + .open_transactional_merk_at_path(path.into(), t, None, grove_version) .value?; if merk.is_empty_tree().unwrap() { @@ -311,7 +332,7 @@ impl GroveDb { let chunk_producer_res = ChunkProducer::new(&merk); match chunk_producer_res { Ok(mut chunk_producer) => { - let chunk_res = chunk_producer.chunk(&chunk_id); + let chunk_res = chunk_producer.chunk(&chunk_id, grove_version); match chunk_res { Ok((chunk, _)) => match util_encode_vec_ops(chunk) { Ok(op_bytes) => Ok(op_bytes), @@ -347,7 +368,15 @@ impl GroveDb { app_hash: CryptoHash, tx: &'db Transaction, version: u16, + grove_version: &GroveVersion, ) -> Result { + check_grovedb_v0!( + "start_snapshot_syncing", + grove_version + .grovedb_versions + .replication + .start_snapshot_syncing + ); // For now, only CURRENT_STATE_SYNC_VERSION is supported if version != CURRENT_STATE_SYNC_VERSION { return Err(Error::CorruptedData( @@ -375,7 +404,7 @@ impl GroveDb { let mut root_prefix_state_sync_info = SubtreeStateSyncInfo::default(); let root_prefix = [0u8; 32]; - if let Ok(merk) = self.open_merk_for_replication(SubtreePath::empty(), tx) { + if let Ok(merk) = self.open_merk_for_replication(SubtreePath::empty(), tx, grove_version) { let restorer = Restorer::new(merk, app_hash, None); root_prefix_state_sync_info.restorer = Some(restorer); root_prefix_state_sync_info.pending_chunks.insert(vec![]); @@ -407,7 +436,12 @@ impl GroveDb { chunk: Vec, tx: &'db Transaction, version: u16, + grove_version: &GroveVersion, ) -> Result<(Vec>, MultiStateSyncInfo), Error> { + check_grovedb_v0!( + "apply_chunk", + grove_version.grovedb_versions.replication.apply_chunk + ); // For now, only CURRENT_STATE_SYNC_VERSION is supported if version != CURRENT_STATE_SYNC_VERSION { return Err(Error::CorruptedData( @@ -432,7 +466,7 @@ impl GroveDb { } if let Some(subtree_state_sync) = state_sync_info.current_prefixes.remove(&chunk_prefix) { if let Ok((res, mut new_subtree_state_sync)) = - self.apply_inner_chunk(subtree_state_sync, &chunk_id, chunk) + self.apply_inner_chunk(subtree_state_sync, &chunk_id, chunk, grove_version) { if !res.is_empty() { for local_chunk_id in res.iter() { @@ -462,7 +496,7 @@ impl GroveDb { )), Some(restorer) => { if (new_subtree_state_sync.num_processed_chunks > 0) - && (restorer.finalize().is_err()) + && (restorer.finalize(grove_version).is_err()) { return Err(Error::InternalError( "Unable to finalize Merk".to_string(), @@ -472,7 +506,8 @@ impl GroveDb { // Subtree was successfully save. Time to discover new subtrees that // need to be processed - let subtrees_metadata = self.get_subtrees_metadata(Some(tx))?; + let subtrees_metadata = + self.get_subtrees_metadata(Some(tx), grove_version)?; if let Some(value) = subtrees_metadata.data.get(&chunk_prefix) { println!( " path:{:?} done (num_processed_chunks:{:?})", @@ -481,9 +516,12 @@ impl GroveDb { ); } - if let Ok((res, new_state_sync_info)) = - self.discover_subtrees(state_sync_info, subtrees_metadata, tx) - { + if let Ok((res, new_state_sync_info)) = self.discover_subtrees( + state_sync_info, + subtrees_metadata, + tx, + grove_version, + ) { next_chunk_ids.extend(res); Ok((next_chunk_ids, new_state_sync_info)) } else { @@ -515,6 +553,7 @@ impl GroveDb { mut state_sync_info: SubtreeStateSyncInfo<'db>, chunk_id: &[u8], chunk_data: Vec, + grove_version: &GroveVersion, ) -> Result<(Vec>, SubtreeStateSyncInfo), Error> { let mut res = vec![]; @@ -529,7 +568,7 @@ impl GroveDb { if !chunk_data.is_empty() { match util_decode_vec_ops(chunk_data) { Ok(ops) => { - match restorer.process_chunk(chunk_id, ops) { + match restorer.process_chunk(chunk_id, ops, grove_version) { Ok(next_chunk_ids) => { state_sync_info.num_processed_chunks += 1; for next_chunk_id in next_chunk_ids { @@ -576,6 +615,7 @@ impl GroveDb { mut state_sync_info: MultiStateSyncInfo<'db>, subtrees_metadata: SubtreesMetadata, tx: &'db Transaction, + grove_version: &GroveVersion, ) -> Result<(Vec>, MultiStateSyncInfo), Error> { let mut res = vec![]; @@ -594,7 +634,7 @@ impl GroveDb { ); let mut subtree_state_sync_info = SubtreeStateSyncInfo::default(); - if let Ok(merk) = self.open_merk_for_replication(path.into(), tx) { + if let Ok(merk) = self.open_merk_for_replication(path.into(), tx, grove_version) { let restorer = Restorer::new(merk, *s_elem_value_hash, Some(*s_actual_value_hash)); subtree_state_sync_info.restorer = Some(restorer); diff --git a/grovedb/src/tests/common.rs b/grovedb/src/tests/common.rs index 2fe8dfde..a02ef9c6 100644 --- a/grovedb/src/tests/common.rs +++ b/grovedb/src/tests/common.rs @@ -1,6 +1,7 @@ //! Common tests use grovedb_path::SubtreePath; +use grovedb_version::version::GroveVersion; use crate::{operations::proof::util::ProvedPathKeyValues, Element, Error}; @@ -17,7 +18,7 @@ pub fn compare_result_tuples( } fn deserialize_and_extract_item_bytes(raw_bytes: &[u8]) -> Result, Error> { - let elem = Element::deserialize(raw_bytes)?; + let elem = Element::deserialize(raw_bytes, GroveVersion::latest())?; match elem { Element::Item(item, _) => Ok(item), _ => Err(Error::CorruptedPath("expected only item type".to_string())), diff --git a/grovedb/src/tests/mod.rs b/grovedb/src/tests/mod.rs index 43a9c34d..226a047b 100644 --- a/grovedb/src/tests/mod.rs +++ b/grovedb/src/tests/mod.rs @@ -13,6 +13,7 @@ use std::{ option::Option::None, }; +use grovedb_version::version::GroveVersion; use grovedb_visualize::{Drawer, Visualize}; use tempfile::TempDir; @@ -67,36 +68,44 @@ pub fn make_empty_grovedb() -> TempGroveDb { } /// A helper method to create GroveDB with one leaf for a root tree -pub fn make_test_grovedb() -> TempGroveDb { +pub fn make_test_grovedb(grove_version: &GroveVersion) -> TempGroveDb { // Tree Structure // root // test_leaf // another_test_leaf let tmp_dir = TempDir::new().unwrap(); let mut db = GroveDb::open(tmp_dir.path()).unwrap(); - add_test_leaves(&mut db); + add_test_leaves(&mut db, grove_version); TempGroveDb { _tmp_dir: tmp_dir, grove_db: db, } } -fn add_test_leaves(db: &mut GroveDb) { - db.insert(EMPTY_PATH, TEST_LEAF, Element::empty_tree(), None, None) - .unwrap() - .expect("successful root tree leaf insert"); +fn add_test_leaves(db: &mut GroveDb, grove_version: &GroveVersion) { + db.insert( + EMPTY_PATH, + TEST_LEAF, + Element::empty_tree(), + None, + None, + grove_version, + ) + .unwrap() + .expect("successful root tree leaf insert"); db.insert( EMPTY_PATH, ANOTHER_TEST_LEAF, Element::empty_tree(), None, None, + grove_version, ) .unwrap() .expect("successful root tree leaf 2 insert"); } -pub fn make_deep_tree() -> TempGroveDb { +pub fn make_deep_tree(grove_version: &GroveVersion) -> TempGroveDb { // Tree Structure // root // test_leaf @@ -136,11 +145,18 @@ pub fn make_deep_tree() -> TempGroveDb { // k14,v14 // Insert elements into grovedb instance - let temp_db = make_test_grovedb(); + let temp_db = make_test_grovedb(grove_version); // add an extra root leaf temp_db - .insert(EMPTY_PATH, DEEP_LEAF, Element::empty_tree(), None, None) + .insert( + EMPTY_PATH, + DEEP_LEAF, + Element::empty_tree(), + None, + None, + grove_version, + ) .unwrap() .expect("successful root tree leaf insert"); @@ -152,6 +168,7 @@ pub fn make_deep_tree() -> TempGroveDb { Element::empty_tree(), None, None, + grove_version, ) .unwrap() .expect("successful subtree insert"); @@ -162,6 +179,7 @@ pub fn make_deep_tree() -> TempGroveDb { Element::empty_tree(), None, None, + grove_version, ) .unwrap() .expect("successful subtree insert"); @@ -172,6 +190,7 @@ pub fn make_deep_tree() -> TempGroveDb { Element::empty_tree(), None, None, + grove_version, ) .unwrap() .expect("successful subtree insert"); @@ -182,6 +201,7 @@ pub fn make_deep_tree() -> TempGroveDb { Element::empty_tree(), None, None, + grove_version, ) .unwrap() .expect("successful subtree insert"); @@ -192,6 +212,7 @@ pub fn make_deep_tree() -> TempGroveDb { Element::empty_tree(), None, None, + grove_version, ) .unwrap() .expect("successful subtree insert"); @@ -202,6 +223,7 @@ pub fn make_deep_tree() -> TempGroveDb { Element::empty_tree(), None, None, + grove_version, ) .unwrap() .expect("successful subtree insert"); @@ -213,6 +235,7 @@ pub fn make_deep_tree() -> TempGroveDb { Element::new_item(b"value1".to_vec()), None, None, + grove_version, ) .unwrap() .expect("successful subtree insert"); @@ -223,6 +246,7 @@ pub fn make_deep_tree() -> TempGroveDb { Element::new_item(b"value2".to_vec()), None, None, + grove_version, ) .unwrap() .expect("successful subtree insert"); @@ -233,6 +257,7 @@ pub fn make_deep_tree() -> TempGroveDb { Element::new_item(b"value3".to_vec()), None, None, + grove_version, ) .unwrap() .expect("successful subtree insert"); @@ -243,6 +268,7 @@ pub fn make_deep_tree() -> TempGroveDb { Element::new_item(b"value4".to_vec()), None, None, + grove_version, ) .unwrap() .expect("successful subtree insert"); @@ -253,6 +279,7 @@ pub fn make_deep_tree() -> TempGroveDb { Element::new_item(b"value5".to_vec()), None, None, + grove_version, ) .unwrap() .expect("successful subtree insert"); @@ -263,6 +290,7 @@ pub fn make_deep_tree() -> TempGroveDb { Element::new_item(b"value3".to_vec()), None, None, + grove_version, ) .unwrap() .expect("successful subtree insert"); @@ -273,6 +301,7 @@ pub fn make_deep_tree() -> TempGroveDb { Element::new_item(b"value4".to_vec()), None, None, + grove_version, ) .unwrap() .expect("successful subtree insert"); @@ -283,6 +312,7 @@ pub fn make_deep_tree() -> TempGroveDb { Element::empty_tree(), None, None, + grove_version, ) .unwrap() .expect("successful subtree insert"); @@ -293,6 +323,7 @@ pub fn make_deep_tree() -> TempGroveDb { Element::empty_tree(), None, None, + grove_version, ) .unwrap() .expect("successful subtree insert"); @@ -303,6 +334,7 @@ pub fn make_deep_tree() -> TempGroveDb { Element::empty_tree(), None, None, + grove_version, ) .unwrap() .expect("successful subtree insert"); @@ -313,6 +345,7 @@ pub fn make_deep_tree() -> TempGroveDb { Element::empty_tree(), None, None, + grove_version, ) .unwrap() .expect("successful subtree insert"); @@ -323,6 +356,7 @@ pub fn make_deep_tree() -> TempGroveDb { Element::empty_tree(), None, None, + grove_version, ) .unwrap() .expect("successful subtree insert"); @@ -334,6 +368,7 @@ pub fn make_deep_tree() -> TempGroveDb { Element::new_item(b"value1".to_vec()), None, None, + grove_version, ) .unwrap() .expect("successful subtree insert"); @@ -344,6 +379,7 @@ pub fn make_deep_tree() -> TempGroveDb { Element::new_item(b"value2".to_vec()), None, None, + grove_version, ) .unwrap() .expect("successful subtree insert"); @@ -354,6 +390,7 @@ pub fn make_deep_tree() -> TempGroveDb { Element::new_item(b"value3".to_vec()), None, None, + grove_version, ) .unwrap() .expect("successful subtree insert"); @@ -364,6 +401,7 @@ pub fn make_deep_tree() -> TempGroveDb { Element::new_item(b"value4".to_vec()), None, None, + grove_version, ) .unwrap() .expect("successful subtree insert"); @@ -374,6 +412,7 @@ pub fn make_deep_tree() -> TempGroveDb { Element::new_item(b"value5".to_vec()), None, None, + grove_version, ) .unwrap() .expect("successful subtree insert"); @@ -384,6 +423,7 @@ pub fn make_deep_tree() -> TempGroveDb { Element::new_item(b"value6".to_vec()), None, None, + grove_version, ) .unwrap() .expect("successful subtree insert"); @@ -395,6 +435,7 @@ pub fn make_deep_tree() -> TempGroveDb { Element::new_item(b"value7".to_vec()), None, None, + grove_version, ) .unwrap() .expect("successful subtree insert"); @@ -405,6 +446,7 @@ pub fn make_deep_tree() -> TempGroveDb { Element::new_item(b"value8".to_vec()), None, None, + grove_version, ) .unwrap() .expect("successful subtree insert"); @@ -415,6 +457,7 @@ pub fn make_deep_tree() -> TempGroveDb { Element::new_item(b"value9".to_vec()), None, None, + grove_version, ) .unwrap() .expect("successful subtree insert"); @@ -425,6 +468,7 @@ pub fn make_deep_tree() -> TempGroveDb { Element::new_item(b"value10".to_vec()), None, None, + grove_version, ) .unwrap() .expect("successful subtree insert"); @@ -435,6 +479,7 @@ pub fn make_deep_tree() -> TempGroveDb { Element::new_item(b"value11".to_vec()), None, None, + grove_version, ) .unwrap() .expect("successful subtree insert"); @@ -445,6 +490,7 @@ pub fn make_deep_tree() -> TempGroveDb { Element::new_item(b"value12".to_vec()), None, None, + grove_version, ) .unwrap() .expect("successful subtree insert"); @@ -455,6 +501,7 @@ pub fn make_deep_tree() -> TempGroveDb { Element::new_item(b"value13".to_vec()), None, None, + grove_version, ) .unwrap() .expect("successful subtree insert"); @@ -465,13 +512,14 @@ pub fn make_deep_tree() -> TempGroveDb { Element::new_item(b"value14".to_vec()), None, None, + grove_version, ) .unwrap() .expect("successful subtree insert"); temp_db } -pub fn make_deep_tree_with_sum_trees() -> TempGroveDb { +pub fn make_deep_tree_with_sum_trees(grove_version: &GroveVersion) -> TempGroveDb { // Tree Structure // root // deep_leaf @@ -506,11 +554,18 @@ pub fn make_deep_tree_with_sum_trees() -> TempGroveDb { // .. -> .. // z -> "z" - let temp_db = make_test_grovedb(); + let temp_db = make_test_grovedb(grove_version); // Add deep_leaf to root temp_db - .insert(EMPTY_PATH, DEEP_LEAF, Element::empty_tree(), None, None) + .insert( + EMPTY_PATH, + DEEP_LEAF, + Element::empty_tree(), + None, + None, + grove_version, + ) .unwrap() .expect("successful root tree leaf insert"); @@ -522,6 +577,7 @@ pub fn make_deep_tree_with_sum_trees() -> TempGroveDb { Element::empty_tree(), None, None, + grove_version, ) .unwrap() .expect("successful subtree insert"); @@ -534,6 +590,7 @@ pub fn make_deep_tree_with_sum_trees() -> TempGroveDb { Element::new_item("empty".as_bytes().to_vec()), None, None, + grove_version, ) .unwrap() .expect("successful item insert"); @@ -546,6 +603,7 @@ pub fn make_deep_tree_with_sum_trees() -> TempGroveDb { Element::new_item("storage".as_bytes().to_vec()), None, None, + grove_version, ) .unwrap() .expect("successful item insert"); @@ -559,6 +617,7 @@ pub fn make_deep_tree_with_sum_trees() -> TempGroveDb { Element::empty_tree(), None, None, + grove_version, ) .unwrap() .expect("successful subtree insert"); @@ -572,6 +631,7 @@ pub fn make_deep_tree_with_sum_trees() -> TempGroveDb { Element::new_sum_tree(None), None, None, + grove_version, ) .unwrap() .expect("successful sum tree insert"); @@ -584,6 +644,7 @@ pub fn make_deep_tree_with_sum_trees() -> TempGroveDb { Element::SumItem(1, None), None, None, + grove_version, ) .unwrap() .expect("successful sum item insert"); @@ -594,6 +655,7 @@ pub fn make_deep_tree_with_sum_trees() -> TempGroveDb { Element::SumItem(1, None), None, None, + grove_version, ) .unwrap() .expect("successful sum item insert"); @@ -607,6 +669,7 @@ pub fn make_deep_tree_with_sum_trees() -> TempGroveDb { Element::new_item(value.to_vec()), None, None, + grove_version, ) .unwrap() .expect("successful item insert"); @@ -618,6 +681,7 @@ pub fn make_deep_tree_with_sum_trees() -> TempGroveDb { Element::new_sum_tree(None), None, None, + grove_version, ) .unwrap() .expect("successful sum tree insert"); @@ -634,6 +698,7 @@ pub fn make_deep_tree_with_sum_trees() -> TempGroveDb { Element::SumItem(value1, None), None, None, + grove_version, ) .unwrap() .expect("successful sum item insert"); @@ -644,6 +709,7 @@ pub fn make_deep_tree_with_sum_trees() -> TempGroveDb { Element::SumItem(value2, None), None, None, + grove_version, ) .unwrap() .expect("successful sum item insert"); @@ -657,6 +723,7 @@ pub fn make_deep_tree_with_sum_trees() -> TempGroveDb { Element::SumItem(4, None), None, None, + grove_version, ) .unwrap() .expect("successful sum item insert"); @@ -667,6 +734,7 @@ pub fn make_deep_tree_with_sum_trees() -> TempGroveDb { Element::SumItem(4, None), None, None, + grove_version, ) .unwrap() .expect("successful sum item insert"); @@ -680,6 +748,7 @@ pub fn make_deep_tree_with_sum_trees() -> TempGroveDb { Element::new_item(vec![letter]), None, None, + grove_version, ) .unwrap() .expect(&format!("successful item insert for {}", letter as char)); @@ -699,7 +768,8 @@ mod tests { #[test] fn test_element_with_flags() { - let db = make_test_grovedb(); + let grove_version = GroveVersion::latest(); + let db = make_test_grovedb(grove_version); db.insert( [TEST_LEAF].as_ref(), @@ -707,6 +777,7 @@ mod tests { Element::empty_tree(), None, None, + grove_version, ) .unwrap() .expect("should insert subtree successfully"); @@ -716,6 +787,7 @@ mod tests { Element::new_item(b"flagless".to_vec()), None, None, + grove_version, ) .unwrap() .expect("should insert subtree successfully"); @@ -725,6 +797,7 @@ mod tests { Element::new_item_with_flags(b"flagged".to_vec(), Some([4, 5, 6, 7, 8].to_vec())), None, None, + grove_version, ) .unwrap() .expect("should insert subtree successfully"); @@ -734,6 +807,7 @@ mod tests { Element::new_tree_with_flags(None, Some([1].to_vec())), None, None, + grove_version, ) .unwrap() .expect("should insert subtree successfully"); @@ -750,24 +824,30 @@ mod tests { ), None, None, + grove_version, ) .unwrap() .expect("should insert subtree successfully"); let element_without_flag = db - .get([TEST_LEAF, b"key1"].as_ref(), b"elem1", None) + .get([TEST_LEAF, b"key1"].as_ref(), b"elem1", None, grove_version) .unwrap() .expect("should get successfully"); let element_with_flag = db - .get([TEST_LEAF, b"key1"].as_ref(), b"elem2", None) + .get([TEST_LEAF, b"key1"].as_ref(), b"elem2", None, grove_version) .unwrap() .expect("should get successfully"); let tree_element_with_flag = db - .get([TEST_LEAF, b"key1"].as_ref(), b"elem3", None) + .get([TEST_LEAF, b"key1"].as_ref(), b"elem3", None, grove_version) .unwrap() .expect("should get successfully"); let flagged_ref_follow = db - .get([TEST_LEAF, b"key1", b"elem3"].as_ref(), b"elem4", None) + .get( + [TEST_LEAF, b"key1", b"elem3"].as_ref(), + b"elem4", + None, + grove_version, + ) .unwrap() .expect("should get successfully"); @@ -785,6 +865,7 @@ mod tests { true, QueryKeyElementPairResultType, None, + grove_version, ) .unwrap() .expect("should get successfully"); @@ -827,23 +908,28 @@ mod tests { SizedQuery::new(query, None, None), ); let proof = db - .prove_query(&path_query, None) + .prove_query(&path_query, None, grove_version) .unwrap() .expect("should successfully create proof"); - let (root_hash, result_set) = - GroveDb::verify_query_raw(&proof, &path_query).expect("should verify proof"); - assert_eq!(root_hash, db.grove_db.root_hash(None).unwrap().unwrap()); + let (root_hash, result_set) = GroveDb::verify_query_raw(&proof, &path_query, grove_version) + .expect("should verify proof"); + assert_eq!( + root_hash, + db.grove_db.root_hash(None, grove_version).unwrap().unwrap() + ); assert_eq!(result_set.len(), 3); assert_eq!( - Element::deserialize(&result_set[0].value).expect("should deserialize element"), + Element::deserialize(&result_set[0].value, grove_version) + .expect("should deserialize element"), Element::Item(b"flagless".to_vec(), None) ); assert_eq!( - Element::deserialize(&result_set[1].value).expect("should deserialize element"), + Element::deserialize(&result_set[1].value, grove_version) + .expect("should deserialize element"), Element::Item(b"flagged".to_vec(), Some([4, 5, 6, 7, 8].to_vec())) ); assert_eq!( - Element::deserialize(&result_set[2].value) + Element::deserialize(&result_set[2].value, grove_version) .expect("should deserialize element") .get_flags(), &Some([1].to_vec()) @@ -852,13 +938,14 @@ mod tests { #[test] fn test_cannot_update_populated_tree_item() { + let grove_version = GroveVersion::latest(); // This test shows that you cannot update a tree item - // in a way that disconnects it's root hash from that of + // in a way that disconnects its root hash from that of // the merk it points to. - let db = make_deep_tree(); + let db = make_deep_tree(grove_version); let old_element = db - .get([TEST_LEAF].as_ref(), b"innertree", None) + .get([TEST_LEAF].as_ref(), b"innertree", None, grove_version) .unwrap() .expect("should fetch item"); @@ -869,12 +956,13 @@ mod tests { new_element.clone(), None, None, + grove_version, ) .unwrap() .expect_err("should not override tree"); let current_element = db - .get([TEST_LEAF].as_ref(), b"innertree", None) + .get([TEST_LEAF].as_ref(), b"innertree", None, grove_version) .unwrap() .expect("should fetch item"); @@ -884,8 +972,9 @@ mod tests { #[test] fn test_changes_propagated() { - let db = make_test_grovedb(); - let old_hash = db.root_hash(None).unwrap().unwrap(); + let grove_version = GroveVersion::latest(); + let db = make_test_grovedb(grove_version); + let old_hash = db.root_hash(None, grove_version).unwrap().unwrap(); let element = Element::new_item(b"ayy".to_vec()); // Insert some nested subtrees @@ -895,6 +984,7 @@ mod tests { Element::empty_tree(), None, None, + grove_version, ) .unwrap() .expect("successful subtree 1 insert"); @@ -905,6 +995,7 @@ mod tests { Element::empty_tree(), None, None, + grove_version, ) .unwrap() .expect("successful subtree 2 insert"); @@ -915,30 +1006,41 @@ mod tests { element.clone(), None, None, + grove_version, ) .unwrap() .expect("successful value insert"); assert_eq!( - db.get([TEST_LEAF, b"key1", b"key2"].as_ref(), b"key3", None) - .unwrap() - .expect("successful get"), + db.get( + [TEST_LEAF, b"key1", b"key2"].as_ref(), + b"key3", + None, + grove_version + ) + .unwrap() + .expect("successful get"), element ); - assert_ne!(old_hash, db.root_hash(None).unwrap().unwrap()); + assert_ne!( + old_hash, + db.root_hash(None, grove_version).unwrap().unwrap() + ); } // TODO: Add solid test cases to this #[test] fn test_references() { - let db = make_test_grovedb(); + let grove_version = GroveVersion::latest(); + let db = make_test_grovedb(grove_version); db.insert( [TEST_LEAF].as_ref(), b"merk_1", Element::empty_tree(), None, None, + grove_version, ) .unwrap() .expect("successful subtree insert"); @@ -948,6 +1050,7 @@ mod tests { Element::new_item(b"value1".to_vec()), None, None, + grove_version, ) .unwrap() .expect("successful subtree insert"); @@ -957,6 +1060,7 @@ mod tests { Element::new_item(b"value2".to_vec()), None, None, + grove_version, ) .unwrap() .expect("successful subtree insert"); @@ -967,6 +1071,7 @@ mod tests { Element::empty_tree(), None, None, + grove_version, ) .unwrap() .expect("successful subtree insert"); @@ -983,6 +1088,7 @@ mod tests { ])), None, None, + grove_version, ) .unwrap() .expect("successful subtree insert"); @@ -996,22 +1102,24 @@ mod tests { ])), None, None, + grove_version, ) .unwrap() .expect("successful subtree insert"); assert!(db - .get([TEST_LEAF].as_ref(), b"merk_1", None) + .get([TEST_LEAF].as_ref(), b"merk_1", None, grove_version) .unwrap() .is_ok()); assert!(db - .get([TEST_LEAF].as_ref(), b"merk_2", None) + .get([TEST_LEAF].as_ref(), b"merk_2", None, grove_version) .unwrap() .is_ok()); } #[test] fn test_follow_references() { - let db = make_test_grovedb(); + let grove_version = GroveVersion::latest(); + let db = make_test_grovedb(grove_version); let element = Element::new_item(b"ayy".to_vec()); // Insert an item to refer to @@ -1021,6 +1129,7 @@ mod tests { Element::empty_tree(), None, None, + grove_version, ) .unwrap() .expect("successful subtree 1 insert"); @@ -1030,6 +1139,7 @@ mod tests { element.clone(), None, None, + grove_version, ) .unwrap() .expect("successful value insert"); @@ -1045,12 +1155,13 @@ mod tests { ])), None, None, + grove_version, ) .unwrap() .expect("successful reference insert"); assert_eq!( - db.get([TEST_LEAF].as_ref(), b"reference_key", None) + db.get([TEST_LEAF].as_ref(), b"reference_key", None, grove_version) .unwrap() .expect("successful get"), element @@ -1059,7 +1170,8 @@ mod tests { #[test] fn test_reference_must_point_to_item() { - let db = make_test_grovedb(); + let grove_version = GroveVersion::latest(); + let db = make_test_grovedb(grove_version); let result = db .insert( @@ -1071,6 +1183,7 @@ mod tests { ])), None, None, + grove_version, ) .unwrap(); @@ -1079,8 +1192,9 @@ mod tests { #[test] fn test_too_many_indirections() { + let grove_version = GroveVersion::latest(); use crate::operations::get::MAX_REFERENCE_HOPS; - let db = make_test_grovedb(); + let db = make_test_grovedb(grove_version); let keygen = |idx| format!("key{}", idx).bytes().collect::>(); @@ -1090,6 +1204,7 @@ mod tests { Element::new_item(b"oops".to_vec()), None, None, + grove_version, ) .unwrap() .expect("successful item insert"); @@ -1104,6 +1219,7 @@ mod tests { ])), None, None, + grove_version, ) .unwrap() .expect("successful reference insert"); @@ -1119,12 +1235,18 @@ mod tests { ])), None, None, + grove_version, ) .unwrap() .expect("expected insert"); let result = db - .get([TEST_LEAF].as_ref(), &keygen(MAX_REFERENCE_HOPS + 1), None) + .get( + [TEST_LEAF].as_ref(), + &keygen(MAX_REFERENCE_HOPS + 1), + None, + grove_version, + ) .unwrap(); assert!(matches!(result, Err(Error::ReferenceLimit))); @@ -1132,7 +1254,8 @@ mod tests { #[test] fn test_reference_value_affects_state() { - let db_one = make_test_grovedb(); + let grove_version = GroveVersion::latest(); + let db_one = make_test_grovedb(grove_version); db_one .insert( [TEST_LEAF].as_ref(), @@ -1140,6 +1263,7 @@ mod tests { Element::new_item(vec![0]), None, None, + grove_version, ) .unwrap() .expect("should insert item"); @@ -1153,11 +1277,12 @@ mod tests { ])), None, None, + grove_version, ) .unwrap() .expect("should insert item"); - let db_two = make_test_grovedb(); + let db_two = make_test_grovedb(grove_version); db_two .insert( [TEST_LEAF].as_ref(), @@ -1165,6 +1290,7 @@ mod tests { Element::new_item(vec![0]), None, None, + grove_version, ) .unwrap() .expect("should insert item"); @@ -1178,17 +1304,18 @@ mod tests { )), None, None, + grove_version, ) .unwrap() .expect("should insert item"); assert_ne!( db_one - .root_hash(None) + .root_hash(None, grove_version) .unwrap() .expect("should return root hash"), db_two - .root_hash(None) + .root_hash(None, grove_version) .unwrap() .expect("should return toor hash") ); @@ -1196,12 +1323,13 @@ mod tests { #[test] fn test_tree_structure_is_persistent() { + let grove_version = GroveVersion::latest(); let tmp_dir = TempDir::new().unwrap(); let element = Element::new_item(b"ayy".to_vec()); // Create a scoped GroveDB let prev_root_hash = { let mut db = GroveDb::open(tmp_dir.path()).unwrap(); - add_test_leaves(&mut db); + add_test_leaves(&mut db, grove_version); // Insert some nested subtrees db.insert( @@ -1210,6 +1338,7 @@ mod tests { Element::empty_tree(), None, None, + grove_version, ) .unwrap() .expect("successful subtree 1 insert"); @@ -1219,6 +1348,7 @@ mod tests { Element::empty_tree(), None, None, + grove_version, ) .unwrap() .expect("successful subtree 2 insert"); @@ -1229,71 +1359,105 @@ mod tests { element.clone(), None, None, + grove_version, ) .unwrap() .expect("successful value insert"); assert_eq!( - db.get([TEST_LEAF, b"key1", b"key2"].as_ref(), b"key3", None) - .unwrap() - .expect("successful get 1"), + db.get( + [TEST_LEAF, b"key1", b"key2"].as_ref(), + b"key3", + None, + grove_version + ) + .unwrap() + .expect("successful get 1"), element ); - db.root_hash(None).unwrap().unwrap() + db.root_hash(None, grove_version).unwrap().unwrap() }; // Open a persisted GroveDB let db = GroveDb::open(tmp_dir).unwrap(); assert_eq!( - db.get([TEST_LEAF, b"key1", b"key2"].as_ref(), b"key3", None) - .unwrap() - .expect("successful get 2"), + db.get( + [TEST_LEAF, b"key1", b"key2"].as_ref(), + b"key3", + None, + grove_version + ) + .unwrap() + .expect("successful get 2"), element ); assert!(db - .get([TEST_LEAF, b"key1", b"key2"].as_ref(), b"key4", None) + .get( + [TEST_LEAF, b"key1", b"key2"].as_ref(), + b"key4", + None, + grove_version + ) .unwrap() .is_err()); - assert_eq!(prev_root_hash, db.root_hash(None).unwrap().unwrap()); + assert_eq!( + prev_root_hash, + db.root_hash(None, grove_version).unwrap().unwrap() + ); } #[test] fn test_root_tree_leaves_are_noted() { - let db = make_test_grovedb(); - db.check_subtree_exists_path_not_found([TEST_LEAF].as_ref().into(), None) - .unwrap() - .expect("should exist"); - db.check_subtree_exists_path_not_found([ANOTHER_TEST_LEAF].as_ref().into(), None) + let grove_version = GroveVersion::latest(); + let db = make_test_grovedb(grove_version); + db.check_subtree_exists_path_not_found([TEST_LEAF].as_ref().into(), None, grove_version) .unwrap() .expect("should exist"); + db.check_subtree_exists_path_not_found( + [ANOTHER_TEST_LEAF].as_ref().into(), + None, + grove_version, + ) + .unwrap() + .expect("should exist"); } #[test] fn test_proof_for_invalid_path_root_key() { - let db = make_test_grovedb(); + let grove_version = GroveVersion::latest(); + let db = make_test_grovedb(grove_version); let query = Query::new(); let path_query = PathQuery::new_unsized(vec![b"invalid_path_key".to_vec()], query); - let proof = db.prove_query(&path_query, None).unwrap().unwrap(); + let proof = db + .prove_query(&path_query, None, grove_version) + .unwrap() + .unwrap(); let (hash, result_set) = - GroveDb::verify_query_raw(proof.as_slice(), &path_query).expect("should execute proof"); + GroveDb::verify_query_raw(proof.as_slice(), &path_query, grove_version) + .expect("should execute proof"); - assert_eq!(hash, db.root_hash(None).unwrap().unwrap()); + assert_eq!(hash, db.root_hash(None, grove_version).unwrap().unwrap()); assert_eq!(result_set.len(), 0); } #[test] fn test_proof_for_invalid_path() { - let db = make_deep_tree(); + let grove_version = GroveVersion::latest(); + let db = make_deep_tree(grove_version); let query = Query::new(); let path_query = PathQuery::new_unsized(vec![b"deep_leaf".to_vec(), b"invalid_key".to_vec()], query); - let proof = db.prove_query(&path_query, None).unwrap().unwrap(); + let proof = db + .prove_query(&path_query, None, grove_version) + .unwrap() + .unwrap(); let (hash, result_set) = - GroveDb::verify_query_raw(proof.as_slice(), &path_query).expect("should execute proof"); + GroveDb::verify_query_raw(proof.as_slice(), &path_query, grove_version) + .expect("should execute proof"); - assert_eq!(hash, db.root_hash(None).unwrap().unwrap()); + assert_eq!(hash, db.root_hash(None, grove_version).unwrap().unwrap()); assert_eq!(result_set.len(), 0); let query = Query::new(); @@ -1306,11 +1470,15 @@ mod tests { query, ); - let proof = db.prove_query(&path_query, None).unwrap().unwrap(); + let proof = db + .prove_query(&path_query, None, grove_version) + .unwrap() + .unwrap(); let (hash, result_set) = - GroveDb::verify_query_raw(proof.as_slice(), &path_query).expect("should execute proof"); + GroveDb::verify_query_raw(proof.as_slice(), &path_query, grove_version) + .expect("should execute proof"); - assert_eq!(hash, db.root_hash(None).unwrap().unwrap()); + assert_eq!(hash, db.root_hash(None, grove_version).unwrap().unwrap()); assert_eq!(result_set.len(), 0); let query = Query::new(); @@ -1324,11 +1492,15 @@ mod tests { query, ); - let proof = db.prove_query(&path_query, None).unwrap().unwrap(); + let proof = db + .prove_query(&path_query, None, grove_version) + .unwrap() + .unwrap(); let (hash, result_set) = - GroveDb::verify_query_raw(proof.as_slice(), &path_query).expect("should execute proof"); + GroveDb::verify_query_raw(proof.as_slice(), &path_query, grove_version) + .expect("should execute proof"); - assert_eq!(hash, db.root_hash(None).unwrap().unwrap()); + assert_eq!(hash, db.root_hash(None, grove_version).unwrap().unwrap()); assert_eq!(result_set.len(), 0); let query = Query::new(); @@ -1342,17 +1514,22 @@ mod tests { query, ); - let proof = db.prove_query(&path_query, None).unwrap().unwrap(); + let proof = db + .prove_query(&path_query, None, grove_version) + .unwrap() + .unwrap(); let (hash, result_set) = - GroveDb::verify_query_raw(proof.as_slice(), &path_query).expect("should execute proof"); + GroveDb::verify_query_raw(proof.as_slice(), &path_query, grove_version) + .expect("should execute proof"); - assert_eq!(hash, db.root_hash(None).unwrap().unwrap()); + assert_eq!(hash, db.root_hash(None, grove_version).unwrap().unwrap()); assert_eq!(result_set.len(), 0); } #[test] fn test_proof_for_non_existent_data() { - let temp_db = make_test_grovedb(); + let grove_version = GroveVersion::latest(); + let temp_db = make_test_grovedb(grove_version); let mut query = Query::new(); query.insert_key(b"key1".to_vec()); @@ -1360,16 +1537,24 @@ mod tests { // path to empty subtree let path_query = PathQuery::new_unsized(vec![TEST_LEAF.to_vec()], query); - let proof = temp_db.prove_query(&path_query, None).unwrap().unwrap(); + let proof = temp_db + .prove_query(&path_query, None, grove_version) + .unwrap() + .unwrap(); let (hash, result_set) = - GroveDb::verify_query_raw(proof.as_slice(), &path_query).expect("should execute proof"); + GroveDb::verify_query_raw(proof.as_slice(), &path_query, grove_version) + .expect("should execute proof"); - assert_eq!(hash, temp_db.root_hash(None).unwrap().unwrap()); + assert_eq!( + hash, + temp_db.root_hash(None, grove_version).unwrap().unwrap() + ); assert_eq!(result_set.len(), 0); } #[test] fn test_path_query_proofs_without_subquery_with_reference() { + let grove_version = GroveVersion::latest(); // Tree Structure // root // test_leaf @@ -1386,7 +1571,7 @@ mod tests { // k4,v4 // Insert elements into grovedb instance - let temp_db = make_test_grovedb(); + let temp_db = make_test_grovedb(grove_version); // Insert level 1 nodes temp_db .insert( @@ -1395,6 +1580,7 @@ mod tests { Element::empty_tree(), None, None, + grove_version, ) .unwrap() .expect("successful subtree insert"); @@ -1405,6 +1591,7 @@ mod tests { Element::empty_tree(), None, None, + grove_version, ) .unwrap() .expect("successful subtree insert"); @@ -1415,6 +1602,7 @@ mod tests { Element::empty_tree(), None, None, + grove_version, ) .unwrap() .expect("successful subtree insert"); @@ -1426,6 +1614,7 @@ mod tests { Element::new_item(b"value1".to_vec()), None, None, + grove_version, ) .unwrap() .expect("successful subtree insert"); @@ -1436,6 +1625,7 @@ mod tests { Element::new_item(b"value2".to_vec()), None, None, + grove_version, ) .unwrap() .expect("successful subtree insert"); @@ -1446,6 +1636,7 @@ mod tests { Element::new_item(b"value3".to_vec()), None, None, + grove_version, ) .unwrap() .expect("successful subtree insert"); @@ -1456,6 +1647,7 @@ mod tests { Element::new_item(b"value3".to_vec()), None, None, + grove_version, ) .unwrap() .expect("successful subtree insert"); @@ -1470,6 +1662,7 @@ mod tests { ])), None, None, + grove_version, ) .unwrap() .expect("successful subtree insert"); @@ -1480,6 +1673,7 @@ mod tests { Element::new_item(b"value4".to_vec()), None, None, + grove_version, ) .unwrap() .expect("successful subtree insert"); @@ -1494,6 +1688,7 @@ mod tests { ])), None, None, + grove_version, ) .unwrap() .expect("successful subtree insert"); @@ -1507,7 +1702,10 @@ mod tests { query, ); - let proof = temp_db.prove_query(&path_query, None).unwrap().unwrap(); + let proof = temp_db + .prove_query(&path_query, None, grove_version) + .unwrap() + .unwrap(); assert_eq!( hex::encode(&proof), "005e02cfb7d035b8f4a3631be46c597510a16770c15c74331b3dc8dcb577a206e49675040a746\ @@ -1521,11 +1719,19 @@ mod tests { 4ffdbc429a89c9b6620e7224d73c2ee505eb7e6fb5eb574e1a8dc8b0d0884110001" ); let (hash, result_set) = - GroveDb::verify_query_raw(proof.as_slice(), &path_query).expect("should execute proof"); + GroveDb::verify_query_raw(proof.as_slice(), &path_query, grove_version) + .expect("should execute proof"); - assert_eq!(hash, temp_db.root_hash(None).unwrap().unwrap()); - let r1 = Element::new_item(b"value1".to_vec()).serialize().unwrap(); - let r2 = Element::new_item(b"value4".to_vec()).serialize().unwrap(); + assert_eq!( + hash, + temp_db.root_hash(None, grove_version).unwrap().unwrap() + ); + let r1 = Element::new_item(b"value1".to_vec()) + .serialize(grove_version) + .unwrap(); + let r2 = Element::new_item(b"value4".to_vec()) + .serialize(grove_version) + .unwrap(); compare_result_tuples( result_set, @@ -1535,6 +1741,7 @@ mod tests { #[test] fn test_path_query_proofs_without_subquery() { + let grove_version = GroveVersion::latest(); // Tree Structure // root // test_leaf @@ -1549,7 +1756,7 @@ mod tests { // k4,v4 // Insert elements into grovedb instance - let temp_db = make_test_grovedb(); + let temp_db = make_test_grovedb(grove_version); // Insert level 1 nodes temp_db .insert( @@ -1558,6 +1765,7 @@ mod tests { Element::empty_tree(), None, None, + grove_version, ) .unwrap() .expect("successful subtree insert"); @@ -1568,6 +1776,7 @@ mod tests { Element::empty_tree(), None, None, + grove_version, ) .unwrap() .expect("successful subtree insert"); @@ -1578,6 +1787,7 @@ mod tests { Element::empty_tree(), None, None, + grove_version, ) .unwrap() .expect("successful subtree insert"); @@ -1589,6 +1799,7 @@ mod tests { Element::new_item(b"value1".to_vec()), None, None, + grove_version, ) .unwrap() .expect("successful subtree insert"); @@ -1599,6 +1810,7 @@ mod tests { Element::new_item(b"value2".to_vec()), None, None, + grove_version, ) .unwrap() .expect("successful subtree insert"); @@ -1609,6 +1821,7 @@ mod tests { Element::new_item(b"value3".to_vec()), None, None, + grove_version, ) .unwrap() .expect("successful subtree insert"); @@ -1619,6 +1832,7 @@ mod tests { Element::new_item(b"value3".to_vec()), None, None, + grove_version, ) .unwrap() .expect("successful subtree insert"); @@ -1629,6 +1843,7 @@ mod tests { Element::new_item(b"value4".to_vec()), None, None, + grove_version, ) .unwrap() .expect("successful subtree insert"); @@ -1640,7 +1855,10 @@ mod tests { let path_query = PathQuery::new_unsized(vec![TEST_LEAF.to_vec(), b"innertree".to_vec()], query); - let proof = temp_db.prove_query(&path_query, None).unwrap().unwrap(); + let proof = temp_db + .prove_query(&path_query, None, grove_version) + .unwrap() + .unwrap(); assert_eq!( hex::encode(proof.as_slice()), "005c0409746573745f6c656166000d020109696e6e65727472656500fafa16d06e8d8696dae443731\ @@ -1652,10 +1870,16 @@ mod tests { b979cbe4a51e0b2f08d110001" ); let (hash, result_set) = - GroveDb::verify_query_raw(proof.as_slice(), &path_query).expect("should execute proof"); + GroveDb::verify_query_raw(proof.as_slice(), &path_query, grove_version) + .expect("should execute proof"); - assert_eq!(hash, temp_db.root_hash(None).unwrap().unwrap()); - let r1 = Element::new_item(b"value1".to_vec()).serialize().unwrap(); + assert_eq!( + hash, + temp_db.root_hash(None, grove_version).unwrap().unwrap() + ); + let r1 = Element::new_item(b"value1".to_vec()) + .serialize(grove_version) + .unwrap(); compare_result_tuples(result_set, vec![(b"key1".to_vec(), r1)]); // Range query + limit @@ -1666,12 +1890,21 @@ mod tests { SizedQuery::new(query, Some(1), None), ); - let proof = temp_db.prove_query(&path_query, None).unwrap().unwrap(); + let proof = temp_db + .prove_query(&path_query, None, grove_version) + .unwrap() + .unwrap(); let (hash, result_set) = - GroveDb::verify_query_raw(proof.as_slice(), &path_query).expect("should execute proof"); + GroveDb::verify_query_raw(proof.as_slice(), &path_query, grove_version) + .expect("should execute proof"); - assert_eq!(hash, temp_db.root_hash(None).unwrap().unwrap()); - let r1 = Element::new_item(b"value2".to_vec()).serialize().unwrap(); + assert_eq!( + hash, + temp_db.root_hash(None, grove_version).unwrap().unwrap() + ); + let r1 = Element::new_item(b"value2".to_vec()) + .serialize(grove_version) + .unwrap(); compare_result_tuples(result_set, vec![(b"key2".to_vec(), r1)]); // Range query + direction + limit @@ -1682,13 +1915,24 @@ mod tests { SizedQuery::new(query, Some(2), None), ); - let proof = temp_db.prove_query(&path_query, None).unwrap().unwrap(); + let proof = temp_db + .prove_query(&path_query, None, grove_version) + .unwrap() + .unwrap(); let (hash, result_set) = - GroveDb::verify_query_raw(proof.as_slice(), &path_query).expect("should execute proof"); + GroveDb::verify_query_raw(proof.as_slice(), &path_query, grove_version) + .expect("should execute proof"); - assert_eq!(hash, temp_db.root_hash(None).unwrap().unwrap()); - let r1 = Element::new_item(b"value3".to_vec()).serialize().unwrap(); - let r2 = Element::new_item(b"value2".to_vec()).serialize().unwrap(); + assert_eq!( + hash, + temp_db.root_hash(None, grove_version).unwrap().unwrap() + ); + let r1 = Element::new_item(b"value3".to_vec()) + .serialize(grove_version) + .unwrap(); + let r2 = Element::new_item(b"value2".to_vec()) + .serialize(grove_version) + .unwrap(); compare_result_tuples( result_set, vec![(b"key3".to_vec(), r1), (b"key2".to_vec(), r2)], @@ -1697,7 +1941,8 @@ mod tests { #[test] fn test_path_query_proofs_with_default_subquery() { - let temp_db = make_deep_tree(); + let grove_version = GroveVersion::latest(); + let temp_db = make_deep_tree(grove_version); let mut query = Query::new(); query.insert_all(); @@ -1708,11 +1953,18 @@ mod tests { let path_query = PathQuery::new_unsized(vec![TEST_LEAF.to_vec()], query); - let proof = temp_db.prove_query(&path_query, None).unwrap().unwrap(); + let proof = temp_db + .prove_query(&path_query, None, grove_version) + .unwrap() + .unwrap(); let (hash, result_set) = - GroveDb::verify_query_raw(proof.as_slice(), &path_query).expect("should execute proof"); + GroveDb::verify_query_raw(proof.as_slice(), &path_query, grove_version) + .expect("should execute proof"); - assert_eq!(hash, temp_db.root_hash(None).unwrap().unwrap()); + assert_eq!( + hash, + temp_db.root_hash(None, grove_version).unwrap().unwrap() + ); assert_eq!(result_set.len(), 5); let keys = [ @@ -1729,7 +1981,7 @@ mod tests { b"value4".to_vec(), b"value5".to_vec(), ]; - let elements = values.map(|x| Element::new_item(x).serialize().unwrap()); + let elements = values.map(|x| Element::new_item(x).serialize(grove_version).unwrap()); let expected_result_set: Vec<(Vec, Vec)> = keys.into_iter().zip(elements).collect(); compare_result_tuples(result_set, expected_result_set); @@ -1742,16 +1994,23 @@ mod tests { let path_query = PathQuery::new_unsized(vec![TEST_LEAF.to_vec()], query); - let proof = temp_db.prove_query(&path_query, None).unwrap().unwrap(); + let proof = temp_db + .prove_query(&path_query, None, grove_version) + .unwrap() + .unwrap(); let (hash, result_set) = - GroveDb::verify_query_raw(proof.as_slice(), &path_query).expect("should execute proof"); + GroveDb::verify_query_raw(proof.as_slice(), &path_query, grove_version) + .expect("should execute proof"); - assert_eq!(hash, temp_db.root_hash(None).unwrap().unwrap()); + assert_eq!( + hash, + temp_db.root_hash(None, grove_version).unwrap().unwrap() + ); assert_eq!(result_set.len(), 2); let keys = [b"key4".to_vec(), b"key5".to_vec()]; let values = [b"value4".to_vec(), b"value5".to_vec()]; - let elements = values.map(|x| Element::new_item(x).serialize().unwrap()); + let elements = values.map(|x| Element::new_item(x).serialize(grove_version).unwrap()); let expected_result_set: Vec<(Vec, Vec)> = keys.into_iter().zip(elements).collect(); compare_result_tuples(result_set, expected_result_set); @@ -1765,18 +2024,25 @@ mod tests { let path_query = PathQuery::new_unsized(vec![TEST_LEAF.to_vec()], query); - let proof = temp_db.prove_query(&path_query, None).unwrap().unwrap(); - let (hash, result_set) = GroveDb::verify_query_raw(proof.as_slice(), &path_query).expect( - "should + let proof = temp_db + .prove_query(&path_query, None, grove_version) + .unwrap() + .unwrap(); + let (hash, result_set) = + GroveDb::verify_query_raw(proof.as_slice(), &path_query, grove_version).expect( + "should execute proof", - ); + ); - assert_eq!(hash, temp_db.root_hash(None).unwrap().unwrap()); + assert_eq!( + hash, + temp_db.root_hash(None, grove_version).unwrap().unwrap() + ); assert_eq!(result_set.len(), 3); let keys = [b"key2".to_vec(), b"key3".to_vec(), b"key4".to_vec()]; let values = [b"value2".to_vec(), b"value3".to_vec(), b"value4".to_vec()]; - let elements = values.map(|x| Element::new_item(x).serialize().unwrap()); + let elements = values.map(|x| Element::new_item(x).serialize(grove_version).unwrap()); let expected_result_set: Vec<(Vec, Vec)> = keys.into_iter().zip(elements).collect(); compare_result_tuples(result_set, expected_result_set); @@ -1795,11 +2061,18 @@ mod tests { let path_query = PathQuery::new_unsized(vec![DEEP_LEAF.to_vec()], query); - let proof = temp_db.prove_query(&path_query, None).unwrap().unwrap(); + let proof = temp_db + .prove_query(&path_query, None, grove_version) + .unwrap() + .unwrap(); let (hash, result_set) = - GroveDb::verify_query_raw(proof.as_slice(), &path_query).expect("should execute proof"); + GroveDb::verify_query_raw(proof.as_slice(), &path_query, grove_version) + .expect("should execute proof"); - assert_eq!(hash, temp_db.root_hash(None).unwrap().unwrap()); + assert_eq!( + hash, + temp_db.root_hash(None, grove_version).unwrap().unwrap() + ); assert_eq!(result_set.len(), 14); let keys = [ @@ -1834,14 +2107,15 @@ mod tests { b"value13".to_vec(), b"value14".to_vec(), ]; - let elements = values.map(|x| Element::new_item(x).serialize().unwrap()); + let elements = values.map(|x| Element::new_item(x).serialize(grove_version).unwrap()); let expected_result_set: Vec<(Vec, Vec)> = keys.into_iter().zip(elements).collect(); compare_result_tuples(result_set, expected_result_set); } #[test] fn test_path_query_proofs_with_subquery_path() { - let temp_db = make_deep_tree(); + let grove_version = GroveVersion::latest(); + let temp_db = make_deep_tree(grove_version); let mut query = Query::new(); query.insert_all(); @@ -1854,16 +2128,23 @@ mod tests { let path_query = PathQuery::new_unsized(vec![DEEP_LEAF.to_vec()], query); - let proof = temp_db.prove_query(&path_query, None).unwrap().unwrap(); + let proof = temp_db + .prove_query(&path_query, None, grove_version) + .unwrap() + .unwrap(); let (hash, result_set) = - GroveDb::verify_query_raw(proof.as_slice(), &path_query).expect("should execute proof"); + GroveDb::verify_query_raw(proof.as_slice(), &path_query, grove_version) + .expect("should execute proof"); - assert_eq!(hash, temp_db.root_hash(None).unwrap().unwrap()); + assert_eq!( + hash, + temp_db.root_hash(None, grove_version).unwrap().unwrap() + ); assert_eq!(result_set.len(), 3); let keys = [b"key1".to_vec(), b"key2".to_vec(), b"key3".to_vec()]; let values = [b"value1".to_vec(), b"value2".to_vec(), b"value3".to_vec()]; - let elements = values.map(|x| Element::new_item(x).serialize().unwrap()); + let elements = values.map(|x| Element::new_item(x).serialize(grove_version).unwrap()); let expected_result_set: Vec<(Vec, Vec)> = keys.into_iter().zip(elements).collect(); compare_result_tuples(result_set, expected_result_set); @@ -1878,15 +2159,22 @@ mod tests { query.set_subquery(subq); let path_query = PathQuery::new_unsized(vec![], query); - let proof = temp_db.prove_query(&path_query, None).unwrap().unwrap(); + let proof = temp_db + .prove_query(&path_query, None, grove_version) + .unwrap() + .unwrap(); let (hash, result_set) = - GroveDb::verify_query_raw(proof.as_slice(), &path_query).expect("should execute proof"); - assert_eq!(hash, temp_db.root_hash(None).unwrap().unwrap()); + GroveDb::verify_query_raw(proof.as_slice(), &path_query, grove_version) + .expect("should execute proof"); + assert_eq!( + hash, + temp_db.root_hash(None, grove_version).unwrap().unwrap() + ); assert_eq!(result_set.len(), 3); let keys = [b"key1".to_vec(), b"key2".to_vec(), b"key3".to_vec()]; let values = [b"value1".to_vec(), b"value2".to_vec(), b"value3".to_vec()]; - let elements = values.map(|x| Element::new_item(x).serialize().unwrap()); + let elements = values.map(|x| Element::new_item(x).serialize(grove_version).unwrap()); let expected_result_set: Vec<(Vec, Vec)> = keys.into_iter().zip(elements).collect(); compare_result_tuples(result_set, expected_result_set); @@ -1902,10 +2190,17 @@ mod tests { let path_query = PathQuery::new_unsized(vec![b"deep_leaf".to_vec(), b"deep_node_1".to_vec()], query); - let proof = temp_db.prove_query(&path_query, None).unwrap().unwrap(); + let proof = temp_db + .prove_query(&path_query, None, grove_version) + .unwrap() + .unwrap(); let (hash, result_set) = - GroveDb::verify_query_raw(proof.as_slice(), &path_query).expect("should execute proof"); - assert_eq!(hash, temp_db.root_hash(None).unwrap().unwrap()); + GroveDb::verify_query_raw(proof.as_slice(), &path_query, grove_version) + .expect("should execute proof"); + assert_eq!( + hash, + temp_db.root_hash(None, grove_version).unwrap().unwrap() + ); assert_eq!(result_set.len(), 6); let keys = [ @@ -1924,7 +2219,7 @@ mod tests { b"value5".to_vec(), b"value6".to_vec(), ]; - let elements = values.map(|x| Element::new_item(x).serialize().unwrap()); + let elements = values.map(|x| Element::new_item(x).serialize(grove_version).unwrap()); let expected_result_set: Vec<(Vec, Vec)> = keys.into_iter().zip(elements).collect(); compare_result_tuples(result_set, expected_result_set); @@ -1944,16 +2239,24 @@ mod tests { query.set_subquery(subq); let path_query = PathQuery::new_unsized(vec![], query); - let proof = temp_db.prove_query(&path_query, None).unwrap().unwrap(); + let proof = temp_db + .prove_query(&path_query, None, grove_version) + .unwrap() + .unwrap(); let (hash, result_set) = - GroveDb::verify_query_raw(proof.as_slice(), &path_query).expect("should execute proof"); - assert_eq!(hash, temp_db.root_hash(None).unwrap().unwrap()); + GroveDb::verify_query_raw(proof.as_slice(), &path_query, grove_version) + .expect("should execute proof"); + assert_eq!( + hash, + temp_db.root_hash(None, grove_version).unwrap().unwrap() + ); assert_eq!(result_set.len(), 0); } #[test] fn test_path_query_proofs_with_key_and_subquery() { - let temp_db = make_deep_tree(); + let grove_version = GroveVersion::latest(); + let temp_db = make_deep_tree(grove_version); let mut query = Query::new(); query.insert_key(b"deep_node_1".to_vec()); @@ -1966,23 +2269,31 @@ mod tests { let path_query = PathQuery::new_unsized(vec![DEEP_LEAF.to_vec()], query); - let proof = temp_db.prove_query(&path_query, None).unwrap().unwrap(); + let proof = temp_db + .prove_query(&path_query, None, grove_version) + .unwrap() + .unwrap(); let (hash, result_set) = - GroveDb::verify_query_raw(proof.as_slice(), &path_query).expect("should execute proof"); + GroveDb::verify_query_raw(proof.as_slice(), &path_query, grove_version) + .expect("should execute proof"); - assert_eq!(hash, temp_db.root_hash(None).unwrap().unwrap()); + assert_eq!( + hash, + temp_db.root_hash(None, grove_version).unwrap().unwrap() + ); assert_eq!(result_set.len(), 3); let keys = [b"key1".to_vec(), b"key2".to_vec(), b"key3".to_vec()]; let values = [b"value1".to_vec(), b"value2".to_vec(), b"value3".to_vec()]; - let elements = values.map(|x| Element::new_item(x).serialize().unwrap()); + let elements = values.map(|x| Element::new_item(x).serialize(grove_version).unwrap()); let expected_result_set: Vec<(Vec, Vec)> = keys.into_iter().zip(elements).collect(); compare_result_tuples(result_set, expected_result_set); } #[test] fn test_path_query_proofs_with_conditional_subquery() { - let temp_db = make_deep_tree(); + let grove_version = GroveVersion::latest(); + let temp_db = make_deep_tree(grove_version); let mut query = Query::new(); query.insert_all(); @@ -2002,11 +2313,18 @@ mod tests { query.set_subquery(subquery); let path_query = PathQuery::new_unsized(vec![DEEP_LEAF.to_vec()], query); - let proof = temp_db.prove_query(&path_query, None).unwrap().unwrap(); + let proof = temp_db + .prove_query(&path_query, None, grove_version) + .unwrap() + .unwrap(); let (hash, result_set) = - GroveDb::verify_query_raw(proof.as_slice(), &path_query).expect("should execute proof"); + GroveDb::verify_query_raw(proof.as_slice(), &path_query, grove_version) + .expect("should execute proof"); - assert_eq!(hash, temp_db.root_hash(None).unwrap().unwrap()); + assert_eq!( + hash, + temp_db.root_hash(None, grove_version).unwrap().unwrap() + ); let keys = [ b"deeper_1".to_vec(), @@ -2046,11 +2364,18 @@ mod tests { query.set_subquery(subquery); let path_query = PathQuery::new_unsized(vec![DEEP_LEAF.to_vec()], query); - let proof = temp_db.prove_query(&path_query, None).unwrap().unwrap(); + let proof = temp_db + .prove_query(&path_query, None, grove_version) + .unwrap() + .unwrap(); let (hash, result_set) = - GroveDb::verify_query_raw(proof.as_slice(), &path_query).expect("should execute proof"); + GroveDb::verify_query_raw(proof.as_slice(), &path_query, grove_version) + .expect("should execute proof"); - assert_eq!(hash, temp_db.root_hash(None).unwrap().unwrap()); + assert_eq!( + hash, + temp_db.root_hash(None, grove_version).unwrap().unwrap() + ); assert_eq!(result_set.len(), 6); let keys = [ @@ -2070,7 +2395,7 @@ mod tests { b"value11".to_vec(), ]; let elements = values - .map(|x| Element::new_item(x).serialize().unwrap()) + .map(|x| Element::new_item(x).serialize(grove_version).unwrap()) .to_vec(); // compare_result_sets(&elements, &result_set); let expected_result_set: Vec<(Vec, Vec)> = keys.into_iter().zip(elements).collect(); @@ -2079,7 +2404,8 @@ mod tests { #[test] fn test_path_query_proofs_with_sized_query() { - let temp_db = make_deep_tree(); + let grove_version = GroveVersion::latest(); + let temp_db = make_deep_tree(grove_version); let mut query = Query::new(); query.insert_all(); @@ -2105,25 +2431,33 @@ mod tests { let path_query = PathQuery::new( vec![DEEP_LEAF.to_vec()], SizedQuery::new(query, Some(5), None), /* we need to add a bigger limit because of - * empty proved sub trees */ + * empty proved subtrees */ ); - let proof = temp_db.prove_query(&path_query, None).unwrap().unwrap(); + let proof = temp_db + .prove_query(&path_query, None, grove_version) + .unwrap() + .unwrap(); let (hash, result_set) = - GroveDb::verify_query_raw(proof.as_slice(), &path_query).expect("should execute proof"); + GroveDb::verify_query_raw(proof.as_slice(), &path_query, grove_version) + .expect("should execute proof"); - assert_eq!(hash, temp_db.root_hash(None).unwrap().unwrap()); + assert_eq!( + hash, + temp_db.root_hash(None, grove_version).unwrap().unwrap() + ); assert_eq!(result_set.len(), 3); let keys = [b"key4".to_vec(), b"key5".to_vec(), b"key6".to_vec()]; let values = [b"value4".to_vec(), b"value5".to_vec(), b"value6".to_vec()]; - let elements = values.map(|x| Element::new_item(x).serialize().unwrap()); + let elements = values.map(|x| Element::new_item(x).serialize(grove_version).unwrap()); let expected_result_set: Vec<(Vec, Vec)> = keys.into_iter().zip(elements).collect(); compare_result_tuples(result_set, expected_result_set); } #[test] fn test_path_query_proof_with_range_subquery_and_limit() { - let db = make_deep_tree(); + let grove_version = GroveVersion::latest(); + let db = make_deep_tree(grove_version); // Create a path query with a range query, subquery, and limit let mut main_query = Query::new(); @@ -2140,15 +2474,18 @@ mod tests { ); // Generate proof - let proof = db.prove_query(&path_query, None).unwrap().unwrap(); + let proof = db + .prove_query(&path_query, None, grove_version) + .unwrap() + .unwrap(); // Verify proof - let verification_result = GroveDb::verify_query_raw(&proof, &path_query); + let verification_result = GroveDb::verify_query_raw(&proof, &path_query, grove_version); match verification_result { Ok((hash, result_set)) => { // Check if the hash matches the root hash - assert_eq!(hash, db.root_hash(None).unwrap().unwrap()); + assert_eq!(hash, db.root_hash(None, grove_version).unwrap().unwrap()); // Check if we got the correct number of results assert_eq!(result_set.len(), 3, "Expected 3 results due to limit"); } @@ -2163,13 +2500,16 @@ mod tests { SizedQuery::new(main_query.clone(), None, None), ); - let proof_no_limit = db.prove_query(&path_query_no_limit, None).unwrap().unwrap(); + let proof_no_limit = db + .prove_query(&path_query_no_limit, None, grove_version) + .unwrap() + .unwrap(); let verification_result_no_limit = - GroveDb::verify_query_raw(&proof_no_limit, &path_query_no_limit); + GroveDb::verify_query_raw(&proof_no_limit, &path_query_no_limit, grove_version); match verification_result_no_limit { Ok((hash, result_set)) => { - assert_eq!(hash, db.root_hash(None).unwrap().unwrap()); + assert_eq!(hash, db.root_hash(None, grove_version).unwrap().unwrap()); assert_eq!(result_set.len(), 5, "Expected 5 results without limit"); } Err(e) => { @@ -2180,7 +2520,8 @@ mod tests { #[test] fn test_path_query_proof_with_range_subquery_and_limit_with_sum_trees() { - let db = make_deep_tree_with_sum_trees(); + let grove_version = GroveVersion::latest(); + let db = make_deep_tree_with_sum_trees(grove_version); // Create a path query with a range query, subquery, and limit let mut main_query = Query::new(); @@ -2207,6 +2548,7 @@ mod tests { false, QueryResultType::QueryPathKeyElementTrioResultType, None, + grove_version, ) .unwrap() .expect("expected query to execute") @@ -2230,14 +2572,17 @@ mod tests { ); // Generate proof - let proof = db.prove_query(&path_query, None).unwrap().unwrap(); + let proof = db + .prove_query(&path_query, None, grove_version) + .unwrap() + .unwrap(); // Verify proof - let (hash, result_set) = - GroveDb::verify_query_raw(&proof, &path_query).expect("proof verification failed"); + let (hash, result_set) = GroveDb::verify_query_raw(&proof, &path_query, grove_version) + .expect("proof verification failed"); // Check if the hash matches the root hash - assert_eq!(hash, db.root_hash(None).unwrap().unwrap()); + assert_eq!(hash, db.root_hash(None, grove_version).unwrap().unwrap()); // Check if we got the correct number of results assert_eq!(result_set.len(), 3, "Expected 3 results due to limit"); @@ -2247,13 +2592,16 @@ mod tests { SizedQuery::new(main_query.clone(), None, None), ); - let proof_no_limit = db.prove_query(&path_query_no_limit, None).unwrap().unwrap(); + let proof_no_limit = db + .prove_query(&path_query_no_limit, None, grove_version) + .unwrap() + .unwrap(); let verification_result_no_limit = - GroveDb::verify_query_raw(&proof_no_limit, &path_query_no_limit); + GroveDb::verify_query_raw(&proof_no_limit, &path_query_no_limit, grove_version); match verification_result_no_limit { Ok((hash, result_set)) => { - assert_eq!(hash, db.root_hash(None).unwrap().unwrap()); + assert_eq!(hash, db.root_hash(None, grove_version).unwrap().unwrap()); assert_eq!(result_set.len(), 29, "Expected 29 results without limit"); } Err(e) => { @@ -2264,7 +2612,8 @@ mod tests { #[test] fn test_path_query_proofs_with_direction() { - let temp_db = make_deep_tree(); + let grove_version = GroveVersion::latest(); + let temp_db = make_deep_tree(grove_version); // root // deep_leaf @@ -2316,11 +2665,18 @@ mod tests { SizedQuery::new(query, Some(6), None), /* we need 6 because of intermediate empty * trees in proofs */ ); - let proof = temp_db.prove_query(&path_query, None).unwrap().unwrap(); + let proof = temp_db + .prove_query(&path_query, None, grove_version) + .unwrap() + .unwrap(); let (hash, result_set) = - GroveDb::verify_query_raw(proof.as_slice(), &path_query).expect("should execute proof"); + GroveDb::verify_query_raw(proof.as_slice(), &path_query, grove_version) + .expect("should execute proof"); - assert_eq!(hash, temp_db.root_hash(None).unwrap().unwrap()); + assert_eq!( + hash, + temp_db.root_hash(None, grove_version).unwrap().unwrap() + ); assert_eq!(result_set.len(), 4); let keys = [ @@ -2335,7 +2691,7 @@ mod tests { b"value6".to_vec(), b"value5".to_vec(), ]; - let elements = values.map(|x| Element::new_item(x).serialize().unwrap()); + let elements = values.map(|x| Element::new_item(x).serialize(grove_version).unwrap()); let expected_result_set: Vec<(Vec, Vec)> = keys.into_iter().zip(elements).collect(); compare_result_tuples(result_set, expected_result_set); @@ -2354,11 +2710,18 @@ mod tests { let path_query = PathQuery::new_unsized(vec![DEEP_LEAF.to_vec()], query); - let proof = temp_db.prove_query(&path_query, None).unwrap().unwrap(); + let proof = temp_db + .prove_query(&path_query, None, grove_version) + .unwrap() + .unwrap(); let (hash, result_set) = - GroveDb::verify_query_raw(proof.as_slice(), &path_query).expect("should execute proof"); + GroveDb::verify_query_raw(proof.as_slice(), &path_query, grove_version) + .expect("should execute proof"); - assert_eq!(hash, temp_db.root_hash(None).unwrap().unwrap()); + assert_eq!( + hash, + temp_db.root_hash(None, grove_version).unwrap().unwrap() + ); assert_eq!(result_set.len(), 14); let keys = [ @@ -2393,25 +2756,34 @@ mod tests { b"value8".to_vec(), b"value9".to_vec(), ]; - let elements = values.map(|x| Element::new_item(x).serialize().unwrap()); + let elements = values.map(|x| Element::new_item(x).serialize(grove_version).unwrap()); let expected_result_set: Vec<(Vec, Vec)> = keys.into_iter().zip(elements).collect(); compare_result_tuples(result_set, expected_result_set); } #[test] fn test_checkpoint() { - let db = make_test_grovedb(); + let grove_version = GroveVersion::latest(); + let db = make_test_grovedb(grove_version); let element1 = Element::new_item(b"ayy".to_vec()); - db.insert(EMPTY_PATH, b"key1", Element::empty_tree(), None, None) - .unwrap() - .expect("cannot insert a subtree 1 into GroveDB"); + db.insert( + EMPTY_PATH, + b"key1", + Element::empty_tree(), + None, + None, + grove_version, + ) + .unwrap() + .expect("cannot insert a subtree 1 into GroveDB"); db.insert( [b"key1".as_ref()].as_ref(), b"key2", Element::empty_tree(), None, None, + grove_version, ) .unwrap() .expect("cannot insert a subtree 2 into GroveDB"); @@ -2421,14 +2793,20 @@ mod tests { element1.clone(), None, None, + grove_version, ) .unwrap() .expect("cannot insert an item into GroveDB"); assert_eq!( - db.get([b"key1".as_ref(), b"key2".as_ref()].as_ref(), b"key3", None) - .unwrap() - .expect("cannot get from grovedb"), + db.get( + [b"key1".as_ref(), b"key2".as_ref()].as_ref(), + b"key3", + None, + grove_version + ) + .unwrap() + .expect("cannot get from grovedb"), element1 ); @@ -2441,14 +2819,24 @@ mod tests { GroveDb::open(checkpoint_tempdir).expect("cannot open grovedb from checkpoint"); assert_eq!( - db.get([b"key1".as_ref(), b"key2".as_ref()].as_ref(), b"key3", None) - .unwrap() - .expect("cannot get from grovedb"), + db.get( + [b"key1".as_ref(), b"key2".as_ref()].as_ref(), + b"key3", + None, + grove_version + ) + .unwrap() + .expect("cannot get from grovedb"), element1 ); assert_eq!( checkpoint_db - .get([b"key1".as_ref(), b"key2".as_ref()].as_ref(), b"key3", None) + .get( + [b"key1".as_ref(), b"key2".as_ref()].as_ref(), + b"key3", + None, + grove_version + ) .unwrap() .expect("cannot get from checkpoint"), element1 @@ -2464,6 +2852,7 @@ mod tests { element2.clone(), None, None, + grove_version, ) .unwrap() .expect("cannot insert into checkpoint"); @@ -2474,20 +2863,21 @@ mod tests { element3.clone(), None, None, + grove_version, ) .unwrap() .expect("cannot insert into GroveDB"); assert_eq!( checkpoint_db - .get([b"key1".as_ref()].as_ref(), b"key4", None) + .get([b"key1".as_ref()].as_ref(), b"key4", None, grove_version) .unwrap() .expect("cannot get from checkpoint"), element2, ); assert_eq!( - db.get([b"key1".as_ref()].as_ref(), b"key4", None) + db.get([b"key1".as_ref()].as_ref(), b"key4", None, grove_version) .unwrap() .expect("cannot get from GroveDB"), element3 @@ -2500,30 +2890,40 @@ mod tests { element3.clone(), None, None, + grove_version, ) .unwrap() .expect("cannot insert into checkpoint"); - db.insert([b"key1".as_ref()].as_ref(), b"key6", element3, None, None) - .unwrap() - .expect("cannot insert into GroveDB"); + db.insert( + [b"key1".as_ref()].as_ref(), + b"key6", + element3, + None, + None, + grove_version, + ) + .unwrap() + .expect("cannot insert into GroveDB"); assert!(matches!( checkpoint_db - .get([b"key1".as_ref()].as_ref(), b"key6", None) + .get([b"key1".as_ref()].as_ref(), b"key6", None, grove_version) .unwrap(), Err(Error::PathKeyNotFound(_)) )); assert!(matches!( - db.get([b"key1".as_ref()].as_ref(), b"key5", None).unwrap(), + db.get([b"key1".as_ref()].as_ref(), b"key5", None, grove_version) + .unwrap(), Err(Error::PathKeyNotFound(_)) )); } #[test] fn test_is_empty_tree() { - let db = make_test_grovedb(); + let grove_version = GroveVersion::latest(); + let db = make_test_grovedb(grove_version); // Create an empty tree with no elements db.insert( @@ -2532,36 +2932,39 @@ mod tests { Element::empty_tree(), None, None, + grove_version, ) .unwrap() .unwrap(); assert!(db - .is_empty_tree([TEST_LEAF, b"innertree"].as_ref(), None) + .is_empty_tree([TEST_LEAF, b"innertree"].as_ref(), None, grove_version) .unwrap() .expect("path is valid tree")); - // add an element to the tree to make it non empty + // add an element to the tree to make it non-empty db.insert( [TEST_LEAF, b"innertree"].as_ref(), b"key1", Element::new_item(b"hello".to_vec()), None, None, + grove_version, ) .unwrap() .unwrap(); assert!(!db - .is_empty_tree([TEST_LEAF, b"innertree"].as_ref(), None) + .is_empty_tree([TEST_LEAF, b"innertree"].as_ref(), None, grove_version) .unwrap() .expect("path is valid tree")); } #[test] fn transaction_should_be_aborted_when_rollback_is_called() { + let grove_version = GroveVersion::latest(); let item_key = b"key3"; - let db = make_test_grovedb(); + let db = make_test_grovedb(grove_version); let transaction = db.start_transaction(); let element1 = Element::new_item(b"ayy".to_vec()); @@ -2573,6 +2976,7 @@ mod tests { element1, None, Some(&transaction), + grove_version, ) .unwrap(); @@ -2581,14 +2985,20 @@ mod tests { db.rollback_transaction(&transaction).unwrap(); let result = db - .get([TEST_LEAF].as_ref(), item_key, Some(&transaction)) + .get( + [TEST_LEAF].as_ref(), + item_key, + Some(&transaction), + grove_version, + ) .unwrap(); assert!(matches!(result, Err(Error::PathKeyNotFound(_)))); } #[test] fn transaction_should_be_aborted() { - let db = make_test_grovedb(); + let grove_version = GroveVersion::latest(); + let db = make_test_grovedb(grove_version); let transaction = db.start_transaction(); let item_key = b"key3"; @@ -2600,6 +3010,7 @@ mod tests { element, None, Some(&transaction), + grove_version, ) .unwrap() .unwrap(); @@ -2607,13 +3018,16 @@ mod tests { drop(transaction); // Transactional data shouldn't be committed to the main database - let result = db.get([TEST_LEAF].as_ref(), item_key, None).unwrap(); + let result = db + .get([TEST_LEAF].as_ref(), item_key, None, grove_version) + .unwrap(); assert!(matches!(result, Err(Error::PathKeyNotFound(_)))); } #[test] fn test_subtree_pairs_iterator() { - let db = make_test_grovedb(); + let grove_version = GroveVersion::latest(); + let db = make_test_grovedb(grove_version); let element = Element::new_item(b"ayy".to_vec()); let element2 = Element::new_item(b"lmao".to_vec()); @@ -2624,6 +3038,7 @@ mod tests { Element::empty_tree(), None, None, + grove_version, ) .unwrap() .expect("successful subtree 1 insert"); @@ -2633,6 +3048,7 @@ mod tests { Element::empty_tree(), None, None, + grove_version, ) .unwrap() .expect("successful subtree 2 insert"); @@ -2643,6 +3059,7 @@ mod tests { element.clone(), None, None, + grove_version, ) .unwrap() .expect("successful value insert"); @@ -2650,7 +3067,8 @@ mod tests { db.get( [TEST_LEAF, b"subtree1", b"subtree11"].as_ref(), b"key1", - None + None, + grove_version ) .unwrap() .expect("successful get 1"), @@ -2662,6 +3080,7 @@ mod tests { element.clone(), None, None, + grove_version, ) .unwrap() .expect("successful value insert"); @@ -2671,6 +3090,7 @@ mod tests { Element::empty_tree(), None, None, + grove_version, ) .unwrap() .expect("successful subtree 3 insert"); @@ -2680,6 +3100,7 @@ mod tests { element.clone(), None, None, + grove_version, ) .unwrap() .expect("successful value insert"); @@ -2689,6 +3110,7 @@ mod tests { element2.clone(), None, None, + grove_version, ) .unwrap() .expect("successful value insert"); @@ -2704,26 +3126,30 @@ mod tests { .unwrap(); let mut iter = Element::iterator(storage_context.raw_iter()).unwrap(); assert_eq!( - iter.next_element().unwrap().unwrap(), + iter.next_element(grove_version).unwrap().unwrap(), Some((b"key1".to_vec(), element)) ); assert_eq!( - iter.next_element().unwrap().unwrap(), + iter.next_element(grove_version).unwrap().unwrap(), Some((b"key2".to_vec(), element2)) ); - let subtree_element = iter.next_element().unwrap().unwrap().unwrap(); + let subtree_element = iter.next_element(grove_version).unwrap().unwrap().unwrap(); assert_eq!(subtree_element.0, b"subtree11".to_vec()); assert!(matches!(subtree_element.1, Element::Tree(..))); - let subtree_element = iter.next_element().unwrap().unwrap().unwrap(); + let subtree_element = iter.next_element(grove_version).unwrap().unwrap().unwrap(); assert_eq!(subtree_element.0, b"subtree12".to_vec()); assert!(matches!(subtree_element.1, Element::Tree(..))); - assert!(matches!(iter.next_element().unwrap(), Ok(None))); + assert!(matches!( + iter.next_element(grove_version).unwrap(), + Ok(None) + )); } #[test] fn test_find_subtrees() { + let grove_version = GroveVersion::latest(); let element = Element::new_item(b"ayy".to_vec()); - let db = make_test_grovedb(); + let db = make_test_grovedb(grove_version); // Insert some nested subtrees db.insert( [TEST_LEAF].as_ref(), @@ -2731,6 +3157,7 @@ mod tests { Element::empty_tree(), None, None, + grove_version, ) .unwrap() .expect("successful subtree 1 insert"); @@ -2740,6 +3167,7 @@ mod tests { Element::empty_tree(), None, None, + grove_version, ) .unwrap() .expect("successful subtree 2 insert"); @@ -2750,6 +3178,7 @@ mod tests { element, None, None, + grove_version, ) .unwrap() .expect("successful value insert"); @@ -2759,11 +3188,12 @@ mod tests { Element::empty_tree(), None, None, + grove_version, ) .unwrap() .expect("successful subtree 3 insert"); let subtrees = db - .find_subtrees(&[TEST_LEAF].as_ref().into(), None) + .find_subtrees(&[TEST_LEAF].as_ref().into(), None, grove_version) .unwrap() .expect("cannot get subtrees"); assert_eq!( @@ -2779,12 +3209,14 @@ mod tests { #[test] fn test_root_subtree_has_root_key() { - let db = make_test_grovedb(); + let grove_version = GroveVersion::latest(); + let db = make_test_grovedb(grove_version); let storage = db.db.get_storage_context(EMPTY_PATH, None).unwrap(); let root_merk = Merk::open_base( storage, false, Some(&Element::value_defined_cost_for_serialized_value), + grove_version, ) .unwrap() .expect("expected to get root merk"); @@ -2797,16 +3229,19 @@ mod tests { #[test] fn test_get_subtree() { - let db = make_test_grovedb(); + let grove_version = GroveVersion::latest(); + let db = make_test_grovedb(grove_version); let element = Element::new_item(b"ayy".to_vec()); // Returns error is subtree is not valid { - let subtree = db.get([TEST_LEAF].as_ref(), b"invalid_tree", None).unwrap(); + let subtree = db + .get([TEST_LEAF].as_ref(), b"invalid_tree", None, grove_version) + .unwrap(); assert!(subtree.is_err()); // Doesn't return an error for subtree that exists but empty - let subtree = db.get(EMPTY_PATH, TEST_LEAF, None).unwrap(); + let subtree = db.get(EMPTY_PATH, TEST_LEAF, None, grove_version).unwrap(); assert!(subtree.is_ok()); } @@ -2817,12 +3252,13 @@ mod tests { Element::empty_tree(), None, None, + grove_version, ) .unwrap() .expect("successful subtree 1 insert"); let key1_tree = db - .get(EMPTY_PATH, TEST_LEAF, None) + .get(EMPTY_PATH, TEST_LEAF, None, grove_version) .unwrap() .expect("expected to get a root tree"); @@ -2845,6 +3281,7 @@ mod tests { Element::empty_tree(), None, None, + grove_version, ) .unwrap() .expect("successful subtree 2 insert"); @@ -2856,6 +3293,7 @@ mod tests { element.clone(), None, None, + grove_version, ) .unwrap() .expect("successful value insert"); @@ -2865,6 +3303,7 @@ mod tests { Element::empty_tree(), None, None, + grove_version, ) .unwrap() .expect("successful subtree 3 insert"); @@ -2882,10 +3321,13 @@ mod tests { Some(b"key3".to_vec()), false, Some(&Element::value_defined_cost_for_serialized_value), + grove_version, ) .unwrap() .expect("cannot open merk"); - let result_element = Element::get(&subtree, b"key3", true).unwrap().unwrap(); + let result_element = Element::get(&subtree, b"key3", true, grove_version) + .unwrap() + .unwrap(); assert_eq!(result_element, Element::new_item(b"ayy".to_vec())); } // Insert a new tree with transaction @@ -2897,6 +3339,7 @@ mod tests { Element::empty_tree(), None, Some(&transaction), + grove_version, ) .unwrap() .expect("successful subtree insert"); @@ -2907,6 +3350,7 @@ mod tests { element, None, Some(&transaction), + grove_version, ) .unwrap() .expect("successful value insert"); @@ -2926,10 +3370,13 @@ mod tests { Some(b"key4".to_vec()), false, Some(&Element::value_defined_cost_for_serialized_value), + grove_version, ) .unwrap() .expect("cannot open merk"); - let result_element = Element::get(&subtree, b"key4", true).unwrap().unwrap(); + let result_element = Element::get(&subtree, b"key4", true, grove_version) + .unwrap() + .unwrap(); assert_eq!(result_element, Element::new_item(b"ayy".to_vec())); // Should be able to retrieve instances created before transaction @@ -2943,16 +3390,20 @@ mod tests { Some(b"key3".to_vec()), false, Some(&Element::value_defined_cost_for_serialized_value), + grove_version, ) .unwrap() .expect("cannot open merk"); - let result_element = Element::get(&subtree, b"key3", true).unwrap().unwrap(); + let result_element = Element::get(&subtree, b"key3", true, grove_version) + .unwrap() + .unwrap(); assert_eq!(result_element, Element::new_item(b"ayy".to_vec())); } #[test] fn test_get_full_query() { - let db = make_test_grovedb(); + let grove_version = GroveVersion::latest(); + let db = make_test_grovedb(grove_version); // Insert a couple of subtrees first db.insert( @@ -2961,6 +3412,7 @@ mod tests { Element::empty_tree(), None, None, + grove_version, ) .unwrap() .expect("successful subtree insert"); @@ -2970,6 +3422,7 @@ mod tests { Element::empty_tree(), None, None, + grove_version, ) .unwrap() .expect("successful subtree insert"); @@ -2980,6 +3433,7 @@ mod tests { Element::new_item(b"ayya".to_vec()), None, None, + grove_version, ) .unwrap() .expect("successful value insert"); @@ -2989,6 +3443,7 @@ mod tests { Element::new_item(b"ayyb".to_vec()), None, None, + grove_version, ) .unwrap() .expect("successful value insert"); @@ -2998,6 +3453,7 @@ mod tests { Element::new_item(b"ayyc".to_vec()), None, None, + grove_version, ) .unwrap() .expect("successful value insert"); @@ -3007,6 +3463,7 @@ mod tests { Element::new_item(b"ayyd".to_vec()), None, None, + grove_version, ) .unwrap() .expect("successful value insert"); @@ -3041,7 +3498,8 @@ mod tests { true, true, QueryKeyElementPairResultType, - None + None, + grove_version ) .unwrap() .expect("expected successful get_query") @@ -3056,8 +3514,9 @@ mod tests { #[test] fn test_aux_uses_separate_cf() { + let grove_version = GroveVersion::latest(); let element = Element::new_item(b"ayy".to_vec()); - let db = make_test_grovedb(); + let db = make_test_grovedb(grove_version); // Insert some nested subtrees db.insert( [TEST_LEAF].as_ref(), @@ -3065,6 +3524,7 @@ mod tests { Element::empty_tree(), None, None, + grove_version, ) .unwrap() .expect("successful subtree 1 insert"); @@ -3074,6 +3534,7 @@ mod tests { Element::empty_tree(), None, None, + grove_version, ) .unwrap() .expect("successful subtree 2 insert"); @@ -3084,6 +3545,7 @@ mod tests { element.clone(), None, None, + grove_version, ) .unwrap() .expect("successful value insert"); @@ -3102,9 +3564,14 @@ mod tests { .expect("cannot delete from aux"); assert_eq!( - db.get([TEST_LEAF, b"key1", b"key2"].as_ref(), b"key3", None) - .unwrap() - .expect("cannot get element"), + db.get( + [TEST_LEAF, b"key1", b"key2"].as_ref(), + b"key3", + None, + grove_version + ) + .unwrap() + .expect("cannot get element"), element ); assert_eq!( @@ -3135,10 +3602,11 @@ mod tests { #[test] fn test_aux_with_transaction() { + let grove_version = GroveVersion::latest(); let element = Element::new_item(b"ayy".to_vec()); let aux_value = b"ayylmao".to_vec(); let key = b"key".to_vec(); - let db = make_test_grovedb(); + let db = make_test_grovedb(grove_version); let transaction = db.start_transaction(); // Insert a regular data with aux data in the same transaction @@ -3148,6 +3616,7 @@ mod tests { element, None, Some(&transaction), + grove_version, ) .unwrap() .expect("unable to insert"); @@ -3181,19 +3650,24 @@ mod tests { #[test] fn test_root_hash() { - let db = make_test_grovedb(); + let grove_version = GroveVersion::latest(); + let db = make_test_grovedb(grove_version); // Check hashes are different if tree is edited - let old_root_hash = db.root_hash(None).unwrap(); + let old_root_hash = db.root_hash(None, grove_version).unwrap(); db.insert( [TEST_LEAF].as_ref(), b"key1", Element::new_item(b"ayy".to_vec()), None, None, + grove_version, ) .unwrap() .expect("unable to insert an item"); - assert_ne!(old_root_hash.unwrap(), db.root_hash(None).unwrap().unwrap()); + assert_ne!( + old_root_hash.unwrap(), + db.root_hash(None, grove_version).unwrap().unwrap() + ); // Check isolation let transaction = db.start_transaction(); @@ -3204,35 +3678,50 @@ mod tests { Element::new_item(b"ayy".to_vec()), None, Some(&transaction), + grove_version, ) .unwrap() .expect("unable to insert an item"); - let root_hash_outside = db.root_hash(None).unwrap().unwrap(); + let root_hash_outside = db.root_hash(None, grove_version).unwrap().unwrap(); assert_ne!( - db.root_hash(Some(&transaction)).unwrap().unwrap(), + db.root_hash(Some(&transaction), grove_version) + .unwrap() + .unwrap(), root_hash_outside ); - assert_eq!(db.root_hash(None).unwrap().unwrap(), root_hash_outside); + assert_eq!( + db.root_hash(None, grove_version).unwrap().unwrap(), + root_hash_outside + ); db.commit_transaction(transaction).unwrap().unwrap(); - assert_ne!(db.root_hash(None).unwrap().unwrap(), root_hash_outside); + assert_ne!( + db.root_hash(None, grove_version).unwrap().unwrap(), + root_hash_outside + ); } #[test] fn test_get_non_existing_root_leaf() { - let db = make_test_grovedb(); - assert!(db.get(EMPTY_PATH, b"ayy", None).unwrap().is_err()); + let grove_version = GroveVersion::latest(); + let db = make_test_grovedb(grove_version); + assert!(db + .get(EMPTY_PATH, b"ayy", None, grove_version) + .unwrap() + .is_err()); } #[test] fn test_check_subtree_exists_function() { - let db = make_test_grovedb(); + let grove_version = GroveVersion::latest(); + let db = make_test_grovedb(grove_version); db.insert( [TEST_LEAF].as_ref(), b"key_scalar", Element::new_item(b"ayy".to_vec()), None, None, + grove_version, ) .unwrap() .expect("cannot insert item"); @@ -3242,39 +3731,49 @@ mod tests { Element::empty_tree(), None, None, + grove_version, ) .unwrap() .expect("cannot insert item"); // Empty tree path means root always exist assert!(db - .check_subtree_exists_invalid_path(EMPTY_PATH, None) + .check_subtree_exists_invalid_path(EMPTY_PATH, None, grove_version) .unwrap() .is_ok()); // TEST_LEAF should be a tree assert!(db - .check_subtree_exists_invalid_path([TEST_LEAF].as_ref().into(), None) + .check_subtree_exists_invalid_path([TEST_LEAF].as_ref().into(), None, grove_version) .unwrap() .is_ok()); // TEST_LEAF.key_subtree should be a tree assert!(db - .check_subtree_exists_invalid_path([TEST_LEAF, b"key_subtree"].as_ref().into(), None) + .check_subtree_exists_invalid_path( + [TEST_LEAF, b"key_subtree"].as_ref().into(), + None, + grove_version + ) .unwrap() .is_ok()); // TEST_LEAF.key_scalar should NOT be a tree assert!(matches!( - db.check_subtree_exists_invalid_path([TEST_LEAF, b"key_scalar"].as_ref().into(), None) - .unwrap(), + db.check_subtree_exists_invalid_path( + [TEST_LEAF, b"key_scalar"].as_ref().into(), + None, + grove_version + ) + .unwrap(), Err(Error::InvalidPath(_)) )); } #[test] fn test_tree_value_exists_method_no_tx() { - let db = make_test_grovedb(); + let grove_version = GroveVersion::latest(); + let db = make_test_grovedb(grove_version); // Test keys in non-root tree db.insert( [TEST_LEAF].as_ref(), @@ -3282,31 +3781,49 @@ mod tests { Element::new_item(b"ayy".to_vec()), None, None, + grove_version, ) .unwrap() .expect("cannot insert item"); assert!(db - .has_raw([TEST_LEAF].as_ref(), b"key", None) + .has_raw([TEST_LEAF].as_ref(), b"key", None, grove_version) .unwrap() .unwrap()); assert!(!db - .has_raw([TEST_LEAF].as_ref(), b"badkey", None) + .has_raw([TEST_LEAF].as_ref(), b"badkey", None, grove_version) .unwrap() .unwrap()); // Test keys for a root tree - db.insert(EMPTY_PATH, b"leaf", Element::empty_tree(), None, None) - .unwrap() - .expect("cannot insert item"); + db.insert( + EMPTY_PATH, + b"leaf", + Element::empty_tree(), + None, + None, + grove_version, + ) + .unwrap() + .expect("cannot insert item"); - assert!(db.has_raw(EMPTY_PATH, b"leaf", None).unwrap().unwrap()); - assert!(db.has_raw(EMPTY_PATH, TEST_LEAF, None).unwrap().unwrap()); - assert!(!db.has_raw(EMPTY_PATH, b"badleaf", None).unwrap().unwrap()); + assert!(db + .has_raw(EMPTY_PATH, b"leaf", None, grove_version) + .unwrap() + .unwrap()); + assert!(db + .has_raw(EMPTY_PATH, TEST_LEAF, None, grove_version) + .unwrap() + .unwrap()); + assert!(!db + .has_raw(EMPTY_PATH, b"badleaf", None, grove_version) + .unwrap() + .unwrap()); } #[test] fn test_tree_value_exists_method_tx() { - let db = make_test_grovedb(); + let grove_version = GroveVersion::latest(); + let db = make_test_grovedb(grove_version); let tx = db.start_transaction(); // Test keys in non-root tree db.insert( @@ -3315,38 +3832,56 @@ mod tests { Element::new_item(b"ayy".to_vec()), None, Some(&tx), + grove_version, ) .unwrap() .expect("cannot insert item"); assert!(db - .has_raw([TEST_LEAF].as_ref(), b"key", Some(&tx)) + .has_raw([TEST_LEAF].as_ref(), b"key", Some(&tx), grove_version) .unwrap() .unwrap()); assert!(!db - .has_raw([TEST_LEAF].as_ref(), b"key", None) + .has_raw([TEST_LEAF].as_ref(), b"key", None, grove_version) .unwrap() .unwrap()); // Test keys for a root tree - db.insert(EMPTY_PATH, b"leaf", Element::empty_tree(), None, Some(&tx)) + db.insert( + EMPTY_PATH, + b"leaf", + Element::empty_tree(), + None, + Some(&tx), + grove_version, + ) + .unwrap() + .expect("cannot insert item"); + assert!(db + .has_raw(EMPTY_PATH, b"leaf", Some(&tx), grove_version) .unwrap() - .expect("cannot insert item"); - assert!(db.has_raw(EMPTY_PATH, b"leaf", Some(&tx)).unwrap().unwrap()); - assert!(!db.has_raw(EMPTY_PATH, b"leaf", None).unwrap().unwrap()); + .unwrap()); + assert!(!db + .has_raw(EMPTY_PATH, b"leaf", None, grove_version) + .unwrap() + .unwrap()); db.commit_transaction(tx) .unwrap() .expect("cannot commit transaction"); assert!(db - .has_raw([TEST_LEAF].as_ref(), b"key", None) + .has_raw([TEST_LEAF].as_ref(), b"key", None, grove_version) + .unwrap() + .unwrap()); + assert!(db + .has_raw(EMPTY_PATH, b"leaf", None, grove_version) .unwrap() .unwrap()); - assert!(db.has_raw(EMPTY_PATH, b"leaf", None).unwrap().unwrap()); } #[test] fn test_storage_wipe() { - let db = make_test_grovedb(); + let grove_version = GroveVersion::latest(); + let db = make_test_grovedb(grove_version); let _path = db._tmp_dir.path(); // Test keys in non-root tree @@ -3356,19 +3891,23 @@ mod tests { Element::new_item(b"ayy".to_vec()), None, None, + grove_version, ) .unwrap() .expect("cannot insert item"); // retrieve key before wipe - let elem = db.get(&[TEST_LEAF], b"key", None).unwrap().unwrap(); + let elem = db + .get(&[TEST_LEAF], b"key", None, grove_version) + .unwrap() + .unwrap(); assert_eq!(elem, Element::new_item(b"ayy".to_vec())); // wipe the database db.grove_db.wipe().unwrap(); // retrieve key after wipe - let elem_result = db.get(&[TEST_LEAF], b"key", None).unwrap(); + let elem_result = db.get(&[TEST_LEAF], b"key", None, grove_version).unwrap(); assert!(elem_result.is_err()); assert!(matches!( elem_result, diff --git a/grovedb/src/tests/query_tests.rs b/grovedb/src/tests/query_tests.rs index e7325a6a..48c358c6 100644 --- a/grovedb/src/tests/query_tests.rs +++ b/grovedb/src/tests/query_tests.rs @@ -2,7 +2,8 @@ mod tests { //! Query tests use grovedb_merk::proofs::{query::QueryItem, Query}; - use rand::Rng; + use grovedb_version::version::GroveVersion; + use rand::random; use tempfile::TempDir; use crate::{ @@ -19,7 +20,7 @@ mod tests { Element, GroveDb, PathQuery, SizedQuery, }; - fn populate_tree_for_non_unique_range_subquery(db: &TempGroveDb) { + fn populate_tree_for_non_unique_range_subquery(db: &TempGroveDb, grove_version: &GroveVersion) { // Insert a couple of subtrees first for i in 1985u32..2000 { let i_vec = i.to_be_bytes().to_vec(); @@ -29,6 +30,7 @@ mod tests { Element::empty_tree(), None, None, + grove_version, ) .unwrap() .expect("successful subtree insert"); @@ -40,6 +42,7 @@ mod tests { Element::empty_tree(), None, None, + grove_version, ) .unwrap() .expect("successful subtree insert"); @@ -53,6 +56,7 @@ mod tests { Element::new_item(j_vec), None, None, + grove_version, ) .unwrap() .expect("successful value insert"); @@ -60,7 +64,10 @@ mod tests { } } - fn populate_tree_for_non_unique_double_range_subquery(db: &TempGroveDb) { + fn populate_tree_for_non_unique_double_range_subquery( + db: &TempGroveDb, + grove_version: &GroveVersion, + ) { // Insert a couple of subtrees first for i in 0u32..10 { let i_vec = i.to_be_bytes().to_vec(); @@ -70,6 +77,7 @@ mod tests { Element::empty_tree(), None, None, + grove_version, ) .unwrap() .expect("successful subtree insert"); @@ -81,6 +89,7 @@ mod tests { Element::empty_tree(), None, None, + grove_version, ) .unwrap() .expect("successful subtree insert"); @@ -93,6 +102,7 @@ mod tests { Element::empty_tree(), None, None, + grove_version, ) .unwrap() .expect("successful value insert"); @@ -105,6 +115,7 @@ mod tests { Element::empty_tree(), None, None, + grove_version, ) .unwrap() .expect("successful subtree insert"); @@ -117,6 +128,7 @@ mod tests { Element::new_item(k_vec), None, None, + grove_version, ) .unwrap() .expect("successful value insert"); @@ -125,7 +137,10 @@ mod tests { } } - fn populate_tree_by_reference_for_non_unique_range_subquery(db: &TempGroveDb) { + fn populate_tree_by_reference_for_non_unique_range_subquery( + db: &TempGroveDb, + grove_version: &GroveVersion, + ) { // This subtree will be holding values db.insert( [TEST_LEAF].as_ref(), @@ -133,6 +148,7 @@ mod tests { Element::empty_tree(), None, None, + grove_version, ) .unwrap() .expect("successful subtree insert"); @@ -144,6 +160,7 @@ mod tests { Element::empty_tree(), None, None, + grove_version, ) .unwrap() .expect("successful subtree insert"); @@ -156,6 +173,7 @@ mod tests { Element::empty_tree(), None, None, + grove_version, ) .unwrap() .expect("successful subtree insert"); @@ -167,12 +185,13 @@ mod tests { Element::empty_tree(), None, None, + grove_version, ) .unwrap() .expect("successful subtree insert"); for j in 100u32..150 { - let random_key = rand::thread_rng().gen::<[u8; 32]>(); + let random_key = random::<[u8; 32]>(); let mut j_vec = i_vec.clone(); j_vec.append(&mut j.to_be_bytes().to_vec()); @@ -183,6 +202,7 @@ mod tests { Element::new_item(j_vec.clone()), None, None, + grove_version, ) .unwrap() .expect("successful value insert"); @@ -197,6 +217,7 @@ mod tests { ])), None, None, + grove_version, ) .unwrap() .expect("successful value insert"); @@ -204,7 +225,7 @@ mod tests { } } - fn populate_tree_for_unique_range_subquery(db: &TempGroveDb) { + fn populate_tree_for_unique_range_subquery(db: &TempGroveDb, grove_version: &GroveVersion) { // Insert a couple of subtrees first for i in 1985u32..2000 { let i_vec = i.to_be_bytes().to_vec(); @@ -214,6 +235,7 @@ mod tests { Element::empty_tree(), None, None, + grove_version, ) .unwrap() .expect("successful subtree insert"); @@ -224,13 +246,17 @@ mod tests { Element::new_item(i_vec), None, None, + grove_version, ) .unwrap() .expect("successful value insert"); } } - fn populate_tree_by_reference_for_unique_range_subquery(db: &TempGroveDb) { + fn populate_tree_by_reference_for_unique_range_subquery( + db: &TempGroveDb, + grove_version: &GroveVersion, + ) { // This subtree will be holding values db.insert( [TEST_LEAF].as_ref(), @@ -238,6 +264,7 @@ mod tests { Element::empty_tree(), None, None, + grove_version, ) .unwrap() .expect("successful subtree insert"); @@ -249,6 +276,7 @@ mod tests { Element::empty_tree(), None, None, + grove_version, ) .unwrap() .expect("successful subtree insert"); @@ -261,6 +289,7 @@ mod tests { Element::empty_tree(), None, None, + grove_version, ) .unwrap() .expect("successful subtree insert"); @@ -272,6 +301,7 @@ mod tests { Element::new_item(i_vec.clone()), None, None, + grove_version, ) .unwrap() .expect("successful value insert"); @@ -287,23 +317,35 @@ mod tests { ])), None, None, + grove_version, ) .unwrap() .expect("successful value insert"); } } - fn populate_tree_for_unique_range_subquery_with_non_unique_null_values(db: &mut TempGroveDb) { - populate_tree_for_unique_range_subquery(db); - db.insert([TEST_LEAF].as_ref(), &[], Element::empty_tree(), None, None) - .unwrap() - .expect("successful subtree insert"); + fn populate_tree_for_unique_range_subquery_with_non_unique_null_values( + db: &mut TempGroveDb, + grove_version: &GroveVersion, + ) { + populate_tree_for_unique_range_subquery(db, grove_version); + db.insert( + [TEST_LEAF].as_ref(), + &[], + Element::empty_tree(), + None, + None, + grove_version, + ) + .unwrap() + .expect("successful subtree insert"); db.insert( [TEST_LEAF, &[]].as_ref(), b"\0", Element::empty_tree(), None, None, + grove_version, ) .unwrap() .expect("successful subtree insert"); @@ -316,19 +358,21 @@ mod tests { Element::new_item(i_vec.clone()), None, None, + grove_version, ) .unwrap() .expect("successful value insert"); } } - fn populate_tree_for_uneven_keys(db: &TempGroveDb) { + fn populate_tree_for_uneven_keys(db: &TempGroveDb, grove_version: &GroveVersion) { db.insert( [TEST_LEAF].as_ref(), "b".as_ref(), Element::new_item(1u8.to_be_bytes().to_vec()), None, None, + grove_version, ) .unwrap() .expect("successful subtree insert"); @@ -339,6 +383,7 @@ mod tests { Element::new_item(2u8.to_be_bytes().to_vec()), None, None, + grove_version, ) .unwrap() .expect("successful subtree insert"); @@ -349,6 +394,7 @@ mod tests { Element::new_item(3u8.to_be_bytes().to_vec()), None, None, + grove_version, ) .unwrap() .expect("successful subtree insert"); @@ -359,6 +405,7 @@ mod tests { Element::new_item(4u8.to_be_bytes().to_vec()), None, None, + grove_version, ) .unwrap() .expect("successful subtree insert"); @@ -369,6 +416,7 @@ mod tests { Element::new_item(5u8.to_be_bytes().to_vec()), None, None, + grove_version, ) .unwrap() .expect("successful subtree insert"); @@ -376,8 +424,9 @@ mod tests { #[test] fn test_get_correct_order() { - let db = make_test_grovedb(); - populate_tree_for_uneven_keys(&db); + let grove_version = GroveVersion::latest(); + let db = make_test_grovedb(grove_version); + populate_tree_for_uneven_keys(&db, grove_version); let path = vec![TEST_LEAF.to_vec()]; let query = Query::new_range_full(); @@ -385,7 +434,7 @@ mod tests { let path_query = PathQuery::new_unsized(path, query.clone()); let (elements, _) = db - .query_item_value(&path_query, true, true, true, None) + .query_item_value(&path_query, true, true, true, None, grove_version) .unwrap() .expect("expected successful get_path_query"); @@ -394,8 +443,9 @@ mod tests { #[test] fn test_get_range_query_with_non_unique_subquery() { - let db = make_test_grovedb(); - populate_tree_for_non_unique_range_subquery(&db); + let grove_version = GroveVersion::latest(); + let db = make_test_grovedb(grove_version); + populate_tree_for_non_unique_range_subquery(&db, grove_version); let path = vec![TEST_LEAF.to_vec()]; let mut query = Query::new(); @@ -411,7 +461,7 @@ mod tests { let path_query = PathQuery::new_unsized(path, query.clone()); let (elements, _) = db - .query_item_value(&path_query, true, true, true, None) + .query_item_value(&path_query, true, true, true, None, grove_version) .unwrap() .expect("expected successful get_path_query"); @@ -425,17 +475,22 @@ mod tests { last_value.append(&mut 149_u32.to_be_bytes().to_vec()); assert_eq!(elements[elements.len() - 1], last_value); - let proof = db.prove_query(&path_query, None).unwrap().unwrap(); - let (hash, result_set) = GroveDb::verify_query_raw(&proof, &path_query).unwrap(); - assert_eq!(hash, db.root_hash(None).unwrap().unwrap()); + let proof = db + .prove_query(&path_query, None, grove_version) + .unwrap() + .unwrap(); + let (hash, result_set) = + GroveDb::verify_query_raw(&proof, &path_query, grove_version).unwrap(); + assert_eq!(hash, db.root_hash(None, grove_version).unwrap().unwrap()); assert_eq!(result_set.len(), 200); compare_result_sets(&elements, &result_set); } #[test] fn test_get_range_query_with_unique_subquery() { - let mut db = make_test_grovedb(); - populate_tree_for_unique_range_subquery(&mut db); + let grove_version = GroveVersion::latest(); + let mut db = make_test_grovedb(grove_version); + populate_tree_for_unique_range_subquery(&mut db, grove_version); let path = vec![TEST_LEAF.to_vec()]; let mut query = Query::new(); @@ -448,7 +503,7 @@ mod tests { let path_query = PathQuery::new_unsized(path, query.clone()); let (elements, _) = db - .query_item_value(&path_query, true, true, true, None) + .query_item_value(&path_query, true, true, true, None, grove_version) .unwrap() .expect("expected successful get_path_query"); @@ -460,17 +515,22 @@ mod tests { let last_value = 1991_u32.to_be_bytes().to_vec(); assert_eq!(elements[elements.len() - 1], last_value); - let proof = db.prove_query(&path_query, None).unwrap().unwrap(); - let (hash, result_set) = GroveDb::verify_query_raw(&proof, &path_query).unwrap(); - assert_eq!(hash, db.root_hash(None).unwrap().unwrap()); + let proof = db + .prove_query(&path_query, None, grove_version) + .unwrap() + .unwrap(); + let (hash, result_set) = + GroveDb::verify_query_raw(&proof, &path_query, grove_version).unwrap(); + assert_eq!(hash, db.root_hash(None, grove_version).unwrap().unwrap()); assert_eq!(result_set.len(), 4); compare_result_sets(&elements, &result_set); } #[test] fn test_get_range_query_with_unique_subquery_on_references() { - let db = make_test_grovedb(); - populate_tree_by_reference_for_unique_range_subquery(&db); + let grove_version = GroveVersion::latest(); + let db = make_test_grovedb(grove_version); + populate_tree_by_reference_for_unique_range_subquery(&db, grove_version); let path = vec![TEST_LEAF.to_vec(), b"1".to_vec()]; let mut query = Query::new(); @@ -483,7 +543,7 @@ mod tests { let path_query = PathQuery::new_unsized(path, query.clone()); let (elements, _) = db - .query_item_value(&path_query, true, true, true, None) + .query_item_value(&path_query, true, true, true, None, grove_version) .unwrap() .expect("expected successful get_path_query"); @@ -495,17 +555,22 @@ mod tests { let last_value = 1991_u32.to_be_bytes().to_vec(); assert_eq!(elements[elements.len() - 1], last_value); - let proof = db.prove_query(&path_query, None).unwrap().unwrap(); - let (hash, result_set) = GroveDb::verify_query_raw(&proof, &path_query).unwrap(); - assert_eq!(hash, db.root_hash(None).unwrap().unwrap()); + let proof = db + .prove_query(&path_query, None, grove_version) + .unwrap() + .unwrap(); + let (hash, result_set) = + GroveDb::verify_query_raw(&proof, &path_query, grove_version).unwrap(); + assert_eq!(hash, db.root_hash(None, grove_version).unwrap().unwrap()); assert_eq!(result_set.len(), 4); compare_result_sets(&elements, &result_set); } #[test] fn test_get_range_query_with_unique_subquery_with_non_unique_null_values() { - let mut db = make_test_grovedb(); - populate_tree_for_unique_range_subquery_with_non_unique_null_values(&mut db); + let grove_version = GroveVersion::latest(); + let mut db = make_test_grovedb(grove_version); + populate_tree_for_unique_range_subquery_with_non_unique_null_values(&mut db, grove_version); let path = vec![TEST_LEAF.to_vec()]; let mut query = Query::new(); @@ -527,7 +592,7 @@ mod tests { let path_query = PathQuery::new_unsized(path, query.clone()); let (elements, _) = db - .query_item_value(&path_query, true, true, true, None) + .query_item_value(&path_query, true, true, true, None, grove_version) .unwrap() .expect("expected successful get_path_query"); @@ -539,17 +604,22 @@ mod tests { let last_value = 1999_u32.to_be_bytes().to_vec(); assert_eq!(elements[elements.len() - 1], last_value); - let proof = db.prove_query(&path_query, None).unwrap().unwrap(); - let (hash, result_set) = GroveDb::verify_query_raw(&proof, &path_query).unwrap(); - assert_eq!(hash, db.root_hash(None).unwrap().unwrap()); + let proof = db + .prove_query(&path_query, None, grove_version) + .unwrap() + .unwrap(); + let (hash, result_set) = + GroveDb::verify_query_raw(&proof, &path_query, grove_version).unwrap(); + assert_eq!(hash, db.root_hash(None, grove_version).unwrap().unwrap()); assert_eq!(result_set.len(), 115); compare_result_sets(&elements, &result_set); } #[test] fn test_get_range_query_with_unique_subquery_ignore_non_unique_null_values() { - let mut db = make_test_grovedb(); - populate_tree_for_unique_range_subquery_with_non_unique_null_values(&mut db); + let grove_version = GroveVersion::latest(); + let mut db = make_test_grovedb(grove_version); + populate_tree_for_unique_range_subquery_with_non_unique_null_values(&mut db, grove_version); let path = vec![TEST_LEAF.to_vec()]; let mut query = Query::new(); @@ -565,14 +635,14 @@ mod tests { // tree query.add_conditional_subquery( QueryItem::Key(b"".to_vec()), - Some(vec![b"\0".to_vec()]), // We want to go into 0 but we don't want to get anything + Some(vec![b"\0".to_vec()]), // We want to go into 0, but we don't want to get anything Some(subquery), ); let path_query = PathQuery::new_unsized(path, query.clone()); let (elements, _) = db - .query_item_value(&path_query, true, true, true, None) + .query_item_value(&path_query, true, true, true, None, grove_version) .unwrap() .expect("expected successful get_path_query"); @@ -584,17 +654,22 @@ mod tests { let last_value = 1999_u32.to_be_bytes().to_vec(); assert_eq!(elements[elements.len() - 1], last_value); - let proof = db.prove_query(&path_query, None).unwrap().unwrap(); - let (hash, result_set) = GroveDb::verify_query_raw(&proof, &path_query).unwrap(); - assert_eq!(hash, db.root_hash(None).unwrap().unwrap()); + let proof = db + .prove_query(&path_query, None, grove_version) + .unwrap() + .unwrap(); + let (hash, result_set) = + GroveDb::verify_query_raw(&proof, &path_query, grove_version).unwrap(); + assert_eq!(hash, db.root_hash(None, grove_version).unwrap().unwrap()); assert_eq!(result_set.len(), 15); compare_result_sets(&elements, &result_set); } #[test] fn test_get_range_inclusive_query_with_non_unique_subquery() { - let db = make_test_grovedb(); - populate_tree_for_non_unique_range_subquery(&db); + let grove_version = GroveVersion::latest(); + let db = make_test_grovedb(grove_version); + populate_tree_for_non_unique_range_subquery(&db, grove_version); let path = vec![TEST_LEAF.to_vec()]; let mut query = Query::new(); @@ -612,7 +687,7 @@ mod tests { let path_query = PathQuery::new_unsized(path, query.clone()); let (elements, _) = db - .query_item_value(&path_query, true, true, true, None) + .query_item_value(&path_query, true, true, true, None, grove_version) .unwrap() .expect("expected successful get_path_query"); @@ -626,17 +701,22 @@ mod tests { last_value.append(&mut 149_u32.to_be_bytes().to_vec()); assert_eq!(elements[elements.len() - 1], last_value); - let proof = db.prove_query(&path_query, None).unwrap().unwrap(); - let (hash, result_set) = GroveDb::verify_query_raw(&proof, &path_query).unwrap(); - assert_eq!(hash, db.root_hash(None).unwrap().unwrap()); + let proof = db + .prove_query(&path_query, None, grove_version) + .unwrap() + .unwrap(); + let (hash, result_set) = + GroveDb::verify_query_raw(&proof, &path_query, grove_version).unwrap(); + assert_eq!(hash, db.root_hash(None, grove_version).unwrap().unwrap()); assert_eq!(result_set.len(), 400); compare_result_sets(&elements, &result_set); } #[test] fn test_get_range_inclusive_query_with_non_unique_subquery_on_references() { - let db = make_test_grovedb(); - populate_tree_by_reference_for_non_unique_range_subquery(&db); + let grove_version = GroveVersion::latest(); + let db = make_test_grovedb(grove_version); + populate_tree_by_reference_for_non_unique_range_subquery(&db, grove_version); let path = vec![TEST_LEAF.to_vec(), b"1".to_vec()]; let mut query = Query::new(); @@ -654,7 +734,7 @@ mod tests { let path_query = PathQuery::new_unsized(path, query.clone()); let (elements, _) = db - .query_item_value(&path_query, true, true, true, None) + .query_item_value(&path_query, true, true, true, None, grove_version) .unwrap() .expect("expected successful get_path_query"); @@ -671,17 +751,22 @@ mod tests { last_value.append(&mut 149_u32.to_be_bytes().to_vec()); assert!(elements.contains(&last_value)); - let proof = db.prove_query(&path_query, None).unwrap().unwrap(); - let (hash, result_set) = GroveDb::verify_query_raw(&proof, &path_query).unwrap(); - assert_eq!(hash, db.root_hash(None).unwrap().unwrap()); + let proof = db + .prove_query(&path_query, None, grove_version) + .unwrap() + .unwrap(); + let (hash, result_set) = + GroveDb::verify_query_raw(&proof, &path_query, grove_version).unwrap(); + assert_eq!(hash, db.root_hash(None, grove_version).unwrap().unwrap()); assert_eq!(result_set.len(), 400); compare_result_sets(&elements, &result_set); } #[test] fn test_get_range_inclusive_query_with_unique_subquery() { - let db = make_test_grovedb(); - populate_tree_for_unique_range_subquery(&db); + let grove_version = GroveVersion::latest(); + let db = make_test_grovedb(grove_version); + populate_tree_for_unique_range_subquery(&db, grove_version); let path = vec![TEST_LEAF.to_vec()]; let mut query = Query::new(); @@ -696,7 +781,7 @@ mod tests { let path_query = PathQuery::new_unsized(path, query.clone()); let (elements, _) = db - .query_item_value(&path_query, true, true, true, None) + .query_item_value(&path_query, true, true, true, None, grove_version) .unwrap() .expect("expected successful get_path_query"); @@ -708,17 +793,22 @@ mod tests { let last_value = 1995_u32.to_be_bytes().to_vec(); assert_eq!(elements[elements.len() - 1], last_value); - let proof = db.prove_query(&path_query, None).unwrap().unwrap(); - let (hash, result_set) = GroveDb::verify_query_raw(&proof, &path_query).unwrap(); - assert_eq!(hash, db.root_hash(None).unwrap().unwrap()); + let proof = db + .prove_query(&path_query, None, grove_version) + .unwrap() + .unwrap(); + let (hash, result_set) = + GroveDb::verify_query_raw(&proof, &path_query, grove_version).unwrap(); + assert_eq!(hash, db.root_hash(None, grove_version).unwrap().unwrap()); assert_eq!(result_set.len(), 8); compare_result_sets(&elements, &result_set); } #[test] fn test_get_range_from_query_with_non_unique_subquery() { - let db = make_test_grovedb(); - populate_tree_for_non_unique_range_subquery(&db); + let grove_version = GroveVersion::latest(); + let db = make_test_grovedb(grove_version); + populate_tree_for_non_unique_range_subquery(&db, grove_version); let path = vec![TEST_LEAF.to_vec()]; let mut query = Query::new(); @@ -734,7 +824,7 @@ mod tests { let path_query = PathQuery::new_unsized(path, query.clone()); let (elements, _) = db - .query_item_value(&path_query, true, true, true, None) + .query_item_value(&path_query, true, true, true, None, grove_version) .unwrap() .expect("expected successful get_path_query"); @@ -748,17 +838,22 @@ mod tests { last_value.append(&mut 149_u32.to_be_bytes().to_vec()); assert_eq!(elements[elements.len() - 1], last_value); - let proof = db.prove_query(&path_query, None).unwrap().unwrap(); - let (hash, result_set) = GroveDb::verify_query_raw(&proof, &path_query).unwrap(); - assert_eq!(hash, db.root_hash(None).unwrap().unwrap()); + let proof = db + .prove_query(&path_query, None, grove_version) + .unwrap() + .unwrap(); + let (hash, result_set) = + GroveDb::verify_query_raw(&proof, &path_query, grove_version).unwrap(); + assert_eq!(hash, db.root_hash(None, grove_version).unwrap().unwrap()); assert_eq!(result_set.len(), 250); compare_result_sets(&elements, &result_set); } #[test] fn test_get_range_from_query_with_unique_subquery() { - let db = make_test_grovedb(); - populate_tree_for_unique_range_subquery(&db); + let grove_version = GroveVersion::latest(); + let db = make_test_grovedb(grove_version); + populate_tree_for_unique_range_subquery(&db, grove_version); let path = vec![TEST_LEAF.to_vec()]; let mut query = Query::new(); @@ -771,7 +866,7 @@ mod tests { let path_query = PathQuery::new_unsized(path, query.clone()); let (elements, _) = db - .query_item_value(&path_query, true, true, true, None) + .query_item_value(&path_query, true, true, true, None, grove_version) .unwrap() .expect("expected successful get_path_query"); @@ -783,17 +878,22 @@ mod tests { let last_value = 1999_u32.to_be_bytes().to_vec(); assert_eq!(elements[elements.len() - 1], last_value); - let proof = db.prove_query(&path_query, None).unwrap().unwrap(); - let (hash, result_set) = GroveDb::verify_query_raw(&proof, &path_query).unwrap(); - assert_eq!(hash, db.root_hash(None).unwrap().unwrap()); + let proof = db + .prove_query(&path_query, None, grove_version) + .unwrap() + .unwrap(); + let (hash, result_set) = + GroveDb::verify_query_raw(&proof, &path_query, grove_version).unwrap(); + assert_eq!(hash, db.root_hash(None, grove_version).unwrap().unwrap()); assert_eq!(result_set.len(), 5); compare_result_sets(&elements, &result_set); } #[test] fn test_get_range_to_query_with_non_unique_subquery() { - let db = make_test_grovedb(); - populate_tree_for_non_unique_range_subquery(&db); + let grove_version = GroveVersion::latest(); + let db = make_test_grovedb(grove_version); + populate_tree_for_non_unique_range_subquery(&db, grove_version); let path = vec![TEST_LEAF.to_vec()]; let mut query = Query::new(); @@ -809,7 +909,7 @@ mod tests { let path_query = PathQuery::new_unsized(path, query.clone()); let (elements, _) = db - .query_item_value(&path_query, true, true, true, None) + .query_item_value(&path_query, true, true, true, None, grove_version) .unwrap() .expect("expected successful get_path_query"); @@ -823,17 +923,22 @@ mod tests { last_value.append(&mut 149_u32.to_be_bytes().to_vec()); assert_eq!(elements[elements.len() - 1], last_value); - let proof = db.prove_query(&path_query, None).unwrap().unwrap(); - let (hash, result_set) = GroveDb::verify_query_raw(&proof, &path_query).unwrap(); - assert_eq!(hash, db.root_hash(None).unwrap().unwrap()); + let proof = db + .prove_query(&path_query, None, grove_version) + .unwrap() + .unwrap(); + let (hash, result_set) = + GroveDb::verify_query_raw(&proof, &path_query, grove_version).unwrap(); + assert_eq!(hash, db.root_hash(None, grove_version).unwrap().unwrap()); assert_eq!(result_set.len(), 500); compare_result_sets(&elements, &result_set); } #[test] fn test_get_range_to_query_with_unique_subquery() { - let db = make_test_grovedb(); - populate_tree_for_unique_range_subquery(&db); + let grove_version = GroveVersion::latest(); + let db = make_test_grovedb(grove_version); + populate_tree_for_unique_range_subquery(&db, grove_version); let path = vec![TEST_LEAF.to_vec()]; let mut query = Query::new(); @@ -846,7 +951,7 @@ mod tests { let path_query = PathQuery::new_unsized(path, query.clone()); let (elements, _) = db - .query_item_value(&path_query, true, true, true, None) + .query_item_value(&path_query, true, true, true, None, grove_version) .unwrap() .expect("expected successful get_path_query"); @@ -858,17 +963,22 @@ mod tests { let last_value = 1994_u32.to_be_bytes().to_vec(); assert_eq!(elements[elements.len() - 1], last_value); - let proof = db.prove_query(&path_query, None).unwrap().unwrap(); - let (hash, result_set) = GroveDb::verify_query_raw(&proof, &path_query).unwrap(); - assert_eq!(hash, db.root_hash(None).unwrap().unwrap()); + let proof = db + .prove_query(&path_query, None, grove_version) + .unwrap() + .unwrap(); + let (hash, result_set) = + GroveDb::verify_query_raw(&proof, &path_query, grove_version).unwrap(); + assert_eq!(hash, db.root_hash(None, grove_version).unwrap().unwrap()); assert_eq!(result_set.len(), 10); compare_result_sets(&elements, &result_set); } #[test] fn test_get_range_to_inclusive_query_with_non_unique_subquery() { - let db = make_test_grovedb(); - populate_tree_for_non_unique_range_subquery(&db); + let grove_version = GroveVersion::latest(); + let db = make_test_grovedb(grove_version); + populate_tree_for_non_unique_range_subquery(&db, grove_version); let path = vec![TEST_LEAF.to_vec()]; let mut query = Query::new(); @@ -884,7 +994,7 @@ mod tests { let path_query = PathQuery::new_unsized(path, query.clone()); let (elements, _) = db - .query_item_value(&path_query, true, true, true, None) + .query_item_value(&path_query, true, true, true, None, grove_version) .unwrap() .expect("expected successful get_path_query"); @@ -898,17 +1008,22 @@ mod tests { last_value.append(&mut 149_u32.to_be_bytes().to_vec()); assert_eq!(elements[elements.len() - 1], last_value); - let proof = db.prove_query(&path_query, None).unwrap().unwrap(); - let (hash, result_set) = GroveDb::verify_query_raw(&proof, &path_query).unwrap(); - assert_eq!(hash, db.root_hash(None).unwrap().unwrap()); + let proof = db + .prove_query(&path_query, None, grove_version) + .unwrap() + .unwrap(); + let (hash, result_set) = + GroveDb::verify_query_raw(&proof, &path_query, grove_version).unwrap(); + assert_eq!(hash, db.root_hash(None, grove_version).unwrap().unwrap()); assert_eq!(result_set.len(), 550); compare_result_sets(&elements, &result_set); } #[test] fn test_get_range_to_inclusive_query_with_non_unique_subquery_and_key_out_of_bounds() { - let db = make_test_grovedb(); - populate_tree_for_non_unique_range_subquery(&db); + let grove_version = GroveVersion::latest(); + let db = make_test_grovedb(grove_version); + populate_tree_for_non_unique_range_subquery(&db, grove_version); let path = vec![TEST_LEAF.to_vec()]; let mut query = Query::new_with_direction(false); @@ -924,7 +1039,7 @@ mod tests { let path_query = PathQuery::new_unsized(path, query.clone()); let (elements, _) = db - .query_item_value(&path_query, true, true, true, None) + .query_item_value(&path_query, true, true, true, None, grove_version) .unwrap() .expect("expected successful get_path_query"); @@ -938,17 +1053,22 @@ mod tests { last_value.append(&mut 100_u32.to_be_bytes().to_vec()); assert_eq!(elements[elements.len() - 1], last_value); - let proof = db.prove_query(&path_query, None).unwrap().unwrap(); - let (hash, result_set) = GroveDb::verify_query_raw(&proof, &path_query).unwrap(); - assert_eq!(hash, db.root_hash(None).unwrap().unwrap()); + let proof = db + .prove_query(&path_query, None, grove_version) + .unwrap() + .unwrap(); + let (hash, result_set) = + GroveDb::verify_query_raw(&proof, &path_query, grove_version).unwrap(); + assert_eq!(hash, db.root_hash(None, grove_version).unwrap().unwrap()); assert_eq!(result_set.len(), 750); compare_result_sets(&elements, &result_set); } #[test] fn test_get_range_to_inclusive_query_with_unique_subquery() { - let db = make_test_grovedb(); - populate_tree_for_unique_range_subquery(&db); + let grove_version = GroveVersion::latest(); + let db = make_test_grovedb(grove_version); + populate_tree_for_unique_range_subquery(&db, grove_version); let path = vec![TEST_LEAF.to_vec()]; let mut query = Query::new(); @@ -961,7 +1081,7 @@ mod tests { let path_query = PathQuery::new_unsized(path, query.clone()); let (elements, _) = db - .query_item_value(&path_query, true, true, true, None) + .query_item_value(&path_query, true, true, true, None, grove_version) .unwrap() .expect("expected successful get_path_query"); @@ -973,17 +1093,22 @@ mod tests { let last_value = 1995_u32.to_be_bytes().to_vec(); assert_eq!(elements[elements.len() - 1], last_value); - let proof = db.prove_query(&path_query, None).unwrap().unwrap(); - let (hash, result_set) = GroveDb::verify_query_raw(&proof, &path_query).unwrap(); - assert_eq!(hash, db.root_hash(None).unwrap().unwrap()); + let proof = db + .prove_query(&path_query, None, grove_version) + .unwrap() + .unwrap(); + let (hash, result_set) = + GroveDb::verify_query_raw(&proof, &path_query, grove_version).unwrap(); + assert_eq!(hash, db.root_hash(None, grove_version).unwrap().unwrap()); assert_eq!(result_set.len(), 11); compare_result_sets(&elements, &result_set); } #[test] fn test_get_range_after_query_with_non_unique_subquery() { - let db = make_test_grovedb(); - populate_tree_for_non_unique_range_subquery(&db); + let grove_version = GroveVersion::latest(); + let db = make_test_grovedb(grove_version); + populate_tree_for_non_unique_range_subquery(&db, grove_version); let path = vec![TEST_LEAF.to_vec()]; let mut query = Query::new(); @@ -999,7 +1124,7 @@ mod tests { let path_query = PathQuery::new_unsized(path, query.clone()); let (elements, _) = db - .query_item_value(&path_query, true, true, true, None) + .query_item_value(&path_query, true, true, true, None, grove_version) .unwrap() .expect("expected successful get_path_query"); @@ -1013,17 +1138,22 @@ mod tests { last_value.append(&mut 149_u32.to_be_bytes().to_vec()); assert_eq!(elements[elements.len() - 1], last_value); - let proof = db.prove_query(&path_query, None).unwrap().unwrap(); - let (hash, result_set) = GroveDb::verify_query_raw(&proof, &path_query).unwrap(); - assert_eq!(hash, db.root_hash(None).unwrap().unwrap()); + let proof = db + .prove_query(&path_query, None, grove_version) + .unwrap() + .unwrap(); + let (hash, result_set) = + GroveDb::verify_query_raw(&proof, &path_query, grove_version).unwrap(); + assert_eq!(hash, db.root_hash(None, grove_version).unwrap().unwrap()); assert_eq!(result_set.len(), 200); compare_result_sets(&elements, &result_set); } #[test] fn test_get_range_after_to_query_with_non_unique_subquery() { - let db = make_test_grovedb(); - populate_tree_for_non_unique_range_subquery(&db); + let grove_version = GroveVersion::latest(); + let db = make_test_grovedb(grove_version); + populate_tree_for_non_unique_range_subquery(&db, grove_version); let path = vec![TEST_LEAF.to_vec()]; let mut query = Query::new(); @@ -1041,7 +1171,7 @@ mod tests { let path_query = PathQuery::new_unsized(path, query.clone()); let (elements, _) = db - .query_item_value(&path_query, true, true, true, None) + .query_item_value(&path_query, true, true, true, None, grove_version) .unwrap() .expect("expected successful get_path_query"); @@ -1055,17 +1185,22 @@ mod tests { last_value.append(&mut 149_u32.to_be_bytes().to_vec()); assert_eq!(elements[elements.len() - 1], last_value); - let proof = db.prove_query(&path_query, None).unwrap().unwrap(); - let (hash, result_set) = GroveDb::verify_query_raw(&proof, &path_query).unwrap(); - assert_eq!(hash, db.root_hash(None).unwrap().unwrap()); + let proof = db + .prove_query(&path_query, None, grove_version) + .unwrap() + .unwrap(); + let (hash, result_set) = + GroveDb::verify_query_raw(&proof, &path_query, grove_version).unwrap(); + assert_eq!(hash, db.root_hash(None, grove_version).unwrap().unwrap()); assert_eq!(result_set.len(), 50); compare_result_sets(&elements, &result_set); } #[test] fn test_get_range_after_to_inclusive_query_with_non_unique_subquery() { - let db = make_test_grovedb(); - populate_tree_for_non_unique_range_subquery(&db); + let grove_version = GroveVersion::latest(); + let db = make_test_grovedb(grove_version); + populate_tree_for_non_unique_range_subquery(&db, grove_version); let path = vec![TEST_LEAF.to_vec()]; let mut query = Query::new(); @@ -1083,7 +1218,7 @@ mod tests { let path_query = PathQuery::new_unsized(path, query.clone()); let (elements, _) = db - .query_item_value(&path_query, true, true, true, None) + .query_item_value(&path_query, true, true, true, None, grove_version) .unwrap() .expect("expected successful get_path_query"); @@ -1097,17 +1232,22 @@ mod tests { last_value.append(&mut 149_u32.to_be_bytes().to_vec()); assert_eq!(elements[elements.len() - 1], last_value); - let proof = db.prove_query(&path_query, None).unwrap().unwrap(); - let (hash, result_set) = GroveDb::verify_query_raw(&proof, &path_query).unwrap(); - assert_eq!(hash, db.root_hash(None).unwrap().unwrap()); + let proof = db + .prove_query(&path_query, None, grove_version) + .unwrap() + .unwrap(); + let (hash, result_set) = + GroveDb::verify_query_raw(&proof, &path_query, grove_version).unwrap(); + assert_eq!(hash, db.root_hash(None, grove_version).unwrap().unwrap()); assert_eq!(result_set.len(), 100); compare_result_sets(&elements, &result_set); } #[test] fn test_get_range_after_to_inclusive_query_with_non_unique_subquery_and_key_out_of_bounds() { - let db = make_test_grovedb(); - populate_tree_for_non_unique_range_subquery(&db); + let grove_version = GroveVersion::latest(); + let db = make_test_grovedb(grove_version); + populate_tree_for_non_unique_range_subquery(&db, grove_version); let path = vec![TEST_LEAF.to_vec()]; let mut query = Query::new_with_direction(false); @@ -1125,7 +1265,7 @@ mod tests { let path_query = PathQuery::new_unsized(path, query.clone()); let (elements, _) = db - .query_item_value(&path_query, true, true, true, None) + .query_item_value(&path_query, true, true, true, None, grove_version) .unwrap() .expect("expected successful get_path_query"); @@ -1139,28 +1279,32 @@ mod tests { last_value.append(&mut 100_u32.to_be_bytes().to_vec()); assert_eq!(elements[elements.len() - 1], last_value); - let proof = db.prove_query(&path_query, None).unwrap().unwrap(); - let (hash, result_set) = GroveDb::verify_query_raw(&proof, &path_query).unwrap(); - assert_eq!(hash, db.root_hash(None).unwrap().unwrap()); + let proof = db + .prove_query(&path_query, None, grove_version) + .unwrap() + .unwrap(); + let (hash, result_set) = + GroveDb::verify_query_raw(&proof, &path_query, grove_version).unwrap(); + assert_eq!(hash, db.root_hash(None, grove_version).unwrap().unwrap()); assert_eq!(result_set.len(), 200); compare_result_sets(&elements, &result_set); } #[test] fn test_get_range_inclusive_query_with_double_non_unique_subquery() { - let db = make_test_grovedb(); - populate_tree_for_non_unique_double_range_subquery(&db); + let grove_version = GroveVersion::latest(); + let db = make_test_grovedb(grove_version); + populate_tree_for_non_unique_double_range_subquery(&db, grove_version); let path = vec![TEST_LEAF.to_vec()]; let mut query = Query::new(); - query.insert_range_inclusive((3u32).to_be_bytes().to_vec()..=(4u32).to_be_bytes().to_vec()); + query.insert_range_inclusive(3u32.to_be_bytes().to_vec()..=4u32.to_be_bytes().to_vec()); query.set_subquery_key(b"a".to_vec()); let mut subquery = Query::new(); - subquery.insert_range_inclusive( - (29u32).to_be_bytes().to_vec()..=(31u32).to_be_bytes().to_vec(), - ); + subquery + .insert_range_inclusive(29u32.to_be_bytes().to_vec()..=31u32.to_be_bytes().to_vec()); subquery.set_subquery_key(b"\0".to_vec()); @@ -1174,7 +1318,7 @@ mod tests { let path_query = PathQuery::new_unsized(path, query.clone()); let (elements, _) = db - .query_item_value(&path_query, true, true, true, None) + .query_item_value(&path_query, true, true, true, None, grove_version) .unwrap() .expect("expected successful get_path_query"); @@ -1186,17 +1330,22 @@ mod tests { let last_value = 109_u32.to_be_bytes().to_vec(); assert_eq!(elements[elements.len() - 1], last_value); - let proof = db.prove_query(&path_query, None).unwrap().unwrap(); - let (hash, result_set) = GroveDb::verify_query_raw(&proof, &path_query).unwrap(); - assert_eq!(hash, db.root_hash(None).unwrap().unwrap()); + let proof = db + .prove_query(&path_query, None, grove_version) + .unwrap() + .unwrap(); + let (hash, result_set) = + GroveDb::verify_query_raw(&proof, &path_query, grove_version).unwrap(); + assert_eq!(hash, db.root_hash(None, grove_version).unwrap().unwrap()); assert_eq!(result_set.len(), 60); compare_result_sets(&elements, &result_set); } #[test] fn test_get_range_query_with_limit_and_offset() { - let db = make_test_grovedb(); - populate_tree_for_non_unique_range_subquery(&db); + let grove_version = GroveVersion::latest(); + let db = make_test_grovedb(grove_version); + populate_tree_for_non_unique_range_subquery(&db, grove_version); let path = vec![TEST_LEAF.to_vec()]; let mut query = Query::new_with_direction(true); @@ -1213,7 +1362,7 @@ mod tests { let path_query = PathQuery::new(path.clone(), SizedQuery::new(query.clone(), None, None)); let (elements, _) = db - .query_item_value(&path_query, true, true, true, None) + .query_item_value(&path_query, true, true, true, None, grove_version) .unwrap() .expect("expected successful get_path_query"); @@ -1227,9 +1376,13 @@ mod tests { last_value.append(&mut 149_u32.to_be_bytes().to_vec()); assert_eq!(elements[elements.len() - 1], last_value); - let proof = db.prove_query(&path_query, None).unwrap().unwrap(); - let (hash, result_set) = GroveDb::verify_query_raw(&proof, &path_query).unwrap(); - assert_eq!(hash, db.root_hash(None).unwrap().unwrap()); + let proof = db + .prove_query(&path_query, None, grove_version) + .unwrap() + .unwrap(); + let (hash, result_set) = + GroveDb::verify_query_raw(&proof, &path_query, grove_version).unwrap(); + assert_eq!(hash, db.root_hash(None, grove_version).unwrap().unwrap()); assert_eq!(result_set.len(), 250); compare_result_sets(&elements, &result_set); @@ -1244,7 +1397,7 @@ mod tests { let path_query = PathQuery::new(path.clone(), SizedQuery::new(query.clone(), None, None)); let (elements, _) = db - .query_item_value(&path_query, true, true, true, None) + .query_item_value(&path_query, true, true, true, None, grove_version) .unwrap() .expect("expected successful get_path_query"); @@ -1258,9 +1411,13 @@ mod tests { last_value.append(&mut 100_u32.to_be_bytes().to_vec()); assert_eq!(elements[elements.len() - 1], last_value); - let proof = db.prove_query(&path_query, None).unwrap().unwrap(); - let (hash, result_set) = GroveDb::verify_query_raw(&proof, &path_query).unwrap(); - assert_eq!(hash, db.root_hash(None).unwrap().unwrap()); + let proof = db + .prove_query(&path_query, None, grove_version) + .unwrap() + .unwrap(); + let (hash, result_set) = + GroveDb::verify_query_raw(&proof, &path_query, grove_version).unwrap(); + assert_eq!(hash, db.root_hash(None, grove_version).unwrap().unwrap()); assert_eq!(result_set.len(), 250); compare_result_sets(&elements, &result_set); @@ -1276,7 +1433,7 @@ mod tests { PathQuery::new(path.clone(), SizedQuery::new(query.clone(), Some(55), None)); let (elements, _) = db - .query_item_value(&path_query, true, true, true, None) + .query_item_value(&path_query, true, true, true, None, grove_version) .unwrap() .expect("expected successful get_path_query"); @@ -1291,9 +1448,13 @@ mod tests { last_value.append(&mut 104_u32.to_be_bytes().to_vec()); assert_eq!(elements[elements.len() - 1], last_value); - let proof = db.prove_query(&path_query, None).unwrap().unwrap(); - let (hash, result_set) = GroveDb::verify_query_raw(&proof, &path_query).unwrap(); - assert_eq!(hash, db.root_hash(None).unwrap().unwrap()); + let proof = db + .prove_query(&path_query, None, grove_version) + .unwrap() + .unwrap(); + let (hash, result_set) = + GroveDb::verify_query_raw(&proof, &path_query, grove_version).unwrap(); + assert_eq!(hash, db.root_hash(None, grove_version).unwrap().unwrap()); assert_eq!(result_set.len(), 55); compare_result_sets(&elements, &result_set); @@ -1307,14 +1468,14 @@ mod tests { ); let (elements, _) = db - .query_item_value(&path_query, true, true, true, None) + .query_item_value(&path_query, true, true, true, None, grove_version) .unwrap() .expect("expected successful get_path_query"); assert_eq!(elements.len(), 60); // Skips the first 14 elements, starts from the 15th - // i.e skips [100 - 113] starts from 114 + // i.e. skips [100 - 113] starts from 114 let mut first_value = 1990_u32.to_be_bytes().to_vec(); first_value.append(&mut 114_u32.to_be_bytes().to_vec()); assert_eq!(elements[0], first_value); @@ -1339,7 +1500,7 @@ mod tests { ); let (elements, _) = db - .query_item_value(&path_query, true, true, true, None) + .query_item_value(&path_query, true, true, true, None, grove_version) .unwrap() .expect("expected successful get_path_query"); @@ -1368,7 +1529,7 @@ mod tests { ); let (elements, _) = db - .query_item_value(&path_query, true, true, true, None) + .query_item_value(&path_query, true, true, true, None, grove_version) .unwrap() .expect("expected successful get_path_query"); @@ -1384,20 +1545,24 @@ mod tests { ); let (elements, _) = db - .query_item_value(&path_query, true, true, true, None) + .query_item_value(&path_query, true, true, true, None, grove_version) .unwrap() .expect("expected successful get_path_query"); assert_eq!(elements.len(), 250); - let proof = db.prove_query(&path_query, None).unwrap().unwrap(); - let (hash, result_set) = GroveDb::verify_query_raw(&proof, &path_query).unwrap(); - assert_eq!(hash, db.root_hash(None).unwrap().unwrap()); + let proof = db + .prove_query(&path_query, None, grove_version) + .unwrap() + .unwrap(); + let (hash, result_set) = + GroveDb::verify_query_raw(&proof, &path_query, grove_version).unwrap(); + assert_eq!(hash, db.root_hash(None, grove_version).unwrap().unwrap()); assert_eq!(result_set.len(), 250); // Test on unique subtree build - let db = make_test_grovedb(); - populate_tree_for_unique_range_subquery(&db); + let db = make_test_grovedb(grove_version); + populate_tree_for_unique_range_subquery(&db, grove_version); let mut query = Query::new_with_direction(true); query.insert_range(1990_u32.to_be_bytes().to_vec()..2000_u32.to_be_bytes().to_vec()); @@ -1407,7 +1572,7 @@ mod tests { let path_query = PathQuery::new(path, SizedQuery::new(query.clone(), Some(5), Some(2))); let (elements, _) = db - .query_item_value(&path_query, true, true, true, None) + .query_item_value(&path_query, true, true, true, None, grove_version) .unwrap() .expect("expected successful get_path_query"); @@ -1422,6 +1587,7 @@ mod tests { #[test] fn test_correct_child_root_hash_propagation_for_parent_in_same_batch() { + let grove_version = GroveVersion::latest(); let tmp_dir = TempDir::new().unwrap(); let db = GroveDb::open(tmp_dir.path()).unwrap(); let tree_name_slice: &[u8] = &[ @@ -1430,7 +1596,7 @@ mod tests { ]; let batch = vec![GroveDbOp::insert_op(vec![], vec![1], Element::empty_tree())]; - db.apply_batch(batch, None, None) + db.apply_batch(batch, None, None, grove_version) .unwrap() .expect("should apply batch"); @@ -1476,7 +1642,7 @@ mod tests { Element::empty_tree(), ), ]; - db.apply_batch(batch, None, None) + db.apply_batch(batch, None, None, grove_version) .unwrap() .expect("should apply batch"); @@ -1532,7 +1698,7 @@ mod tests { )), ), ]; - db.apply_batch(batch, None, None) + db.apply_batch(batch, None, None, grove_version) .unwrap() .expect("should apply batch"); @@ -1559,16 +1725,18 @@ mod tests { ); let proof = db - .prove_query(&path_query, None) + .prove_query(&path_query, None, grove_version) .unwrap() .expect("expected successful proving"); - let (hash, _result_set) = GroveDb::verify_query_raw(&proof, &path_query).unwrap(); - assert_eq!(hash, db.root_hash(None).unwrap().unwrap()); + let (hash, _result_set) = + GroveDb::verify_query_raw(&proof, &path_query, grove_version).unwrap(); + assert_eq!(hash, db.root_hash(None, grove_version).unwrap().unwrap()); } #[test] fn test_mixed_level_proofs() { - let db = make_test_grovedb(); + let grove_version = GroveVersion::latest(); + let db = make_test_grovedb(grove_version); // TEST_LEAF // / | | \ @@ -1584,6 +1752,7 @@ mod tests { Element::empty_tree(), None, None, + grove_version, ) .unwrap() .expect("successful subtree insert"); @@ -1593,6 +1762,7 @@ mod tests { Element::new_item(vec![1]), None, None, + grove_version, ) .unwrap() .expect("successful item insert"); @@ -1602,6 +1772,7 @@ mod tests { Element::empty_tree(), None, None, + grove_version, ) .unwrap() .expect("successful subtree insert"); @@ -1611,6 +1782,7 @@ mod tests { Element::new_reference(ReferencePathType::SiblingReference(b"key2".to_vec())), None, None, + grove_version, ) .unwrap() .expect("successful subtree insert"); @@ -1621,6 +1793,7 @@ mod tests { Element::new_item(vec![2]), None, None, + grove_version, ) .unwrap() .expect("successful item insert"); @@ -1630,6 +1803,7 @@ mod tests { Element::new_item(vec![3]), None, None, + grove_version, ) .unwrap() .expect("successful item insert"); @@ -1639,6 +1813,7 @@ mod tests { Element::new_item(vec![4]), None, None, + grove_version, ) .unwrap() .expect("successful item insert"); @@ -1653,16 +1828,20 @@ mod tests { let path_query = PathQuery::new_unsized(path.clone(), query.clone()); let (elements, _) = db - .query_item_value(&path_query, true, true, true, None) + .query_item_value(&path_query, true, true, true, None, grove_version) .unwrap() .expect("successful get_path_query"); assert_eq!(elements.len(), 5); assert_eq!(elements, vec![vec![2], vec![3], vec![4], vec![1], vec![1]]); - let proof = db.prove_query(&path_query, None).unwrap().unwrap(); - let (hash, result_set) = GroveDb::verify_query_raw(&proof, &path_query).unwrap(); - assert_eq!(hash, db.root_hash(None).unwrap().unwrap()); + let proof = db + .prove_query(&path_query, None, grove_version) + .unwrap() + .unwrap(); + let (hash, result_set) = + GroveDb::verify_query_raw(&proof, &path_query, grove_version).unwrap(); + assert_eq!(hash, db.root_hash(None, grove_version).unwrap().unwrap()); // println!( // "{}", // result_set @@ -1677,16 +1856,20 @@ mod tests { // Test mixed element proofs with limit and offset let path_query = PathQuery::new_unsized(path.clone(), query.clone()); let (elements, _) = db - .query_item_value(&path_query, true, true, true, None) + .query_item_value(&path_query, true, true, true, None, grove_version) .unwrap() .expect("successful get_path_query"); assert_eq!(elements.len(), 5); assert_eq!(elements, vec![vec![2], vec![3], vec![4], vec![1], vec![1]]); - let proof = db.prove_query(&path_query, None).unwrap().unwrap(); - let (hash, result_set) = GroveDb::verify_query_raw(&proof, &path_query).unwrap(); - assert_eq!(hash, db.root_hash(None).unwrap().unwrap()); + let proof = db + .prove_query(&path_query, None, grove_version) + .unwrap() + .unwrap(); + let (hash, result_set) = + GroveDb::verify_query_raw(&proof, &path_query, grove_version).unwrap(); + assert_eq!(hash, db.root_hash(None, grove_version).unwrap().unwrap()); assert_eq!(result_set.len(), 5); compare_result_sets(&elements, &result_set); @@ -1695,16 +1878,20 @@ mod tests { let path_query = PathQuery::new(path.clone(), SizedQuery::new(query.clone(), Some(1), None)); let (elements, _) = db - .query_item_value(&path_query, true, true, true, None) + .query_item_value(&path_query, true, true, true, None, grove_version) .unwrap() .expect("successful get_path_query"); assert_eq!(elements.len(), 1); assert_eq!(elements, vec![vec![2]]); - let proof = db.prove_query(&path_query, None).unwrap().unwrap(); - let (hash, result_set) = GroveDb::verify_query_raw(&proof, &path_query).unwrap(); - assert_eq!(hash, db.root_hash(None).unwrap().unwrap()); + let proof = db + .prove_query(&path_query, None, grove_version) + .unwrap() + .unwrap(); + let (hash, result_set) = + GroveDb::verify_query_raw(&proof, &path_query, grove_version).unwrap(); + assert_eq!(hash, db.root_hash(None, grove_version).unwrap().unwrap()); assert_eq!(result_set.len(), 1); compare_result_sets(&elements, &result_set); @@ -1713,16 +1900,20 @@ mod tests { SizedQuery::new(query.clone(), Some(3), Some(0)), ); let (elements, _) = db - .query_item_value(&path_query, true, true, true, None) + .query_item_value(&path_query, true, true, true, None, grove_version) .unwrap() .expect("successful get_path_query"); assert_eq!(elements.len(), 3); assert_eq!(elements, vec![vec![2], vec![3], vec![4]]); - let proof = db.prove_query(&path_query, None).unwrap().unwrap(); - let (hash, result_set) = GroveDb::verify_query_raw(&proof, &path_query).unwrap(); - assert_eq!(hash, db.root_hash(None).unwrap().unwrap()); + let proof = db + .prove_query(&path_query, None, grove_version) + .unwrap() + .unwrap(); + let (hash, result_set) = + GroveDb::verify_query_raw(&proof, &path_query, grove_version).unwrap(); + assert_eq!(hash, db.root_hash(None, grove_version).unwrap().unwrap()); assert_eq!(result_set.len(), 3); compare_result_sets(&elements, &result_set); @@ -1731,22 +1922,26 @@ mod tests { SizedQuery::new(query.clone(), Some(4), Some(0)), ); let (elements, _) = db - .query_item_value(&path_query, true, true, true, None) + .query_item_value(&path_query, true, true, true, None, grove_version) .unwrap() .expect("successful get_path_query"); assert_eq!(elements.len(), 4); assert_eq!(elements, vec![vec![2], vec![3], vec![4], vec![1]]); - let proof = db.prove_query(&path_query, None).unwrap().unwrap(); - let (hash, result_set) = GroveDb::verify_query_raw(&proof, &path_query).unwrap(); - assert_eq!(hash, db.root_hash(None).unwrap().unwrap()); + let proof = db + .prove_query(&path_query, None, grove_version) + .unwrap() + .unwrap(); + let (hash, result_set) = + GroveDb::verify_query_raw(&proof, &path_query, grove_version).unwrap(); + assert_eq!(hash, db.root_hash(None, grove_version).unwrap().unwrap()); assert_eq!(result_set.len(), 4); compare_result_sets(&elements, &result_set); let path_query = PathQuery::new(path, SizedQuery::new(query.clone(), Some(10), Some(4))); let (elements, _) = db - .query_item_value(&path_query, true, true, true, None) + .query_item_value(&path_query, true, true, true, None, grove_version) .unwrap() .expect("successful get_path_query"); @@ -1756,13 +1951,15 @@ mod tests { #[test] fn test_mixed_level_proofs_with_tree() { - let db = make_test_grovedb(); + let grove_version = GroveVersion::latest(); + let db = make_test_grovedb(grove_version); db.insert( [TEST_LEAF].as_ref(), b"key1", Element::empty_tree(), None, None, + grove_version, ) .unwrap() .expect("successful subtree insert"); @@ -1772,6 +1969,7 @@ mod tests { Element::empty_tree(), None, None, + grove_version, ) .unwrap() .expect("successful subtree insert"); @@ -1781,6 +1979,7 @@ mod tests { Element::empty_tree(), None, None, + grove_version, ) .unwrap() .expect("successful subtree insert"); @@ -1791,6 +1990,7 @@ mod tests { Element::new_item(vec![2]), None, None, + grove_version, ) .unwrap() .expect("successful item insert"); @@ -1800,6 +2000,7 @@ mod tests { Element::new_item(vec![3]), None, None, + grove_version, ) .unwrap() .expect("successful item insert"); @@ -1809,6 +2010,7 @@ mod tests { Element::new_item(vec![4]), None, None, + grove_version, ) .unwrap() .expect("successful item insert"); @@ -1818,6 +2020,7 @@ mod tests { Element::new_item(vec![5]), None, None, + grove_version, ) .unwrap() .expect("successful item insert"); @@ -1840,15 +2043,20 @@ mod tests { true, QueryResultType::QueryPathKeyElementTrioResultType, None, + grove_version, ) .unwrap() .expect("expected successful get_path_query"); assert_eq!(elements.len(), 5); - let proof = db.prove_query(&path_query, None).unwrap().unwrap(); - let (hash, result_set) = GroveDb::verify_query_raw(&proof, &path_query).unwrap(); - assert_eq!(hash, db.root_hash(None).unwrap().unwrap()); + let proof = db + .prove_query(&path_query, None, grove_version) + .unwrap() + .unwrap(); + let (hash, result_set) = + GroveDb::verify_query_raw(&proof, &path_query, grove_version).unwrap(); + assert_eq!(hash, db.root_hash(None, grove_version).unwrap().unwrap()); // println!( // "{}", @@ -1873,15 +2081,20 @@ mod tests { true, QueryResultType::QueryPathKeyElementTrioResultType, None, + grove_version, ) .unwrap() .expect("expected successful get_path_query"); assert_eq!(elements.len(), 1); - let proof = db.prove_query(&path_query, None).unwrap().unwrap(); - let (hash, result_set) = GroveDb::verify_query_raw(&proof, &path_query).unwrap(); - assert_eq!(hash, db.root_hash(None).unwrap().unwrap()); + let proof = db + .prove_query(&path_query, None, grove_version) + .unwrap() + .unwrap(); + let (hash, result_set) = + GroveDb::verify_query_raw(&proof, &path_query, grove_version).unwrap(); + assert_eq!(hash, db.root_hash(None, grove_version).unwrap().unwrap()); assert_eq!(result_set.len(), 1); // TODO: verify that the result set is exactly the same // compare_result_sets(&elements, &result_set); @@ -1889,7 +2102,8 @@ mod tests { #[test] fn test_mixed_level_proofs_with_subquery_paths() { - let db = make_test_grovedb(); + let grove_version = GroveVersion::latest(); + let db = make_test_grovedb(grove_version); // TEST_LEAF // / | \ @@ -1906,6 +2120,7 @@ mod tests { Element::empty_tree(), None, None, + grove_version, ) .unwrap() .expect("successful subtree insert"); @@ -1915,6 +2130,7 @@ mod tests { Element::empty_tree(), None, None, + grove_version, ) .unwrap() .expect("successful subtree insert"); @@ -1924,6 +2140,7 @@ mod tests { Element::empty_tree(), None, None, + grove_version, ) .unwrap() .expect("successful subtree insert"); @@ -1934,6 +2151,7 @@ mod tests { Element::empty_tree(), None, None, + grove_version, ) .unwrap() .expect("successful subtree insert"); @@ -1943,6 +2161,7 @@ mod tests { Element::new_item(vec![2]), None, None, + grove_version, ) .unwrap() .expect("successful subtree insert"); @@ -1952,6 +2171,7 @@ mod tests { Element::new_item(vec![3]), None, None, + grove_version, ) .unwrap() .expect("successful subtree insert"); @@ -1962,6 +2182,7 @@ mod tests { Element::new_item(vec![6]), None, None, + grove_version, ) .unwrap() .expect("successful subtree insert"); @@ -1972,6 +2193,7 @@ mod tests { Element::new_item(vec![4]), None, None, + grove_version, ) .unwrap() .expect("successful subtree insert"); @@ -1981,6 +2203,7 @@ mod tests { Element::empty_tree(), None, None, + grove_version, ) .unwrap() .expect("successful subtree insert"); @@ -1991,6 +2214,7 @@ mod tests { Element::empty_tree(), None, None, + grove_version, ) .unwrap() .expect("successful subtree insert"); @@ -2000,6 +2224,7 @@ mod tests { Element::empty_tree(), None, None, + grove_version, ) .unwrap() .expect("successful subtree insert"); @@ -2009,6 +2234,7 @@ mod tests { Element::empty_tree(), None, None, + grove_version, ) .unwrap() .expect("successful subtree insert"); @@ -2030,6 +2256,7 @@ mod tests { false, QueryResultType::QueryPathKeyElementTrioResultType, None, + grove_version, ) .unwrap() .expect("expected successful get_path_query"); @@ -2050,9 +2277,13 @@ mod tests { ]) ); - let proof = db.prove_query(&path_query, None).unwrap().unwrap(); - let (hash, result_set) = GroveDb::verify_query_raw(&proof, &path_query).unwrap(); - assert_eq!(hash, db.root_hash(None).unwrap().unwrap()); + let proof = db + .prove_query(&path_query, None, grove_version) + .unwrap() + .unwrap(); + let (hash, result_set) = + GroveDb::verify_query_raw(&proof, &path_query, grove_version).unwrap(); + assert_eq!(hash, db.root_hash(None, grove_version).unwrap().unwrap()); // println!( // "{}", // result_set @@ -2083,6 +2314,7 @@ mod tests { false, QueryResultType::QueryPathKeyElementTrioResultType, None, + grove_version, ) .unwrap() .expect("expected successful get_path_query"); @@ -2113,9 +2345,13 @@ mod tests { ]) ); - let proof = db.prove_query(&path_query, None).unwrap().unwrap(); - let (hash, result_set) = GroveDb::verify_query_raw(&proof, &path_query).unwrap(); - assert_eq!(hash, db.root_hash(None).unwrap().unwrap()); + let proof = db + .prove_query(&path_query, None, grove_version) + .unwrap() + .unwrap(); + let (hash, result_set) = + GroveDb::verify_query_raw(&proof, &path_query, grove_version).unwrap(); + assert_eq!(hash, db.root_hash(None, grove_version).unwrap().unwrap()); assert_eq!(result_set.len(), 4); // apply empty path translation @@ -2130,9 +2366,13 @@ mod tests { let path_query = PathQuery::new_unsized(path, query.clone()); - let proof = db.prove_query(&path_query, None).unwrap().unwrap(); - let (hash, result_set) = GroveDb::verify_query_raw(&proof, &path_query).unwrap(); - assert_eq!(hash, db.root_hash(None).unwrap().unwrap()); + let proof = db + .prove_query(&path_query, None, grove_version) + .unwrap() + .unwrap(); + let (hash, result_set) = + GroveDb::verify_query_raw(&proof, &path_query, grove_version).unwrap(); + assert_eq!(hash, db.root_hash(None, grove_version).unwrap().unwrap()); assert_eq!(result_set.len(), 5); // use conditionals to return from more than 2 depth @@ -2154,15 +2394,20 @@ mod tests { let path_query = PathQuery::new_unsized(path, query.clone()); - let proof = db.prove_query(&path_query, None).unwrap().unwrap(); - let (hash, result_set) = GroveDb::verify_query_raw(&proof, &path_query).unwrap(); - assert_eq!(hash, db.root_hash(None).unwrap().unwrap()); + let proof = db + .prove_query(&path_query, None, grove_version) + .unwrap() + .unwrap(); + let (hash, result_set) = + GroveDb::verify_query_raw(&proof, &path_query, grove_version).unwrap(); + assert_eq!(hash, db.root_hash(None, grove_version).unwrap().unwrap()); assert_eq!(result_set.len(), 8); } #[test] fn test_proof_with_limit_zero() { - let db = make_deep_tree(); + let grove_version = GroveVersion::latest(); + let db = make_deep_tree(grove_version); let mut query = Query::new(); query.insert_all(); let path_query = PathQuery::new( @@ -2170,22 +2415,27 @@ mod tests { SizedQuery::new(query, Some(0), Some(0)), ); - db.prove_query(&path_query, None) + db.prove_query(&path_query, None, grove_version) .unwrap() .expect_err("expected error when trying to prove with limit 0"); } #[test] fn test_result_set_path_after_verification() { - let db = make_deep_tree(); + let grove_version = GroveVersion::latest(); + let db = make_deep_tree(grove_version); let mut query = Query::new(); query.insert_all(); let path_query = PathQuery::new_unsized(vec![TEST_LEAF.to_vec(), b"innertree".to_vec()], query); - let proof = db.prove_query(&path_query, None).unwrap().unwrap(); - let (hash, result_set) = GroveDb::verify_query_raw(&proof, &path_query).unwrap(); - assert_eq!(hash, db.root_hash(None).unwrap().unwrap()); + let proof = db + .prove_query(&path_query, None, grove_version) + .unwrap() + .unwrap(); + let (hash, result_set) = + GroveDb::verify_query_raw(&proof, &path_query, grove_version).unwrap(); + assert_eq!(hash, db.root_hash(None, grove_version).unwrap().unwrap()); assert_eq!(result_set.len(), 3); // assert the result set path @@ -2214,9 +2464,13 @@ mod tests { query.set_subquery(subq); let path_query = PathQuery::new_unsized(vec![TEST_LEAF.to_vec()], query); - let proof = db.prove_query(&path_query, None).unwrap().unwrap(); - let (hash, result_set) = GroveDb::verify_query_raw(&proof, &path_query).unwrap(); - assert_eq!(hash, db.root_hash(None).unwrap().unwrap()); + let proof = db + .prove_query(&path_query, None, grove_version) + .unwrap() + .unwrap(); + let (hash, result_set) = + GroveDb::verify_query_raw(&proof, &path_query, grove_version).unwrap(); + assert_eq!(hash, db.root_hash(None, grove_version).unwrap().unwrap()); assert_eq!(result_set.len(), 5); assert_eq!( @@ -2250,9 +2504,13 @@ mod tests { query.set_subquery(subq); let path_query = PathQuery::new_unsized(vec![], query); - let proof = db.prove_query(&path_query, None).unwrap().unwrap(); - let (hash, result_set) = GroveDb::verify_query_raw(&proof, &path_query).unwrap(); - assert_eq!(hash, db.root_hash(None).unwrap().unwrap()); + let proof = db + .prove_query(&path_query, None, grove_version) + .unwrap() + .unwrap(); + let (hash, result_set) = + GroveDb::verify_query_raw(&proof, &path_query, grove_version).unwrap(); + assert_eq!(hash, db.root_hash(None, grove_version).unwrap().unwrap()); assert_eq!(result_set.len(), 3); assert_eq!( @@ -2293,9 +2551,13 @@ mod tests { let path_query = PathQuery::new_unsized(vec![TEST_LEAF.to_vec()], query); - let proof = db.prove_query(&path_query, None).unwrap().unwrap(); - let (hash, result_set) = GroveDb::verify_query_raw(&proof, &path_query).unwrap(); - assert_eq!(hash, db.root_hash(None).unwrap().unwrap()); + let proof = db + .prove_query(&path_query, None, grove_version) + .unwrap() + .unwrap(); + let (hash, result_set) = + GroveDb::verify_query_raw(&proof, &path_query, grove_version).unwrap(); + assert_eq!(hash, db.root_hash(None, grove_version).unwrap().unwrap()); assert_eq!(result_set.len(), 4); assert_eq!( @@ -2320,15 +2582,19 @@ mod tests { #[test] fn test_verification_with_path_key_optional_element_trio() { - let db = make_deep_tree(); + let grove_version = GroveVersion::latest(); + let db = make_deep_tree(grove_version); let mut query = Query::new(); query.insert_all(); let path_query = PathQuery::new_unsized(vec![TEST_LEAF.to_vec(), b"innertree".to_vec()], query); - let proof = db.prove_query(&path_query, None).unwrap().unwrap(); - let (hash, result_set) = GroveDb::verify_query(&proof, &path_query).unwrap(); - assert_eq!(hash, db.root_hash(None).unwrap().unwrap()); + let proof = db + .prove_query(&path_query, None, grove_version) + .unwrap() + .unwrap(); + let (hash, result_set) = GroveDb::verify_query(&proof, &path_query, grove_version).unwrap(); + assert_eq!(hash, db.root_hash(None, grove_version).unwrap().unwrap()); assert_eq!(result_set.len(), 3); assert_eq!( @@ -2359,7 +2625,8 @@ mod tests { #[test] fn test_absence_proof() { - let db = make_deep_tree(); + let grove_version = GroveVersion::latest(); + let db = make_deep_tree(grove_version); // simple case, request for items k2..=k5 under inner tree // we pass them as keys as terminal keys does not handle ranges with start or @@ -2375,10 +2642,13 @@ mod tests { SizedQuery::new(query, Some(4), None), ); - let proof = db.prove_query(&path_query, None).unwrap().unwrap(); + let proof = db + .prove_query(&path_query, None, grove_version) + .unwrap() + .unwrap(); let (hash, result_set) = - GroveDb::verify_query_with_absence_proof(&proof, &path_query).unwrap(); - assert_eq!(hash, db.root_hash(None).unwrap().unwrap()); + GroveDb::verify_query_with_absence_proof(&proof, &path_query, grove_version).unwrap(); + assert_eq!(hash, db.root_hash(None, grove_version).unwrap().unwrap()); assert_eq!(result_set.len(), 4); assert_eq!( @@ -2411,7 +2681,8 @@ mod tests { #[test] fn test_subset_proof_verification() { - let db = make_deep_tree(); + let grove_version = GroveVersion::latest(); + let db = make_deep_tree(grove_version); // original path query let mut query = Query::new(); @@ -2422,9 +2693,12 @@ mod tests { let path_query = PathQuery::new_unsized(vec![TEST_LEAF.to_vec()], query); - let proof = db.prove_query(&path_query, None).unwrap().unwrap(); - let (hash, result_set) = GroveDb::verify_query(&proof, &path_query).unwrap(); - assert_eq!(hash, db.root_hash(None).unwrap().unwrap()); + let proof = db + .prove_query(&path_query, None, grove_version) + .unwrap() + .unwrap(); + let (hash, result_set) = GroveDb::verify_query(&proof, &path_query, grove_version).unwrap(); + assert_eq!(hash, db.root_hash(None, grove_version).unwrap().unwrap()); assert_eq!(result_set.len(), 5); assert_eq!( result_set[0], @@ -2475,8 +2749,9 @@ mod tests { query.set_subquery(subq); let subset_path_query = PathQuery::new_unsized(vec![TEST_LEAF.to_vec()], query); - let (hash, result_set) = GroveDb::verify_subset_query(&proof, &subset_path_query).unwrap(); - assert_eq!(hash, db.root_hash(None).unwrap().unwrap()); + let (hash, result_set) = + GroveDb::verify_subset_query(&proof, &subset_path_query, grove_version).unwrap(); + assert_eq!(hash, db.root_hash(None, grove_version).unwrap().unwrap()); assert_eq!(result_set.len(), 1); assert_eq!( result_set[0], @@ -2489,7 +2764,8 @@ mod tests { } #[test] fn test_chained_path_query_verification() { - let db = make_deep_tree(); + let grove_version = GroveVersion::latest(); + let db = make_deep_tree(grove_version); let mut query = Query::new(); query.insert_all(); @@ -2504,9 +2780,12 @@ mod tests { let path_query = PathQuery::new_unsized(vec![b"deep_leaf".to_vec()], query); // first prove non verbose - let proof = db.prove_query(&path_query, None).unwrap().unwrap(); - let (hash, result_set) = GroveDb::verify_query(&proof, &path_query).unwrap(); - assert_eq!(hash, db.root_hash(None).unwrap().unwrap()); + let proof = db + .prove_query(&path_query, None, grove_version) + .unwrap() + .unwrap(); + let (hash, result_set) = GroveDb::verify_query(&proof, &path_query, grove_version).unwrap(); + assert_eq!(hash, db.root_hash(None, grove_version).unwrap().unwrap()); assert_eq!(result_set.len(), 14); // init deeper_1 path query @@ -2544,9 +2823,13 @@ mod tests { &proof, &deeper_1_path_query, chained_path_queries, + grove_version, ) .unwrap(); - assert_eq!(root_hash, db.root_hash(None).unwrap().unwrap()); + assert_eq!( + root_hash, + db.root_hash(None, grove_version).unwrap().unwrap() + ); assert_eq!(results.len(), 2); assert_eq!(results[0].len(), 3); assert_eq!( @@ -2627,11 +2910,12 @@ mod tests { #[test] fn test_query_b_depends_on_query_a() { + let grove_version = GroveVersion::latest(); // we have two trees // one with a mapping of id to name // another with a mapping of name to age // we want to get the age of every one after a certain id ordered by name - let db = make_test_grovedb(); + let db = make_test_grovedb(grove_version); // TEST_LEAF contains the id to name mapping db.insert( @@ -2640,6 +2924,7 @@ mod tests { Element::new_item(b"d".to_vec()), None, None, + grove_version, ) .unwrap() .expect("successful root tree leaf insert"); @@ -2649,6 +2934,7 @@ mod tests { Element::new_item(b"b".to_vec()), None, None, + grove_version, ) .unwrap() .expect("successful root tree leaf insert"); @@ -2658,6 +2944,7 @@ mod tests { Element::new_item(b"c".to_vec()), None, None, + grove_version, ) .unwrap() .expect("successful root tree leaf insert"); @@ -2667,6 +2954,7 @@ mod tests { Element::new_item(b"a".to_vec()), None, None, + grove_version, ) .unwrap() .expect("successful root tree leaf insert"); @@ -2678,6 +2966,7 @@ mod tests { Element::new_item(vec![10]), None, None, + grove_version, ) .unwrap() .expect("successful root tree leaf insert"); @@ -2687,6 +2976,7 @@ mod tests { Element::new_item(vec![30]), None, None, + grove_version, ) .unwrap() .expect("successful root tree leaf insert"); @@ -2696,6 +2986,7 @@ mod tests { Element::new_item(vec![12]), None, None, + grove_version, ) .unwrap() .expect("successful root tree leaf insert"); @@ -2705,13 +2996,14 @@ mod tests { Element::new_item(vec![46]), None, None, + grove_version, ) .unwrap() .expect("successful root tree leaf insert"); // Query: return the age of everyone greater than id 2 ordered by name // id 2 - b - // so we want to return the age for c and d = 12, 46 respectively + // we want to return the age for c and d = 12, 46 respectively // the proof generator knows that id 2 = b, but the verifier doesn't // hence we need to generate two proofs // prove that 2 - b then prove age after b @@ -2724,9 +3016,13 @@ mod tests { let mut path_query_one = PathQuery::new_unsized(vec![TEST_LEAF.to_vec()], query); // first we show that this returns the correct output - let proof = db.prove_query(&path_query_one, None).unwrap().unwrap(); - let (hash, result_set) = GroveDb::verify_query(&proof, &path_query_one).unwrap(); - assert_eq!(hash, db.root_hash(None).unwrap().unwrap()); + let proof = db + .prove_query(&path_query_one, None, grove_version) + .unwrap() + .unwrap(); + let (hash, result_set) = + GroveDb::verify_query(&proof, &path_query_one, grove_version).unwrap(); + assert_eq!(hash, db.root_hash(None, grove_version).unwrap().unwrap()); assert_eq!(result_set.len(), 1); assert_eq!(result_set[0].2, Some(Element::new_item(b"b".to_vec()))); @@ -2736,18 +3032,25 @@ mod tests { let path_query_two = PathQuery::new_unsized(vec![ANOTHER_TEST_LEAF.to_vec()], query); // show that we get the correct output - let proof = db.prove_query(&path_query_two, None).unwrap().unwrap(); - let (hash, result_set) = GroveDb::verify_query(&proof, &path_query_two).unwrap(); - assert_eq!(hash, db.root_hash(None).unwrap().unwrap()); + let proof = db + .prove_query(&path_query_two, None, grove_version) + .unwrap() + .unwrap(); + let (hash, result_set) = + GroveDb::verify_query(&proof, &path_query_two, grove_version).unwrap(); + assert_eq!(hash, db.root_hash(None, grove_version).unwrap().unwrap()); assert_eq!(result_set.len(), 2); assert_eq!(result_set[0].2, Some(Element::new_item(vec![12]))); assert_eq!(result_set[1].2, Some(Element::new_item(vec![46]))); // now we merge the path queries let mut merged_path_queries = - PathQuery::merge(vec![&path_query_one, &path_query_two]).unwrap(); + PathQuery::merge(vec![&path_query_one, &path_query_two], grove_version).unwrap(); merged_path_queries.query.limit = Some(3); - let proof = db.prove_query(&merged_path_queries, None).unwrap().unwrap(); + let proof = db + .prove_query(&merged_path_queries, None, grove_version) + .unwrap() + .unwrap(); // verifier only has access to the statement age > 2 // need to first get the name associated with 2 from the proof @@ -2774,6 +3077,7 @@ mod tests { proof.as_slice(), &path_query_one, chained_path_queries, + grove_version, ) .unwrap(); assert_eq!(result_set.len(), 2); @@ -2787,9 +3091,10 @@ mod tests { #[test] fn test_prove_absent_path_with_intermediate_emtpy_tree() { + let grove_version = GroveVersion::latest(); // root // test_leaf (empty) - let grovedb = make_test_grovedb(); + let grovedb = make_test_grovedb(grove_version); // prove the absence of key "book" in ["test_leaf", "invalid"] let mut query = Query::new(); @@ -2798,13 +3103,17 @@ mod tests { PathQuery::new_unsized(vec![TEST_LEAF.to_vec(), b"invalid".to_vec()], query); let proof = grovedb - .prove_query(&path_query, None) + .prove_query(&path_query, None, grove_version) .unwrap() .expect("should generate proofs"); let (root_hash, result_set) = - GroveDb::verify_query(proof.as_slice(), &path_query).expect("should verify proof"); + GroveDb::verify_query(proof.as_slice(), &path_query, grove_version) + .expect("should verify proof"); assert_eq!(result_set.len(), 0); - assert_eq!(root_hash, grovedb.root_hash(None).unwrap().unwrap()); + assert_eq!( + root_hash, + grovedb.root_hash(None, grove_version).unwrap().unwrap() + ); } } diff --git a/grovedb/src/tests/sum_tree_tests.rs b/grovedb/src/tests/sum_tree_tests.rs index 8f28932f..92df7d73 100644 --- a/grovedb/src/tests/sum_tree_tests.rs +++ b/grovedb/src/tests/sum_tree_tests.rs @@ -6,6 +6,7 @@ use grovedb_merk::{ TreeFeatureType::{BasicMerkNode, SummedMerkNode}, }; use grovedb_storage::StorageBatch; +use grovedb_version::version::GroveVersion; use crate::{ batch::GroveDbOp, @@ -16,20 +17,22 @@ use crate::{ #[test] fn test_sum_tree_behaves_like_regular_tree() { - let db = make_test_grovedb(); + let grove_version = GroveVersion::latest(); + let db = make_test_grovedb(grove_version); db.insert( [TEST_LEAF].as_ref(), b"key", Element::empty_sum_tree(), None, None, + grove_version, ) .unwrap() .expect("should insert tree"); // Can fetch sum tree let sum_tree = db - .get([TEST_LEAF].as_ref(), b"key", None) + .get([TEST_LEAF].as_ref(), b"key", None, grove_version) .unwrap() .expect("should get tree"); assert!(matches!(sum_tree, Element::SumTree(..))); @@ -40,6 +43,7 @@ fn test_sum_tree_behaves_like_regular_tree() { Element::new_item(vec![1]), None, None, + grove_version, ) .unwrap() .expect("should insert item"); @@ -49,6 +53,7 @@ fn test_sum_tree_behaves_like_regular_tree() { Element::new_item(vec![3]), None, None, + grove_version, ) .unwrap() .expect("should insert item"); @@ -58,13 +63,19 @@ fn test_sum_tree_behaves_like_regular_tree() { Element::empty_tree(), None, None, + grove_version, ) .unwrap() .expect("should insert item"); // Test proper item retrieval let item = db - .get([TEST_LEAF, b"key"].as_ref(), b"innerkey", None) + .get( + [TEST_LEAF, b"key"].as_ref(), + b"innerkey", + None, + grove_version, + ) .unwrap() .expect("should get item"); assert_eq!(item, Element::new_item(vec![1])); @@ -75,28 +86,34 @@ fn test_sum_tree_behaves_like_regular_tree() { let path_query = PathQuery::new_unsized(vec![TEST_LEAF.to_vec(), b"key".to_vec()], query); let proof = db - .prove_query(&path_query, None) + .prove_query(&path_query, None, grove_version) .unwrap() .expect("should generate proof"); let (root_hash, result_set) = - GroveDb::verify_query_raw(&proof, &path_query).expect("should verify proof"); - assert_eq!(root_hash, db.grove_db.root_hash(None).unwrap().unwrap()); + GroveDb::verify_query_raw(&proof, &path_query, grove_version).expect("should verify proof"); + assert_eq!( + root_hash, + db.grove_db.root_hash(None, grove_version).unwrap().unwrap() + ); assert_eq!(result_set.len(), 1); assert_eq!( - Element::deserialize(&result_set[0].value).expect("should deserialize element"), + Element::deserialize(&result_set[0].value, grove_version) + .expect("should deserialize element"), Element::new_item(vec![3]) ); } #[test] fn test_sum_item_behaves_like_regular_item() { - let db = make_test_grovedb(); + let grove_version = GroveVersion::latest(); + let db = make_test_grovedb(grove_version); db.insert( [TEST_LEAF].as_ref(), b"sumkey", Element::empty_sum_tree(), None, None, + grove_version, ) .unwrap() .expect("should insert tree"); @@ -106,6 +123,7 @@ fn test_sum_item_behaves_like_regular_item() { Element::new_item(vec![1]), None, None, + grove_version, ) .unwrap() .expect("should insert tree"); @@ -115,6 +133,7 @@ fn test_sum_item_behaves_like_regular_item() { Element::new_sum_item(5), None, None, + grove_version, ) .unwrap() .expect("should insert tree"); @@ -124,13 +143,14 @@ fn test_sum_item_behaves_like_regular_item() { Element::empty_tree(), None, None, + grove_version, ) .unwrap() .expect("should insert tree"); // Test proper item retrieval let item = db - .get([TEST_LEAF, b"sumkey"].as_ref(), b"k2", None) + .get([TEST_LEAF, b"sumkey"].as_ref(), b"k2", None, grove_version) .unwrap() .expect("should get item"); assert_eq!(item, Element::new_sum_item(5)); @@ -141,28 +161,33 @@ fn test_sum_item_behaves_like_regular_item() { let path_query = PathQuery::new_unsized(vec![TEST_LEAF.to_vec(), b"sumkey".to_vec()], query); let proof = db - .prove_query(&path_query, None) + .prove_query(&path_query, None, grove_version) .unwrap() .expect("should generate proof"); let (root_hash, result_set) = - GroveDb::verify_query_raw(&proof, &path_query).expect("should verify proof"); - assert_eq!(root_hash, db.grove_db.root_hash(None).unwrap().unwrap()); + GroveDb::verify_query_raw(&proof, &path_query, grove_version).expect("should verify proof"); + assert_eq!( + root_hash, + db.grove_db.root_hash(None, grove_version).unwrap().unwrap() + ); assert_eq!(result_set.len(), 1); - let element_from_proof = - Element::deserialize(&result_set[0].value).expect("should deserialize element"); + let element_from_proof = Element::deserialize(&result_set[0].value, grove_version) + .expect("should deserialize element"); assert_eq!(element_from_proof, Element::new_sum_item(5)); assert_eq!(element_from_proof.sum_value_or_default(), 5); } #[test] fn test_cannot_insert_sum_item_in_regular_tree() { - let db = make_test_grovedb(); + let grove_version = GroveVersion::latest(); + let db = make_test_grovedb(grove_version); db.insert( [TEST_LEAF].as_ref(), b"sumkey", Element::empty_tree(), None, None, + grove_version, ) .unwrap() .expect("should insert tree"); @@ -173,6 +198,7 @@ fn test_cannot_insert_sum_item_in_regular_tree() { Element::new_sum_item(5), None, None, + grove_version ) .unwrap(), Err(Error::InvalidInput("cannot add sum item to non sum tree")) @@ -181,14 +207,16 @@ fn test_cannot_insert_sum_item_in_regular_tree() { #[test] fn test_homogenous_node_type_in_sum_trees_and_regular_trees() { + let grove_version = GroveVersion::latest(); // All elements in a sum tree must have a summed feature type - let db = make_test_grovedb(); + let db = make_test_grovedb(grove_version); db.insert( [TEST_LEAF].as_ref(), b"key", Element::empty_sum_tree(), None, None, + grove_version, ) .unwrap() .expect("should insert tree"); @@ -199,6 +227,7 @@ fn test_homogenous_node_type_in_sum_trees_and_regular_trees() { Element::new_sum_item(30), None, None, + grove_version, ) .unwrap() .expect("should insert item"); @@ -208,6 +237,7 @@ fn test_homogenous_node_type_in_sum_trees_and_regular_trees() { Element::new_sum_item(10), None, None, + grove_version, ) .unwrap() .expect("should insert item"); @@ -218,6 +248,7 @@ fn test_homogenous_node_type_in_sum_trees_and_regular_trees() { Element::new_item(vec![10]), None, None, + grove_version, ) .unwrap() .expect("should insert item"); @@ -227,6 +258,7 @@ fn test_homogenous_node_type_in_sum_trees_and_regular_trees() { Element::new_item(vec![15]), None, None, + grove_version, ) .unwrap() .expect("should insert item"); @@ -235,14 +267,19 @@ fn test_homogenous_node_type_in_sum_trees_and_regular_trees() { // Open merk and check all elements in it let merk = db - .open_non_transactional_merk_at_path([TEST_LEAF, b"key"].as_ref().into(), Some(&batch)) + .open_non_transactional_merk_at_path( + [TEST_LEAF, b"key"].as_ref().into(), + Some(&batch), + grove_version, + ) .unwrap() .expect("should open tree"); assert!(matches!( merk.get_feature_type( b"item1", true, - None::<&fn(&[u8]) -> Option> + None::<&fn(&[u8], &GroveVersion) -> Option>, + grove_version ) .unwrap() .expect("node should exist"), @@ -252,7 +289,8 @@ fn test_homogenous_node_type_in_sum_trees_and_regular_trees() { merk.get_feature_type( b"item2", true, - None::<&fn(&[u8]) -> Option> + None::<&fn(&[u8], &GroveVersion) -> Option>, + grove_version ) .unwrap() .expect("node should exist"), @@ -262,7 +300,8 @@ fn test_homogenous_node_type_in_sum_trees_and_regular_trees() { merk.get_feature_type( b"item3", true, - None::<&fn(&[u8]) -> Option> + None::<&fn(&[u8], &GroveVersion) -> Option>, + grove_version ) .unwrap() .expect("node should exist"), @@ -272,7 +311,8 @@ fn test_homogenous_node_type_in_sum_trees_and_regular_trees() { merk.get_feature_type( b"item4", true, - None::<&fn(&[u8]) -> Option> + None::<&fn(&[u8], &GroveVersion) -> Option>, + grove_version ) .unwrap() .expect("node should exist"), @@ -281,13 +321,14 @@ fn test_homogenous_node_type_in_sum_trees_and_regular_trees() { assert_eq!(merk.sum().expect("expected to get sum"), Some(40)); // Perform the same test on regular trees - let db = make_test_grovedb(); + let db = make_test_grovedb(grove_version); db.insert( [TEST_LEAF].as_ref(), b"key", Element::empty_tree(), None, None, + grove_version, ) .unwrap() .expect("should insert tree"); @@ -297,6 +338,7 @@ fn test_homogenous_node_type_in_sum_trees_and_regular_trees() { Element::new_item(vec![30]), None, None, + grove_version, ) .unwrap() .expect("should insert item"); @@ -306,19 +348,25 @@ fn test_homogenous_node_type_in_sum_trees_and_regular_trees() { Element::new_item(vec![10]), None, None, + grove_version, ) .unwrap() .expect("should insert item"); let merk = db - .open_non_transactional_merk_at_path([TEST_LEAF, b"key"].as_ref().into(), Some(&batch)) + .open_non_transactional_merk_at_path( + [TEST_LEAF, b"key"].as_ref().into(), + Some(&batch), + grove_version, + ) .unwrap() .expect("should open tree"); assert!(matches!( merk.get_feature_type( b"item1", true, - Some(&Element::value_defined_cost_for_serialized_value) + Some(&Element::value_defined_cost_for_serialized_value), + grove_version ) .unwrap() .expect("node should exist"), @@ -328,7 +376,8 @@ fn test_homogenous_node_type_in_sum_trees_and_regular_trees() { merk.get_feature_type( b"item2", true, - Some(&Element::value_defined_cost_for_serialized_value) + Some(&Element::value_defined_cost_for_serialized_value), + grove_version ) .unwrap() .expect("node should exist"), @@ -339,13 +388,15 @@ fn test_homogenous_node_type_in_sum_trees_and_regular_trees() { #[test] fn test_sum_tree_feature() { - let db = make_test_grovedb(); + let grove_version = GroveVersion::latest(); + let db = make_test_grovedb(grove_version); db.insert( [TEST_LEAF].as_ref(), b"key", Element::empty_tree(), None, None, + grove_version, ) .unwrap() .expect("should insert tree"); @@ -355,7 +406,11 @@ fn test_sum_tree_feature() { // Sum should be non for non sum tree // TODO: change interface to retrieve element directly let merk = db - .open_non_transactional_merk_at_path([TEST_LEAF, b"key"].as_ref().into(), Some(&batch)) + .open_non_transactional_merk_at_path( + [TEST_LEAF, b"key"].as_ref().into(), + Some(&batch), + grove_version, + ) .unwrap() .expect("should open tree"); assert_eq!(merk.sum().expect("expected to get sum"), None); @@ -367,11 +422,12 @@ fn test_sum_tree_feature() { Element::empty_sum_tree(), None, None, + grove_version, ) .unwrap() .expect("should insert sum tree"); let sum_tree = db - .get([TEST_LEAF].as_ref(), b"key2", None) + .get([TEST_LEAF].as_ref(), b"key2", None, grove_version) .unwrap() .expect("should retrieve tree"); assert_eq!(sum_tree.sum_value_or_default(), 0); @@ -383,12 +439,17 @@ fn test_sum_tree_feature() { Element::new_sum_item(30), None, None, + grove_version, ) .unwrap() .expect("should insert item"); // TODO: change interface to retrieve element directly let merk = db - .open_non_transactional_merk_at_path([TEST_LEAF, b"key2"].as_ref().into(), Some(&batch)) + .open_non_transactional_merk_at_path( + [TEST_LEAF, b"key2"].as_ref().into(), + Some(&batch), + grove_version, + ) .unwrap() .expect("should open tree"); assert_eq!(merk.sum().expect("expected to get sum"), Some(30)); @@ -400,6 +461,7 @@ fn test_sum_tree_feature() { Element::new_sum_item(-10), None, None, + grove_version, ) .unwrap() .expect("should insert item"); @@ -409,11 +471,16 @@ fn test_sum_tree_feature() { Element::new_sum_item(50), None, None, + grove_version, ) .unwrap() .expect("should insert item"); let merk = db - .open_non_transactional_merk_at_path([TEST_LEAF, b"key2"].as_ref().into(), Some(&batch)) + .open_non_transactional_merk_at_path( + [TEST_LEAF, b"key2"].as_ref().into(), + Some(&batch), + grove_version, + ) .unwrap() .expect("should open tree"); assert_eq!(merk.sum().expect("expected to get sum"), Some(70)); // 30 - 10 + 50 = 70 @@ -425,11 +492,16 @@ fn test_sum_tree_feature() { Element::new_item(vec![29]), None, None, + grove_version, ) .unwrap() .expect("should insert item"); let merk = db - .open_non_transactional_merk_at_path([TEST_LEAF, b"key2"].as_ref().into(), Some(&batch)) + .open_non_transactional_merk_at_path( + [TEST_LEAF, b"key2"].as_ref().into(), + Some(&batch), + grove_version, + ) .unwrap() .expect("should open tree"); assert_eq!(merk.sum().expect("expected to get sum"), Some(70)); @@ -441,6 +513,7 @@ fn test_sum_tree_feature() { Element::new_sum_item(10), None, None, + grove_version, ) .unwrap() .expect("should insert item"); @@ -450,19 +523,30 @@ fn test_sum_tree_feature() { Element::new_sum_item(-100), None, None, + grove_version, ) .unwrap() .expect("should insert item"); let merk = db - .open_non_transactional_merk_at_path([TEST_LEAF, b"key2"].as_ref().into(), Some(&batch)) + .open_non_transactional_merk_at_path( + [TEST_LEAF, b"key2"].as_ref().into(), + Some(&batch), + grove_version, + ) .unwrap() .expect("should open tree"); assert_eq!(merk.sum().expect("expected to get sum"), Some(-60)); // 30 + 10 - 100 = -60 // We can not replace a normal item with a sum item, so let's delete it first - db.delete([TEST_LEAF, b"key2"].as_ref(), b"item4", None, None) - .unwrap() - .expect("expected to delete"); + db.delete( + [TEST_LEAF, b"key2"].as_ref(), + b"item4", + None, + None, + grove_version, + ) + .unwrap() + .expect("expected to delete"); // Use a large value db.insert( [TEST_LEAF, b"key2"].as_ref(), @@ -470,11 +554,16 @@ fn test_sum_tree_feature() { Element::new_sum_item(10000000), None, None, + grove_version, ) .unwrap() .expect("should insert item"); let merk = db - .open_non_transactional_merk_at_path([TEST_LEAF, b"key2"].as_ref().into(), Some(&batch)) + .open_non_transactional_merk_at_path( + [TEST_LEAF, b"key2"].as_ref().into(), + Some(&batch), + grove_version, + ) .unwrap() .expect("should open tree"); assert_eq!(merk.sum().expect("expected to get sum"), Some(9999940)); // 30 + @@ -487,7 +576,8 @@ fn test_sum_tree_feature() { #[test] fn test_sum_tree_propagation() { - let db = make_test_grovedb(); + let grove_version = GroveVersion::latest(); + let db = make_test_grovedb(grove_version); // Tree // SumTree // SumTree @@ -501,6 +591,7 @@ fn test_sum_tree_propagation() { Element::empty_sum_tree(), None, None, + grove_version, ) .unwrap() .expect("should insert tree"); @@ -510,6 +601,7 @@ fn test_sum_tree_propagation() { Element::empty_sum_tree(), None, None, + grove_version, ) .unwrap() .expect("should insert tree"); @@ -519,6 +611,7 @@ fn test_sum_tree_propagation() { Element::new_sum_item(20), None, None, + grove_version, ) .unwrap() .expect("should insert tree"); @@ -528,6 +621,7 @@ fn test_sum_tree_propagation() { Element::new_item(vec![2]), None, None, + grove_version, ) .unwrap() .expect("should insert item"); @@ -537,6 +631,7 @@ fn test_sum_tree_propagation() { Element::new_sum_item(5), None, None, + grove_version, ) .unwrap() .expect("should insert item"); @@ -546,6 +641,7 @@ fn test_sum_tree_propagation() { Element::new_sum_item(10), None, None, + grove_version, ) .unwrap() .expect("should insert item"); @@ -560,12 +656,13 @@ fn test_sum_tree_propagation() { ])), None, None, + grove_version, ) .unwrap() .expect("should insert item"); let sum_tree = db - .get([TEST_LEAF].as_ref(), b"key", None) + .get([TEST_LEAF].as_ref(), b"key", None, grove_version) .unwrap() .expect("should fetch tree"); assert_eq!(sum_tree.sum_value_or_default(), 35); @@ -574,7 +671,11 @@ fn test_sum_tree_propagation() { // Assert node feature types let test_leaf_merk = db - .open_non_transactional_merk_at_path([TEST_LEAF].as_ref().into(), Some(&batch)) + .open_non_transactional_merk_at_path( + [TEST_LEAF].as_ref().into(), + Some(&batch), + grove_version, + ) .unwrap() .expect("should open tree"); assert!(matches!( @@ -582,7 +683,8 @@ fn test_sum_tree_propagation() { .get_feature_type( b"key", true, - Some(&Element::value_defined_cost_for_serialized_value) + Some(&Element::value_defined_cost_for_serialized_value), + grove_version ) .unwrap() .expect("node should exist"), @@ -590,7 +692,11 @@ fn test_sum_tree_propagation() { )); let parent_sum_tree = db - .open_non_transactional_merk_at_path([TEST_LEAF, b"key"].as_ref().into(), Some(&batch)) + .open_non_transactional_merk_at_path( + [TEST_LEAF, b"key"].as_ref().into(), + Some(&batch), + grove_version, + ) .unwrap() .expect("should open tree"); assert!(matches!( @@ -598,7 +704,8 @@ fn test_sum_tree_propagation() { .get_feature_type( b"tree2", true, - Some(&Element::value_defined_cost_for_serialized_value) + Some(&Element::value_defined_cost_for_serialized_value), + grove_version ) .unwrap() .expect("node should exist"), @@ -611,6 +718,7 @@ fn test_sum_tree_propagation() { .open_non_transactional_merk_at_path( [TEST_LEAF, b"key", b"tree2"].as_ref().into(), Some(&batch), + grove_version, ) .unwrap() .expect("should open tree"); @@ -619,7 +727,8 @@ fn test_sum_tree_propagation() { .get_feature_type( b"item1", true, - None::<&fn(&[u8]) -> Option> + None::<&fn(&[u8], &GroveVersion) -> Option>, + grove_version ) .unwrap() .expect("node should exist"), @@ -630,7 +739,8 @@ fn test_sum_tree_propagation() { .get_feature_type( b"sumitem1", true, - None::<&fn(&[u8]) -> Option> + None::<&fn(&[u8], &GroveVersion) -> Option>, + grove_version ) .unwrap() .expect("node should exist"), @@ -641,7 +751,8 @@ fn test_sum_tree_propagation() { .get_feature_type( b"sumitem2", true, - None::<&fn(&[u8]) -> Option> + None::<&fn(&[u8], &GroveVersion) -> Option>, + grove_version ) .unwrap() .expect("node should exist"), @@ -654,7 +765,8 @@ fn test_sum_tree_propagation() { .get_feature_type( b"item2", true, - None::<&fn(&[u8]) -> Option> + None::<&fn(&[u8], &GroveVersion) -> Option>, + grove_version ) .unwrap() .expect("node should exist"), @@ -664,7 +776,8 @@ fn test_sum_tree_propagation() { #[test] fn test_sum_tree_with_batches() { - let db = make_test_grovedb(); + let grove_version = GroveVersion::latest(); + let db = make_test_grovedb(grove_version); let ops = vec![ GroveDbOp::insert_op( vec![TEST_LEAF.to_vec()], @@ -682,13 +795,17 @@ fn test_sum_tree_with_batches() { Element::new_sum_item(10), ), ]; - db.apply_batch(ops, None, None) + db.apply_batch(ops, None, None, grove_version) .unwrap() .expect("should apply batch"); let batch = StorageBatch::new(); let sum_tree = db - .open_non_transactional_merk_at_path([TEST_LEAF, b"key1"].as_ref().into(), Some(&batch)) + .open_non_transactional_merk_at_path( + [TEST_LEAF, b"key1"].as_ref().into(), + Some(&batch), + grove_version, + ) .unwrap() .expect("should open tree"); @@ -697,7 +814,8 @@ fn test_sum_tree_with_batches() { .get_feature_type( b"a", true, - Some(&Element::value_defined_cost_for_serialized_value) + Some(&Element::value_defined_cost_for_serialized_value), + grove_version ) .unwrap() .expect("node should exist"), @@ -708,7 +826,8 @@ fn test_sum_tree_with_batches() { .get_feature_type( b"b", true, - Some(&Element::value_defined_cost_for_serialized_value) + Some(&Element::value_defined_cost_for_serialized_value), + grove_version ) .unwrap() .expect("node should exist"), @@ -721,13 +840,17 @@ fn test_sum_tree_with_batches() { b"c".to_vec(), Element::new_sum_item(10), )]; - db.apply_batch(ops, None, None) + db.apply_batch(ops, None, None, grove_version) .unwrap() .expect("should apply batch"); let batch = StorageBatch::new(); let sum_tree = db - .open_non_transactional_merk_at_path([TEST_LEAF, b"key1"].as_ref().into(), Some(&batch)) + .open_non_transactional_merk_at_path( + [TEST_LEAF, b"key1"].as_ref().into(), + Some(&batch), + grove_version, + ) .unwrap() .expect("should open tree"); assert!(matches!( @@ -735,7 +858,8 @@ fn test_sum_tree_with_batches() { .get_feature_type( b"c", true, - None::<&fn(&[u8]) -> Option> + None::<&fn(&[u8], &GroveVersion) -> Option>, + grove_version ) .unwrap() .expect("node should exist"), @@ -744,7 +868,7 @@ fn test_sum_tree_with_batches() { assert_eq!(sum_tree.sum().expect("expected to get sum"), Some(20)); // Test propagation - // Add a new sum tree with it's own sum items, should affect sum of original + // Add a new sum tree with its own sum items, should affect sum of original // tree let ops = vec![ GroveDbOp::insert_op( @@ -803,13 +927,17 @@ fn test_sum_tree_with_batches() { Element::new_item(vec![5]), ), ]; - db.apply_batch(ops, None, None) + db.apply_batch(ops, None, None, grove_version) .unwrap() .expect("should apply batch"); let batch = StorageBatch::new(); let sum_tree = db - .open_non_transactional_merk_at_path([TEST_LEAF, b"key1"].as_ref().into(), Some(&batch)) + .open_non_transactional_merk_at_path( + [TEST_LEAF, b"key1"].as_ref().into(), + Some(&batch), + grove_version, + ) .unwrap() .expect("should open tree"); assert_eq!(sum_tree.sum().expect("expected to get sum"), Some(41)); diff --git a/grovedb/src/tests/tree_hashes_tests.rs b/grovedb/src/tests/tree_hashes_tests.rs index d2418132..e86b8fd0 100644 --- a/grovedb/src/tests/tree_hashes_tests.rs +++ b/grovedb/src/tests/tree_hashes_tests.rs @@ -32,6 +32,7 @@ use grovedb_merk::tree::{ combine_hash, kv::ValueDefinedCostType, kv_digest_to_kv_hash, node_hash, value_hash, NULL_HASH, }; use grovedb_storage::StorageBatch; +use grovedb_version::version::GroveVersion; use crate::{ tests::{make_test_grovedb, TEST_LEAF}, @@ -40,7 +41,8 @@ use crate::{ #[test] fn test_node_hashes_when_inserting_item() { - let db = make_test_grovedb(); + let grove_version = GroveVersion::latest(); + let db = make_test_grovedb(grove_version); db.insert( [TEST_LEAF].as_ref(), @@ -48,6 +50,7 @@ fn test_node_hashes_when_inserting_item() { Element::new_item(b"baguette".to_vec()), None, None, + grove_version, ) .unwrap() .expect("successful subtree insert"); @@ -55,7 +58,11 @@ fn test_node_hashes_when_inserting_item() { let batch = StorageBatch::new(); let test_leaf_merk = db - .open_non_transactional_merk_at_path([TEST_LEAF].as_ref().into(), Some(&batch)) + .open_non_transactional_merk_at_path( + [TEST_LEAF].as_ref().into(), + Some(&batch), + grove_version, + ) .unwrap() .expect("should open merk"); @@ -63,7 +70,8 @@ fn test_node_hashes_when_inserting_item() { .get_value_and_value_hash( b"key1", true, - None::<&fn(&[u8]) -> Option>, + None::<&fn(&[u8], &GroveVersion) -> Option>, + grove_version, ) .unwrap() .expect("should get value hash") @@ -73,7 +81,8 @@ fn test_node_hashes_when_inserting_item() { .get_kv_hash( b"key1", true, - None::<&fn(&[u8]) -> Option>, + None::<&fn(&[u8], &GroveVersion) -> Option>, + grove_version, ) .unwrap() .expect("should get value hash") @@ -83,7 +92,8 @@ fn test_node_hashes_when_inserting_item() { .get_hash( b"key1", true, - None::<&fn(&[u8]) -> Option>, + None::<&fn(&[u8], &GroveVersion) -> Option>, + grove_version, ) .unwrap() .expect("should get value hash") @@ -104,7 +114,8 @@ fn test_node_hashes_when_inserting_item() { #[test] fn test_tree_hashes_when_inserting_empty_tree() { - let db = make_test_grovedb(); + let grove_version = GroveVersion::latest(); + let db = make_test_grovedb(grove_version); db.insert( [TEST_LEAF].as_ref(), @@ -112,6 +123,7 @@ fn test_tree_hashes_when_inserting_empty_tree() { Element::empty_tree(), None, None, + grove_version, ) .unwrap() .expect("successful subtree insert"); @@ -119,7 +131,11 @@ fn test_tree_hashes_when_inserting_empty_tree() { let batch = StorageBatch::new(); let test_leaf_merk = db - .open_non_transactional_merk_at_path([TEST_LEAF].as_ref().into(), Some(&batch)) + .open_non_transactional_merk_at_path( + [TEST_LEAF].as_ref().into(), + Some(&batch), + grove_version, + ) .unwrap() .expect("should open merk"); @@ -127,7 +143,8 @@ fn test_tree_hashes_when_inserting_empty_tree() { .get_value_and_value_hash( b"key1", true, - None::<&fn(&[u8]) -> Option>, + None::<&fn(&[u8], &GroveVersion) -> Option>, + grove_version, ) .unwrap() .expect("should get value hash") @@ -137,7 +154,8 @@ fn test_tree_hashes_when_inserting_empty_tree() { .get_kv_hash( b"key1", true, - None::<&fn(&[u8]) -> Option>, + None::<&fn(&[u8], &GroveVersion) -> Option>, + grove_version, ) .unwrap() .expect("should get value hash") @@ -147,14 +165,19 @@ fn test_tree_hashes_when_inserting_empty_tree() { .get_hash( b"key1", true, - None::<&fn(&[u8]) -> Option>, + None::<&fn(&[u8], &GroveVersion) -> Option>, + grove_version, ) .unwrap() .expect("should get value hash") .expect("value hash should be some"); let underlying_merk = db - .open_non_transactional_merk_at_path([TEST_LEAF, b"key1"].as_ref().into(), Some(&batch)) + .open_non_transactional_merk_at_path( + [TEST_LEAF, b"key1"].as_ref().into(), + Some(&batch), + grove_version, + ) .unwrap() .expect("should open merk"); @@ -176,7 +199,8 @@ fn test_tree_hashes_when_inserting_empty_tree() { #[test] fn test_tree_hashes_when_inserting_empty_trees_twice_under_each_other() { - let db = make_test_grovedb(); + let grove_version = GroveVersion::latest(); + let db = make_test_grovedb(grove_version); db.insert( [TEST_LEAF].as_ref(), @@ -184,6 +208,7 @@ fn test_tree_hashes_when_inserting_empty_trees_twice_under_each_other() { Element::empty_tree(), None, None, + grove_version, ) .unwrap() .expect("successful subtree insert"); @@ -194,6 +219,7 @@ fn test_tree_hashes_when_inserting_empty_trees_twice_under_each_other() { Element::empty_tree(), None, None, + grove_version, ) .unwrap() .expect("successful subtree insert"); @@ -201,12 +227,20 @@ fn test_tree_hashes_when_inserting_empty_trees_twice_under_each_other() { let batch = StorageBatch::new(); let under_top_merk = db - .open_non_transactional_merk_at_path([TEST_LEAF].as_ref().into(), Some(&batch)) + .open_non_transactional_merk_at_path( + [TEST_LEAF].as_ref().into(), + Some(&batch), + grove_version, + ) .unwrap() .expect("should open merk"); let middle_merk_key1 = db - .open_non_transactional_merk_at_path([TEST_LEAF, b"key1"].as_ref().into(), Some(&batch)) + .open_non_transactional_merk_at_path( + [TEST_LEAF, b"key1"].as_ref().into(), + Some(&batch), + grove_version, + ) .unwrap() .expect("should open merk"); @@ -216,7 +250,8 @@ fn test_tree_hashes_when_inserting_empty_trees_twice_under_each_other() { .get_value_and_value_hash( b"key2", true, - None::<&fn(&[u8]) -> Option>, + None::<&fn(&[u8], &GroveVersion) -> Option>, + grove_version, ) .unwrap() .expect("should get value hash") @@ -226,6 +261,7 @@ fn test_tree_hashes_when_inserting_empty_trees_twice_under_each_other() { .open_non_transactional_merk_at_path( [TEST_LEAF, b"key1", b"key2"].as_ref().into(), Some(&batch), + grove_version, ) .unwrap() .expect("should open merk"); @@ -243,7 +279,8 @@ fn test_tree_hashes_when_inserting_empty_trees_twice_under_each_other() { .get_kv_hash( b"key2", true, - None::<&fn(&[u8]) -> Option>, + None::<&fn(&[u8], &GroveVersion) -> Option>, + grove_version, ) .unwrap() .expect("should get kv hash") @@ -257,7 +294,8 @@ fn test_tree_hashes_when_inserting_empty_trees_twice_under_each_other() { .get_hash( b"key2", true, - None::<&fn(&[u8]) -> Option>, + None::<&fn(&[u8], &GroveVersion) -> Option>, + grove_version, ) .unwrap() .expect("should get kv hash") @@ -279,7 +317,8 @@ fn test_tree_hashes_when_inserting_empty_trees_twice_under_each_other() { .get_value_and_value_hash( b"key1", true, - None::<&fn(&[u8]) -> Option>, + None::<&fn(&[u8], &GroveVersion) -> Option>, + grove_version, ) .unwrap() .expect("should get value hash") @@ -290,7 +329,7 @@ fn test_tree_hashes_when_inserting_empty_trees_twice_under_each_other() { "0201046b65793200" ); - let element = Element::deserialize(middle_elem_value_key1.as_slice()) + let element = Element::deserialize(middle_elem_value_key1.as_slice(), grove_version) .expect("expected to deserialize element"); assert_eq!(element, Element::new_tree(Some(b"key2".to_vec()))); @@ -321,7 +360,8 @@ fn test_tree_hashes_when_inserting_empty_trees_twice_under_each_other() { .get_kv_hash( b"key1", true, - None::<&fn(&[u8]) -> Option>, + None::<&fn(&[u8], &GroveVersion) -> Option>, + grove_version, ) .unwrap() .expect("should get value hash") @@ -339,7 +379,8 @@ fn test_tree_hashes_when_inserting_empty_trees_twice_under_each_other() { .get_hash( b"key1", true, - None::<&fn(&[u8]) -> Option>, + None::<&fn(&[u8], &GroveVersion) -> Option>, + grove_version, ) .unwrap() .expect("should get value hash") diff --git a/grovedb/src/util.rs b/grovedb/src/util.rs index d05f2396..b9b624a4 100644 --- a/grovedb/src/util.rs +++ b/grovedb/src/util.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. - /// Macro to execute same piece of code on different storage contexts /// (transactional or not) using path argument. macro_rules! storage_context_optional_tx { @@ -57,6 +29,7 @@ macro_rules! storage_context_with_parent_optional_tx { $storage:ident, $root_key:ident, $is_sum_tree:ident, + $grove_version:ident, { $($body:tt)* } ) => { { @@ -71,12 +44,13 @@ macro_rules! storage_context_with_parent_optional_tx { .unwrap_add_cost(&mut $cost); let element = cost_return_on_error!( &mut $cost, - Element::get_from_storage(&parent_storage, parent_key).map_err(|e| { + Element::get_from_storage(&parent_storage, parent_key, $grove_version) + .map_err(|e| { Error::PathParentLayerNotFound( format!( - "could not get key for parent of subtree optional on tx: {}", - e - ) + "could not get key for parent of subtree optional on tx: {}", + e + ) ) }) ); @@ -112,7 +86,7 @@ macro_rules! storage_context_with_parent_optional_tx { ).unwrap_add_cost(&mut $cost); let element = cost_return_on_error!( &mut $cost, - Element::get_from_storage(&parent_storage, parent_key).map_err(|e| { + Element::get_from_storage(&parent_storage, parent_key, $grove_version).map_err(|e| { Error::PathParentLayerNotFound( format!( "could not get key for parent of subtree optional no tx: {}", @@ -161,6 +135,7 @@ macro_rules! storage_context_with_parent_optional_tx_internal_error { $storage:ident, $root_key:ident, $is_sum_tree:ident, + $grove_version:ident, { $($body:tt)* } ) => { { @@ -173,8 +148,11 @@ macro_rules! storage_context_with_parent_optional_tx_internal_error { let parent_storage = $db .get_transactional_storage_context(parent_path, $batch, tx) .unwrap_add_cost(&mut $cost); - let result = Element::get_from_storage(&parent_storage, parent_key) - .map_err(|e| { + let result = Element::get_from_storage( + &parent_storage, + parent_key, + $grove_version + ).map_err(|e| { Error::PathParentLayerNotFound( format!( "could not get key for parent of subtree optional on tx: {}", @@ -218,8 +196,11 @@ macro_rules! storage_context_with_parent_optional_tx_internal_error { parent_path, $batch ).unwrap_add_cost(&mut $cost); - let result = Element::get_from_storage(&parent_storage, parent_key) - .map_err(|e| { + let result = Element::get_from_storage( + &parent_storage, + parent_key, + $grove_version + ).map_err(|e| { Error::PathParentLayerNotFound( format!( "could not get key for parent of subtree optional no tx: {}", @@ -296,6 +277,7 @@ macro_rules! merk_optional_tx { $batch:expr, $transaction:ident, $subtree:ident, + $grove_version:ident, { $($body:tt)* } ) => { if $path.is_root() { @@ -312,7 +294,8 @@ macro_rules! merk_optional_tx { ::grovedb_merk::Merk::open_base( storage.unwrap_add_cost(&mut $cost), false, - Some(&Element::value_defined_cost_for_serialized_value) + Some(&Element::value_defined_cost_for_serialized_value), + $grove_version, ).map(|merk_res| merk_res .map_err(|_| crate::Error::CorruptedData( @@ -333,6 +316,7 @@ macro_rules! merk_optional_tx { storage, root_key, is_sum_tree, + $grove_version, { #[allow(unused_mut)] let mut $subtree = cost_return_on_error!( @@ -342,6 +326,7 @@ macro_rules! merk_optional_tx { root_key, is_sum_tree, Some(&Element::value_defined_cost_for_serialized_value), + $grove_version, ).map(|merk_res| merk_res .map_err(|_| crate::Error::CorruptedData( @@ -366,6 +351,7 @@ macro_rules! merk_optional_tx_internal_error { $batch:expr, $transaction:ident, $subtree:ident, + $grove_version:ident, { $($body:tt)* } ) => { if $path.is_root() { @@ -382,7 +368,8 @@ macro_rules! merk_optional_tx_internal_error { ::grovedb_merk::Merk::open_base( storage.unwrap_add_cost(&mut $cost), false, - Some(&Element::value_defined_cost_for_serialized_value) + Some(&Element::value_defined_cost_for_serialized_value), + $grove_version ).map(|merk_res| merk_res .map_err(|_| crate::Error::CorruptedData( @@ -403,6 +390,7 @@ macro_rules! merk_optional_tx_internal_error { storage, root_key, is_sum_tree, + $grove_version, { #[allow(unused_mut)] let mut $subtree = cost_return_on_error!( @@ -412,6 +400,7 @@ macro_rules! merk_optional_tx_internal_error { root_key, is_sum_tree, Some(&Element::value_defined_cost_for_serialized_value), + $grove_version, ).map(|merk_res| merk_res .map_err(|_| crate::Error::CorruptedData( @@ -436,6 +425,7 @@ macro_rules! merk_optional_tx_path_not_empty { $batch:expr, $transaction:ident, $subtree:ident, + $grove_version:ident, { $($body:tt)* } ) => { { @@ -449,6 +439,7 @@ macro_rules! merk_optional_tx_path_not_empty { storage, root_key, is_sum_tree, + $grove_version, { #[allow(unused_mut)] let mut $subtree = cost_return_on_error!( @@ -458,6 +449,7 @@ macro_rules! merk_optional_tx_path_not_empty { root_key, is_sum_tree, Some(&Element::value_defined_cost_for_serialized_value), + $grove_version, ).map(|merk_res| merk_res .map_err(|_| crate::Error::CorruptedData( @@ -481,6 +473,7 @@ macro_rules! root_merk_optional_tx { $batch:expr, $transaction:ident, $subtree:ident, + $grove_version:ident, { $($body:tt)* } ) => { { @@ -497,7 +490,8 @@ macro_rules! root_merk_optional_tx { ::grovedb_merk::Merk::open_base( storage.unwrap_add_cost(&mut $cost), false, - Some(&Element::value_defined_cost_for_serialized_value) + Some(&Element::value_defined_cost_for_serialized_value), + $grove_version, ).map(|merk_res| merk_res .map_err(|_| crate::Error::CorruptedData( diff --git a/grovedb/src/visualize.rs b/grovedb/src/visualize.rs index 9eb1c00b..39cf3432 100644 --- a/grovedb/src/visualize.rs +++ b/grovedb/src/visualize.rs @@ -37,6 +37,7 @@ use bincode::{ use grovedb_merk::{Merk, VisualizeableMerk}; use grovedb_path::SubtreePathBuilder; use grovedb_storage::StorageContext; +use grovedb_version::version::GroveVersion; use grovedb_visualize::{visualize_stdout, Drawer, Visualize}; use crate::{ @@ -187,13 +188,14 @@ impl GroveDb { mut drawer: Drawer, path: SubtreePathBuilder<'_, B>, transaction: TransactionArg, + grove_version: &GroveVersion, ) -> Result> { drawer.down(); storage_context_optional_tx!(self.db, (&path).into(), None, transaction, storage, { let mut iter = Element::iterator(storage.unwrap().raw_iter()).unwrap(); while let Some((key, element)) = iter - .next_element() + .next_element(grove_version) .unwrap() .expect("cannot get next element") { @@ -209,6 +211,7 @@ impl GroveDb { drawer, path.derive_owned_with_child(key), transaction, + grove_version, )?; drawer.up(); } @@ -227,10 +230,16 @@ impl GroveDb { &self, mut drawer: Drawer, transaction: TransactionArg, + grove_version: &GroveVersion, ) -> Result> { drawer.down(); - drawer = self.draw_subtree(drawer, SubtreePathBuilder::new(), transaction)?; + drawer = self.draw_subtree( + drawer, + SubtreePathBuilder::new(), + transaction, + grove_version, + )?; drawer.up(); Ok(drawer) @@ -240,9 +249,10 @@ impl GroveDb { &self, mut drawer: Drawer, transaction: TransactionArg, + grove_version: &GroveVersion, ) -> Result> { drawer.write(b"root")?; - drawer = self.draw_root_tree(drawer, transaction)?; + drawer = self.draw_root_tree(drawer, transaction, grove_version)?; drawer.flush()?; Ok(drawer) } @@ -250,7 +260,7 @@ impl GroveDb { impl Visualize for GroveDb { fn visualize(&self, drawer: Drawer) -> Result> { - self.visualize_start(drawer, None) + self.visualize_start(drawer, None, GroveVersion::latest()) } } diff --git a/merk/Cargo.toml b/merk/Cargo.toml index 2d1c65be..4364a564 100644 --- a/merk/Cargo.toml +++ b/merk/Cargo.toml @@ -20,6 +20,7 @@ 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" } +grovedb-version = { version = "1.0.0-rc.2", path = "../grovedb-version" } [dependencies.time] version = "0.3.34" diff --git a/merk/benches/merk.rs b/merk/benches/merk.rs index ff0fbaef..e2d55219 100644 --- a/merk/benches/merk.rs +++ b/merk/benches/merk.rs @@ -46,7 +46,7 @@ pub fn get(c: &mut Criterion) { let batch_size = 2_000; let num_batches = initial_size / batch_size; - let mut merk = TempMerk::new(); + let mut merk = TempMerk::new(grove_version); let mut batches = vec![]; for i in 0..num_batches { @@ -56,7 +56,7 @@ pub fn get(c: &mut Criterion) { &[], None, &|_k, _v| Ok(0), - None::<&fn(&[u8]) -> Option>, + None::<&fn(&[u8], &GroveVersion) -> Option>, &mut |_costs, _old_value, _value| Ok((false, None)), &mut |_a, key_bytes_to_remove, value_bytes_to_remove| { Ok(( @@ -64,6 +64,7 @@ pub fn get(c: &mut Criterion) { BasicStorageRemoval(value_bytes_to_remove), )) }, + grove_version, ) .unwrap() .expect("apply failed"); @@ -78,9 +79,14 @@ pub fn get(c: &mut Criterion) { let key_index = (i / num_batches) as usize; let key = &batches[batch_index][key_index].0; - merk.get(key, true, None:: Option>) - .unwrap() - .expect("get failed"); + merk.get( + key, + true, + None:: Option>, + grove_version, + ) + .unwrap() + .expect("get failed"); i = (i + 1) % initial_size; }) @@ -101,7 +107,7 @@ pub fn insert_1m_2k_seq(c: &mut Criterion) { } c.bench_function("insert_1m_2k_seq", |b| { - let mut merk = TempMerk::new(); + let mut merk = TempMerk::new(grove_version); let mut i = 0; b.iter_with_large_drop(|| { @@ -111,7 +117,7 @@ pub fn insert_1m_2k_seq(c: &mut Criterion) { &[], None, &|_k, _v| Ok(0), - None::<&fn(&[u8]) -> Option>, + None::<&fn(&[u8], &GroveVersion) -> Option>, &mut |_costs, _old_value, _value| Ok((false, None)), &mut |_a, key_bytes_to_remove, value_bytes_to_remove| { Ok(( @@ -119,6 +125,7 @@ pub fn insert_1m_2k_seq(c: &mut Criterion) { BasicStorageRemoval(value_bytes_to_remove), )) }, + grove_version, ) .unwrap() .expect("apply failed"); @@ -141,7 +148,7 @@ pub fn insert_1m_2k_rand(c: &mut Criterion) { } c.bench_function("insert_1m_2k_rand", |b| { - let mut merk = TempMerk::new(); + let mut merk = TempMerk::new(grove_version); let mut i = 0; b.iter_with_large_drop(|| { @@ -151,7 +158,7 @@ pub fn insert_1m_2k_rand(c: &mut Criterion) { &[], None, &|_k, _v| Ok(0), - None::<&fn(&[u8]) -> Option>, + None::<&fn(&[u8], &GroveVersion) -> Option>, &mut |_costs, _old_value, _value| Ok((false, None)), &mut |_a, key_bytes_to_remove, value_bytes_to_remove| { Ok(( @@ -159,6 +166,7 @@ pub fn insert_1m_2k_rand(c: &mut Criterion) { BasicStorageRemoval(value_bytes_to_remove), )) }, + grove_version, ) .unwrap() .expect("apply failed"); @@ -175,7 +183,7 @@ pub fn update_1m_2k_seq(c: &mut Criterion) { let n_batches: usize = initial_size / batch_size; let mut batches = Vec::with_capacity(n_batches); - let mut merk = TempMerk::new(); + let mut merk = TempMerk::new(grove_version); for i in 0..n_batches { let batch = make_batch_seq(((i * batch_size) as u64)..((i + 1) * batch_size) as u64); @@ -184,7 +192,7 @@ pub fn update_1m_2k_seq(c: &mut Criterion) { &[], None, &|_k, _v| Ok(0), - None::<&fn(&[u8]) -> Option>, + None::<&fn(&[u8], &GroveVersion) -> Option>, &mut |_costs, _old_value, _value| Ok((false, None)), &mut |_a, key_bytes_to_remove, value_bytes_to_remove| { Ok(( @@ -192,6 +200,7 @@ pub fn update_1m_2k_seq(c: &mut Criterion) { BasicStorageRemoval(value_bytes_to_remove), )) }, + grove_version, ) .unwrap() .expect("apply failed"); @@ -209,7 +218,7 @@ pub fn update_1m_2k_seq(c: &mut Criterion) { &[], None, &|_k, _v| Ok(0), - None::<&fn(&[u8]) -> Option>, + None::<&fn(&[u8], &GroveVersion) -> Option>, &mut |_costs, _old_value, _value| Ok((false, None)), &mut |_a, key_bytes_to_remove, value_bytes_to_remove| { Ok(( @@ -217,6 +226,7 @@ pub fn update_1m_2k_seq(c: &mut Criterion) { BasicStorageRemoval(value_bytes_to_remove), )) }, + grove_version, ) .unwrap() .expect("apply failed"); @@ -233,7 +243,7 @@ pub fn update_1m_2k_rand(c: &mut Criterion) { let n_batches: usize = initial_size / batch_size; let mut batches = Vec::with_capacity(n_batches); - let mut merk = TempMerk::new(); + let mut merk = TempMerk::new(grove_version); for i in 0..n_batches { let batch = make_batch_rand(batch_size as u64, i as u64); @@ -242,7 +252,7 @@ pub fn update_1m_2k_rand(c: &mut Criterion) { &[], None, &|_k, _v| Ok(0), - None::<&fn(&[u8]) -> Option>, + None::<&fn(&[u8], &GroveVersion) -> Option>, &mut |_costs, _old_value, _value| Ok((false, None)), &mut |_a, key_bytes_to_remove, value_bytes_to_remove| { Ok(( @@ -250,6 +260,7 @@ pub fn update_1m_2k_rand(c: &mut Criterion) { BasicStorageRemoval(value_bytes_to_remove), )) }, + grove_version, ) .unwrap() .expect("apply failed"); @@ -267,7 +278,7 @@ pub fn update_1m_2k_rand(c: &mut Criterion) { &[], None, &|_k, _v| Ok(0), - None::<&fn(&[u8]) -> Option>, + None::<&fn(&[u8], &GroveVersion) -> Option>, &mut |_costs, _old_value, _value| Ok((false, None)), &mut |_a, key_bytes_to_remove, value_bytes_to_remove| { Ok(( @@ -275,6 +286,7 @@ pub fn update_1m_2k_rand(c: &mut Criterion) { BasicStorageRemoval(value_bytes_to_remove), )) }, + grove_version, ) .unwrap() .expect("apply failed"); @@ -292,7 +304,7 @@ pub fn delete_1m_2k_rand(c: &mut Criterion) { let mut batches = Vec::with_capacity(n_batches); let mut delete_batches = Vec::with_capacity(n_batches); - let mut merk = TempMerk::new(); + let mut merk = TempMerk::new(grove_version); for i in 0..n_batches { let batch = make_batch_rand(batch_size as u64, i as u64); @@ -302,7 +314,7 @@ pub fn delete_1m_2k_rand(c: &mut Criterion) { &[], None, &|_k, _v| Ok(0), - None::<&fn(&[u8]) -> Option>, + None::<&fn(&[u8], &GroveVersion) -> Option>, &mut |_costs, _old_value, _value| Ok((false, None)), &mut |_a, key_bytes_to_remove, value_bytes_to_remove| { Ok(( @@ -310,6 +322,7 @@ pub fn delete_1m_2k_rand(c: &mut Criterion) { BasicStorageRemoval(value_bytes_to_remove), )) }, + grove_version, ) .unwrap() .expect("apply failed"); @@ -331,7 +344,7 @@ pub fn delete_1m_2k_rand(c: &mut Criterion) { &[], None, &|_k, _v| Ok(0), - None::<&fn(&[u8]) -> Option>, + None::<&fn(&[u8], &GroveVersion) -> Option>, &mut |_costs, _old_value, _value| Ok((false, None)), &mut |_a, key_bytes_to_remove, value_bytes_to_remove| { Ok(( @@ -339,6 +352,7 @@ pub fn delete_1m_2k_rand(c: &mut Criterion) { BasicStorageRemoval(value_bytes_to_remove), )) }, + grove_version, ) .unwrap() .expect("apply failed"); @@ -349,7 +363,7 @@ pub fn delete_1m_2k_rand(c: &mut Criterion) { &[], None, &|_k, _v| Ok(0), - None::<&fn(&[u8]) -> Option>, + None::<&fn(&[u8], &GroveVersion) -> Option>, &mut |_costs, _old_value, _value| Ok((false, None)), &mut |_a, key_bytes_to_remove, value_bytes_to_remove| { Ok(( @@ -357,6 +371,7 @@ pub fn delete_1m_2k_rand(c: &mut Criterion) { BasicStorageRemoval(value_bytes_to_remove), )) }, + grove_version, ) .unwrap() .expect("apply failed"); @@ -374,7 +389,7 @@ pub fn prove_1m_2k_rand(c: &mut Criterion) { let mut batches = Vec::with_capacity(n_batches); let mut prove_keys_per_batch = Vec::with_capacity(n_batches); - let mut merk = TempMerk::new(); + let mut merk = TempMerk::new(grove_version); for i in 0..n_batches { let batch = make_batch_rand(batch_size as u64, i as u64); @@ -383,7 +398,7 @@ pub fn prove_1m_2k_rand(c: &mut Criterion) { &[], None, &|_k, _v| Ok(0), - None::<&fn(&[u8]) -> Option>, + None::<&fn(&[u8], &GroveVersion) -> Option>, &mut |_costs, _old_value, _value| Ok((false, None)), &mut |_a, key_bytes_to_remove, value_bytes_to_remove| { Ok(( @@ -391,6 +406,7 @@ pub fn prove_1m_2k_rand(c: &mut Criterion) { BasicStorageRemoval(value_bytes_to_remove), )) }, + grove_version, ) .unwrap() .expect("apply failed"); @@ -408,7 +424,7 @@ pub fn prove_1m_2k_rand(c: &mut Criterion) { b.iter_with_large_drop(|| { let keys = prove_keys_per_batch[i % n_batches].clone(); - merk.prove_unchecked(keys, None, true) + merk.prove_unchecked(keys, None, true, grove_version) .unwrap() .expect("prove failed"); i += 1; @@ -423,7 +439,7 @@ pub fn build_trunk_chunk_1m_2k_rand(c: &mut Criterion) { let n_batches: usize = initial_size / batch_size; - let mut merk = TempMerk::new(); + let mut merk = TempMerk::new(grove_version); for i in 0..n_batches { let batch = make_batch_rand(batch_size as u64, i as u64); @@ -432,7 +448,7 @@ pub fn build_trunk_chunk_1m_2k_rand(c: &mut Criterion) { &[], None, &|_k, _v| Ok(0), - None::<&fn(&[u8]) -> Option>, + None::<&fn(&[u8], &GroveVersion) -> Option>, &mut |_costs, _old_value, _value| Ok((false, None)), &mut |_a, key_bytes_to_remove, value_bytes_to_remove| { Ok(( @@ -440,6 +456,7 @@ pub fn build_trunk_chunk_1m_2k_rand(c: &mut Criterion) { BasicStorageRemoval(value_bytes_to_remove), )) }, + grove_version, ) .unwrap() .expect("apply failed") @@ -465,7 +482,7 @@ pub fn chunkproducer_rand_1m_1_rand(c: &mut Criterion) { let n_batches: usize = initial_size / batch_size; - let mut merk = TempMerk::new(); + let mut merk = TempMerk::new(grove_version); for i in 0..n_batches { let batch = make_batch_rand(batch_size as u64, i as u64); @@ -474,7 +491,7 @@ pub fn chunkproducer_rand_1m_1_rand(c: &mut Criterion) { &[], None, &|_k, _v| Ok(0), - None::<&fn(&[u8]) -> Option>, + None::<&fn(&[u8], &GroveVersion) -> Option>, &mut |_costs, _old_value, _value| Ok((false, None)), &mut |_a, key_bytes_to_remove, value_bytes_to_remove| { Ok(( @@ -482,6 +499,7 @@ pub fn chunkproducer_rand_1m_1_rand(c: &mut Criterion) { BasicStorageRemoval(value_bytes_to_remove), )) }, + grove_version, ) .unwrap() .expect("apply failed") @@ -493,7 +511,7 @@ pub fn chunkproducer_rand_1m_1_rand(c: &mut Criterion) { c.bench_function("chunkproducer_rand_1m_1_rand", |b| { b.iter_with_large_drop(|| { let i = rng.gen::() % chunks.len(); - let _chunk = chunks.chunk(i).unwrap(); + let _chunk = chunks.chunk(i, grove_version).unwrap(); }); }); } @@ -505,7 +523,7 @@ pub fn chunk_iter_1m_1(c: &mut Criterion) { let n_batches: usize = initial_size / batch_size; - let mut merk = TempMerk::new(); + let mut merk = TempMerk::new(grove_version); for i in 0..n_batches { let batch = make_batch_rand(batch_size as u64, i as u64); @@ -514,7 +532,7 @@ pub fn chunk_iter_1m_1(c: &mut Criterion) { &[], None, &|_k, _v| Ok(0), - None::<&fn(&[u8]) -> Option>, + None::<&fn(&[u8], &GroveVersion) -> Option>, &mut |_costs, _old_value, _value| Ok((false, None)), &mut |_a, key_bytes_to_remove, value_bytes_to_remove| { Ok(( @@ -522,6 +540,7 @@ pub fn chunk_iter_1m_1(c: &mut Criterion) { BasicStorageRemoval(value_bytes_to_remove), )) }, + grove_version, ) .unwrap() .expect("apply failed") @@ -529,11 +548,11 @@ pub fn chunk_iter_1m_1(c: &mut Criterion) { let mut chunks = merk.chunks().unwrap().into_iter(); - let mut next = || match chunks.next() { + let mut next = || match chunks.next(grove_version) { Some(chunk) => chunk, None => { chunks = merk.chunks().unwrap().into_iter(); - chunks.next().unwrap() + chunks.next(grove_version).unwrap() } }; @@ -548,7 +567,7 @@ pub fn chunk_iter_1m_1(c: &mut Criterion) { pub fn restore_500_1(c: &mut Criterion) { let merk_size = 500; - let mut merk = TempMerk::new(); + let mut merk = TempMerk::new(grove_version); let batch = make_batch_rand(merk_size as u64, 0_u64); merk.apply_unchecked::<_, Vec, _, _, _, _>( @@ -556,7 +575,7 @@ pub fn restore_500_1(c: &mut Criterion) { &[], None, &|_k, _v| Ok(0), - None::<&fn(&[u8]) -> Option>, + None::<&fn(&[u8], &GroveVersion) -> Option>, &mut |_costs, _old_value, _value| Ok((false, None)), &mut |_a, key_bytes_to_remove, value_bytes_to_remove| { Ok(( @@ -564,6 +583,7 @@ pub fn restore_500_1(c: &mut Criterion) { BasicStorageRemoval(value_bytes_to_remove), )) }, + grove_version, ) .unwrap() .expect("apply failed"); @@ -585,7 +605,8 @@ pub fn restore_500_1(c: &mut Criterion) { let m = Merk::open_standalone( ctx, false, - None::<&fn(&[u8]) -> Option>, + None::<&fn(&[u8], &GroveVersion) -> Option>, + grove_version, ) .unwrap() .unwrap(); diff --git a/merk/benches/ops.rs b/merk/benches/ops.rs index f9576fba..d194e6ff 100644 --- a/merk/benches/ops.rs +++ b/merk/benches/ops.rs @@ -42,7 +42,7 @@ fn insert_1m_10k_seq_memonly(c: &mut Criterion) { let batch_size = 10_000; let n_batches = initial_size / batch_size; - let mut tree = Owner::new(make_tree_seq(initial_size)); + let mut tree = Owner::new(make_tree_seq(initial_size, grove_version)); let mut batches = Vec::new(); for i in 0..n_batches { @@ -54,7 +54,7 @@ fn insert_1m_10k_seq_memonly(c: &mut Criterion) { b.iter(|| { let batch = &batches[i % n_batches as usize]; - tree.own(|tree| apply_memonly_unchecked(tree, batch)); + tree.own(|tree| apply_memonly_unchecked(tree, batch, grove_version)); i += 1; }); }); @@ -66,7 +66,13 @@ fn insert_1m_10k_rand_memonly(c: &mut Criterion) { let batch_size = 10_000; let n_batches = initial_size / batch_size; - let mut tree = Owner::new(make_tree_rand(initial_size, batch_size, 0, false)); + let mut tree = Owner::new(make_tree_rand( + initial_size, + batch_size, + 0, + false, + grove_version, + )); let mut batches = Vec::new(); for i in 0..n_batches { @@ -78,7 +84,7 @@ fn insert_1m_10k_rand_memonly(c: &mut Criterion) { b.iter(|| { let batch = &batches[i % n_batches as usize]; - tree.own(|tree| apply_memonly_unchecked(tree, batch)); + tree.own(|tree| apply_memonly_unchecked(tree, batch, grove_version)); i += 1; }); }); @@ -90,12 +96,12 @@ fn update_1m_10k_seq_memonly(c: &mut Criterion) { let batch_size = 10_000; let n_batches = initial_size / batch_size; - let mut tree = Owner::new(make_tree_seq(initial_size)); + let mut tree = Owner::new(make_tree_seq(initial_size, grove_version)); let mut batches = Vec::new(); for i in 0..n_batches { let batch = make_batch_seq((i * batch_size)..((i + 1) * batch_size)); - tree.own(|tree| apply_memonly_unchecked(tree, &batch)); + tree.own(|tree| apply_memonly_unchecked(tree, &batch, grove_version)); batches.push(batch); } @@ -104,7 +110,7 @@ fn update_1m_10k_seq_memonly(c: &mut Criterion) { b.iter(|| { let batch = &batches[i % n_batches as usize]; - tree.own(|tree| apply_memonly_unchecked(tree, batch)); + tree.own(|tree| apply_memonly_unchecked(tree, batch, grove_version)); i += 1; }); }); @@ -116,12 +122,18 @@ fn update_1m_10k_rand_memonly(c: &mut Criterion) { let batch_size = 10_000; let n_batches = initial_size / batch_size; - let mut tree = Owner::new(make_tree_rand(initial_size, batch_size, 0, false)); + let mut tree = Owner::new(make_tree_rand( + initial_size, + batch_size, + 0, + false, + grove_version, + )); let mut batches = Vec::new(); for i in 0..n_batches { let batch = make_batch_rand(batch_size, i); - tree.own(|tree| apply_memonly_unchecked(tree, &batch)); + tree.own(|tree| apply_memonly_unchecked(tree, &batch, grove_version)); batches.push(batch); } @@ -130,7 +142,7 @@ fn update_1m_10k_rand_memonly(c: &mut Criterion) { b.iter(|| { let batch = &batches[i % n_batches as usize]; - tree.own(|tree| apply_memonly_unchecked(tree, batch)); + tree.own(|tree| apply_memonly_unchecked(tree, batch, grove_version)); i += 1; }); }); diff --git a/merk/src/debugger.rs b/merk/src/debugger.rs index fc710c0a..c5d322c0 100644 --- a/merk/src/debugger.rs +++ b/merk/src/debugger.rs @@ -2,6 +2,7 @@ use grovedb_costs::CostsExt; use grovedb_storage::StorageContext; +use grovedb_version::version::GroveVersion; use crate::{tree::kv::ValueDefinedCostType, Error, Merk}; @@ -18,7 +19,8 @@ impl<'a, S: StorageContext<'a>> Merk { } .wrap_with_cost(Default::default()) }, - None:: Option>, // I wish I knew why + None:: Option>, + GroveVersion::latest(), ) .unwrap() } diff --git a/merk/src/error.rs b/merk/src/error.rs index 83fb3bde..c365b898 100644 --- a/merk/src/error.rs +++ b/merk/src/error.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. - //! Errors #[cfg(feature = "full")] use crate::proofs::chunk::error::ChunkError; @@ -141,4 +113,14 @@ pub enum Error { /// Costs errors #[error("costs error: {0}")] CostsError(grovedb_costs::error::Error), + // Version errors + #[error(transparent)] + /// Version error + VersionError(grovedb_version::error::GroveVersionError), +} + +impl From for Error { + fn from(value: grovedb_version::error::GroveVersionError) -> Self { + Error::VersionError(value) + } } diff --git a/merk/src/estimated_costs/average_case_costs.rs b/merk/src/estimated_costs/average_case_costs.rs index 1453d708..12f8c2c9 100644 --- a/merk/src/estimated_costs/average_case_costs.rs +++ b/merk/src/estimated_costs/average_case_costs.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. - //! Average case costs for Merk #[cfg(feature = "full")] @@ -336,7 +308,7 @@ pub fn add_average_case_get_merk_node( not_prefixed_key_len: u32, approximate_element_size: u32, is_sum_tree: bool, -) { +) -> Result<(), Error> { // Worst case scenario, the element is not already in memory. // One direct seek has to be performed to read the node from storage. cost.seek_count += 1; @@ -348,6 +320,7 @@ pub fn add_average_case_get_merk_node( approximate_element_size, is_sum_tree, ); + Ok(()) } #[cfg(feature = "full")] diff --git a/merk/src/estimated_costs/mod.rs b/merk/src/estimated_costs/mod.rs index faabce81..bd669db1 100644 --- a/merk/src/estimated_costs/mod.rs +++ b/merk/src/estimated_costs/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. - //! Estimated costs for Merk #[cfg(feature = "full")] diff --git a/merk/src/estimated_costs/worst_case_costs.rs b/merk/src/estimated_costs/worst_case_costs.rs index 407e2c70..f4623c8d 100644 --- a/merk/src/estimated_costs/worst_case_costs.rs +++ b/merk/src/estimated_costs/worst_case_costs.rs @@ -74,7 +74,7 @@ pub fn add_worst_case_get_merk_node( not_prefixed_key_len: u32, max_element_size: u32, is_sum_node: bool, -) { +) -> Result<(), Error> { // Worst case scenario, the element is not already in memory. // One direct seek has to be performed to read the node from storage. cost.seek_count += 1; @@ -83,6 +83,7 @@ pub fn add_worst_case_get_merk_node( // worst case, the node has both the left and right link present. cost.storage_loaded_bytes += TreeNode::worst_case_encoded_tree_size(not_prefixed_key_len, max_element_size, is_sum_node); + Ok(()) } #[cfg(feature = "full")] diff --git a/merk/src/merk/apply.rs b/merk/src/merk/apply.rs index a33dfcc4..84b4cb9a 100644 --- a/merk/src/merk/apply.rs +++ b/merk/src/merk/apply.rs @@ -8,6 +8,7 @@ use grovedb_costs::{ CostResult, CostsExt, }; use grovedb_storage::StorageContext; +use grovedb_version::version::GroveVersion; use crate::{ tree::{ @@ -30,12 +31,19 @@ where /// /// # Example /// ``` - /// # let mut store = grovedb_merk::test_utils::TempMerk::new(); - /// # store.apply::<_, Vec<_>>(&[(vec![4,5,6], Op::Put(vec![0], BasicMerkNode))], &[], None) - /// .unwrap().expect(""); + /// # let grove_version = GroveVersion::latest(); + /// # let mut store = grovedb_merk::test_utils::TempMerk::new(grove_version); + /// # store.apply::<_, Vec<_>>( + /// &[(vec![4,5,6], + /// Op::Put(vec![0], BasicMerkNode))], + /// &[], + /// None, + /// grove_version + /// ).unwrap().expect(""); /// /// use grovedb_merk::Op; /// use grovedb_merk::TreeFeatureType::BasicMerkNode; + /// use grovedb_version::version::GroveVersion; /// /// let batch = &[ /// // puts value [4,5,6] to key[1,2,3] @@ -43,13 +51,14 @@ where /// // deletes key [4,5,6] /// (vec![4, 5, 6], Op::Delete), /// ]; - /// store.apply::<_, Vec<_>>(batch, &[], None).unwrap().expect(""); + /// store.apply::<_, Vec<_>>(batch, &[], None,grove_version).unwrap().expect(""); /// ``` pub fn apply( &mut self, batch: &MerkBatch, aux: &AuxMerkBatch, options: Option, + grove_version: &GroveVersion, ) -> CostResult<(), Error> where KB: AsRef<[u8]>, @@ -67,7 +76,7 @@ where use_sum_nodes, )) }, - None::<&fn(&[u8]) -> Option>, + None::<&fn(&[u8], &GroveVersion) -> Option>, &mut |_costs, _old_value, _value| Ok((false, None)), &mut |_a, key_bytes_to_remove, value_bytes_to_remove| { Ok(( @@ -75,6 +84,7 @@ where BasicStorageRemoval(value_bytes_to_remove), )) }, + grove_version, ) } @@ -87,12 +97,19 @@ where /// /// # Example /// ``` - /// # let mut store = grovedb_merk::test_utils::TempMerk::new(); - /// # store.apply::<_, Vec<_>>(&[(vec![4,5,6], Op::Put(vec![0], BasicMerkNode))], &[], None) - /// .unwrap().expect(""); + /// # let grove_version = GroveVersion::latest(); + /// # let mut store = grovedb_merk::test_utils::TempMerk::new(grove_version); + /// # store.apply::<_, Vec<_>>( + /// &[(vec![4,5,6], + /// Op::Put(vec![0], BasicMerkNode))], + /// &[], + /// None, + /// grove_version + /// ).unwrap().expect(""); /// /// use grovedb_merk::Op; /// use grovedb_merk::TreeFeatureType::BasicMerkNode; + /// use grovedb_version::version::GroveVersion; /// /// let batch = &[ /// // puts value [4,5,6] to key[1,2,3] @@ -100,7 +117,7 @@ where /// // deletes key [4,5,6] /// (vec![4, 5, 6], Op::Delete), /// ]; - /// store.apply::<_, Vec<_>>(batch, &[], None).unwrap().expect(""); + /// store.apply::<_, Vec<_>>(batch, &[], None,grove_version).unwrap().expect(""); /// ``` pub fn apply_with_specialized_costs( &mut self, @@ -108,7 +125,10 @@ where aux: &AuxMerkBatch, options: Option, old_specialized_cost: &impl Fn(&Vec, &Vec) -> Result, - value_defined_cost_fn: Option<&impl Fn(&[u8]) -> Option>, + value_defined_cost_fn: Option< + &impl Fn(&[u8], &GroveVersion) -> Option, + >, + grove_version: &GroveVersion, ) -> CostResult<(), Error> where KB: AsRef<[u8]>, @@ -127,6 +147,7 @@ where BasicStorageRemoval(value_bytes_to_remove), )) }, + grove_version, ) } @@ -140,21 +161,24 @@ where /// /// # Example /// ``` - /// # let mut store = grovedb_merk::test_utils::TempMerk::new(); - /// # store.apply_with_costs_just_in_time_value_update::<_, Vec<_>>( + /// # let grove_version = GroveVersion::latest(); + /// # let mut store = grovedb_merk::test_utils::TempMerk::new(grove_version); + /// # store.apply_with_costs_just_in_time_value_update::<_, Vec<_>>( /// /// /// /// /// &[(vec![4,5,6], Op::Put(vec![0], BasicMerkNode))], /// &[], /// None, /// &|k, v| Ok(0), - /// None::<&fn(&[u8]) -> Option>, + /// None::<&fn(&[u8], &GroveVersion) -> Option>, /// &mut |s, v, o| Ok((false, None)), - /// &mut |s, k, v| Ok((NoStorageRemoval, NoStorageRemoval)) + /// &mut |s, k, v| Ok((NoStorageRemoval, NoStorageRemoval)), + /// grove_version, /// ).unwrap().expect(""); /// /// use grovedb_costs::storage_cost::removal::StorageRemovedBytes::NoStorageRemoval; /// use grovedb_merk::Op; /// use grovedb_merk::tree::kv::ValueDefinedCostType; /// use grovedb_merk::TreeFeatureType::BasicMerkNode; + /// use grovedb_version::version::GroveVersion; /// /// let batch = &[ /// // puts value [4,5,6] to key[1,2,3] @@ -164,13 +188,14 @@ where /// ]; /// /// store.apply_with_costs_just_in_time_value_update::<_, Vec<_>>( - /// batch, + /// batch, /// &[], /// None, /// &|k, v| Ok(0), - /// None::<&fn(&[u8]) -> Option>, + /// None::<&fn(&[u8], &GroveVersion) -> Option>, /// &mut |s, v, o| Ok((false, None)), - /// &mut |s, k, v| Ok((NoStorageRemoval, NoStorageRemoval)) + /// &mut |s, k, v| Ok((NoStorageRemoval, NoStorageRemoval)), + /// grove_version, /// ).unwrap().expect(""); /// ``` pub fn apply_with_costs_just_in_time_value_update( @@ -179,7 +204,9 @@ where aux: &AuxMerkBatch, options: Option, old_specialized_cost: &impl Fn(&Vec, &Vec) -> Result, - value_defined_cost_fn: Option<&impl Fn(&[u8]) -> Option>, + value_defined_cost_fn: Option< + &impl Fn(&[u8], &GroveVersion) -> Option, + >, update_tree_value_based_on_costs: &mut impl FnMut( &StorageCost, &Vec, @@ -196,6 +223,7 @@ where (StorageRemovedBytes, StorageRemovedBytes), Error, >, + grove_version: &GroveVersion, ) -> CostResult<(), Error> where KB: AsRef<[u8]>, @@ -228,6 +256,7 @@ where value_defined_cost_fn, update_tree_value_based_on_costs, section_removal_bytes, + grove_version, ) } @@ -241,21 +270,24 @@ where /// /// # Example /// ``` - /// # let mut store = grovedb_merk::test_utils::TempMerk::new(); - /// # store.apply_with_costs_just_in_time_value_update::<_, Vec<_>>( + /// # let grove_version = GroveVersion::latest(); + /// # let mut store = grovedb_merk::test_utils::TempMerk::new(grove_version); + /// # store.apply_with_costs_just_in_time_value_update::<_, Vec<_>>( /// /// /// /// /// &[(vec![4,5,6], Op::Put(vec![0], BasicMerkNode))], /// &[], /// None, /// &|k, v| Ok(0), - /// None::<&fn(&[u8]) -> Option>, + /// None::<&fn(&[u8], &GroveVersion) -> Option>, /// &mut |s, o, v| Ok((false, None)), - /// &mut |s, k, v| Ok((NoStorageRemoval, NoStorageRemoval)) + /// &mut |s, k, v| Ok((NoStorageRemoval, NoStorageRemoval)), + /// grove_version, /// ).unwrap().expect(""); /// /// use grovedb_costs::storage_cost::removal::StorageRemovedBytes::NoStorageRemoval; /// use grovedb_merk::Op; /// use grovedb_merk::tree::kv::ValueDefinedCostType; /// use grovedb_merk::TreeFeatureType::BasicMerkNode; + /// use grovedb_version::version::GroveVersion; /// /// let batch = &[ /// // puts value [4,5,6] to key [1,2,3] @@ -263,14 +295,15 @@ where /// // deletes key [4,5,6] /// (vec![4, 5, 6], Op::Delete), /// ]; - /// unsafe { store.apply_unchecked::<_, Vec<_>, _, _, _, _>( /// /// /// - /// batch, + /// unsafe { store.apply_unchecked::<_, Vec<_>, _, _, _, _>( /// /// /// /// /// ////// + /// batch, /// &[], /// None, /// &|k, v| Ok(0), - /// None::<&fn(&[u8]) -> Option>, + /// None::<&fn(&[u8], &GroveVersion) -> Option>, /// &mut |s, o, v| Ok((false, None)), - /// &mut |s, k, v| Ok((NoStorageRemoval, NoStorageRemoval)) + /// &mut |s, k, v| Ok((NoStorageRemoval, NoStorageRemoval)), + /// grove_version, /// ).unwrap().expect(""); /// } /// ``` @@ -283,12 +316,13 @@ where value_defined_cost_fn: Option<&V>, update_tree_value_based_on_costs: &mut U, section_removal_bytes: &mut R, + grove_version: &GroveVersion, ) -> CostResult<(), Error> where KB: AsRef<[u8]>, KA: AsRef<[u8]>, C: Fn(&Vec, &Vec) -> Result, - V: Fn(&[u8]) -> Option, + V: Fn(&[u8], &GroveVersion) -> Option, U: FnMut( &StorageCost, &Vec, @@ -310,6 +344,7 @@ where value_defined_cost_fn, update_tree_value_based_on_costs, section_removal_bytes, + grove_version, ) .flat_map_ok(|(maybe_tree, key_updates)| { // we set the new root node of the merk tree diff --git a/merk/src/merk/chunks.rs b/merk/src/merk/chunks.rs index ef94571e..20c6cc39 100644 --- a/merk/src/merk/chunks.rs +++ b/merk/src/merk/chunks.rs @@ -2,6 +2,7 @@ use std::collections::VecDeque; use ed::Encode; use grovedb_storage::StorageContext; +use grovedb_version::version::GroveVersion; use crate::{ error::Error, @@ -97,19 +98,25 @@ where pub fn chunk_with_index( &mut self, chunk_index: usize, + grove_version: &GroveVersion, ) -> Result<(Vec, Option), Error> { let traversal_instructions = generate_traversal_instruction(self.height, chunk_index)?; - self.chunk_internal(chunk_index, traversal_instructions) + self.chunk_internal(chunk_index, traversal_instructions, grove_version) } /// Returns the chunk at a given chunk id. - pub fn chunk(&mut self, chunk_id: &[u8]) -> Result<(Vec, Option>), Error> { + pub fn chunk( + &mut self, + chunk_id: &[u8], + grove_version: &GroveVersion, + ) -> Result<(Vec, Option>), Error> { let traversal_instructions = vec_bytes_as_traversal_instruction(chunk_id)?; let chunk_index = chunk_index_from_traversal_instruction_with_recovery( traversal_instructions.as_slice(), self.height, )?; - let (chunk, next_index) = self.chunk_internal(chunk_index, traversal_instructions)?; + let (chunk, next_index) = + self.chunk_internal(chunk_index, traversal_instructions, grove_version)?; let next_chunk_id = next_index .map(|index| generate_traversal_instruction_as_vec_bytes(self.height, index)) .transpose()?; @@ -122,6 +129,7 @@ where &mut self, index: usize, traversal_instructions: Vec, + grove_version: &GroveVersion, ) -> Result<(Vec, Option), Error> { // ensure that the chunk index is within bounds let max_chunk_index = self.len(); @@ -136,9 +144,11 @@ where let chunk_height = chunk_height(self.height, index).unwrap(); let chunk = self.merk.walk(|maybe_walker| match maybe_walker { - Some(mut walker) => { - walker.traverse_and_build_chunk(&traversal_instructions, chunk_height) - } + Some(mut walker) => walker.traverse_and_build_chunk( + &traversal_instructions, + chunk_height, + grove_version, + ), None => Err(Error::ChunkingError(ChunkError::EmptyTree( "cannot create chunk producer for empty Merk", ))), @@ -160,12 +170,13 @@ where &mut self, chunk_id: &[u8], limit: Option, + grove_version: &GroveVersion, ) -> Result { // we want to convert the chunk id to the index let chunk_index = vec_bytes_as_traversal_instruction(chunk_id).and_then(|instruction| { chunk_index_from_traversal_instruction(instruction.as_slice(), self.height) })?; - self.multi_chunk_with_limit_and_index(chunk_index, limit) + self.multi_chunk_with_limit_and_index(chunk_index, limit, grove_version) } /// Generate multichunk with chunk index @@ -175,6 +186,7 @@ where &mut self, index: usize, limit: Option, + grove_version: &GroveVersion, ) -> Result { // TODO: what happens if the vec is filled? // we need to have some kind of hardhoc limit value if none is supplied. @@ -210,6 +222,7 @@ where let subtree_multi_chunk_result = self.subtree_multi_chunk_with_limit( current_index.expect("confirmed is not None"), temp_limit, + grove_version, ); let limit_too_small_error = matches!( @@ -253,13 +266,14 @@ where &mut self, index: usize, limit: Option, + grove_version: &GroveVersion, ) -> Result { let max_chunk_index = number_of_chunks(self.height); let mut chunk_index = index; // we first get the chunk at the given index // TODO: use the returned chunk index rather than tracking - let (chunk_ops, _) = self.chunk_with_index(chunk_index)?; + let (chunk_ops, _) = self.chunk_with_index(chunk_index, grove_version)?; let mut chunk_byte_length = chunk_ops.encoding_length().map_err(|_e| { Error::ChunkingError(ChunkError::InternalError("can't get encoding length")) })?; @@ -282,7 +296,7 @@ where // we only perform replacements on Hash nodes if matches!(chunk[iteration_index], Op::Push(Node::Hash(..))) { // TODO: use the returned chunk index rather than tracking - let (replacement_chunk, _) = self.chunk_with_index(chunk_index)?; + let (replacement_chunk, _) = self.chunk_with_index(chunk_index, grove_version)?; // calculate the new total let new_total = replacement_chunk.encoding_length().map_err(|_e| { @@ -343,7 +357,10 @@ where /// optimizing throughput compared to random access. // TODO: this is not better than random access, as we are not keeping state // that will make this more efficient, decide if this should be fixed or not - fn next_chunk(&mut self) -> Option, Option>), Error>> { + fn next_chunk( + &mut self, + grove_version: &GroveVersion, + ) -> Option, Option>), Error>> { let max_index = number_of_chunks(self.height); if self.index > max_index { return None; @@ -352,7 +369,7 @@ where // get the chunk at the given index // return the next index as a string Some( - self.chunk_with_index(self.index) + self.chunk_with_index(self.index, grove_version) .and_then(|(chunk, chunk_index)| { chunk_index .map(|index| { @@ -366,14 +383,15 @@ where } /// Iterate over each chunk, returning `None` after last chunk -impl<'db, S> Iterator for ChunkProducer<'db, S> +impl<'db, S> ChunkProducer<'db, S> where S: StorageContext<'db>, { - type Item = Result<(Vec, Option>), Error>; - - fn next(&mut self) -> Option { - self.next_chunk() + pub fn next( + &mut self, + grove_version: &GroveVersion, + ) -> Option, Option>), Error>> { + self.next_chunk(grove_version) } } @@ -451,13 +469,14 @@ mod test { #[test] fn test_merk_chunk_len() { + let grove_version = GroveVersion::latest(); // Tree of height 5 - max of 31 elements, min of 16 elements // 5 will be broken into 2 layers = [3, 2] // exit nodes from first layer = 2^3 = 8 // total_chunk = 1 + 8 = 9 chunks - let mut merk = TempMerk::new(); + let mut merk = TempMerk::new(grove_version); let batch = make_batch_seq(0..20); - merk.apply::<_, Vec<_>>(&batch, &[], None) + merk.apply::<_, Vec<_>>(&batch, &[], None, grove_version) .unwrap() .expect("apply failed"); assert_eq!(merk.height(), Some(5)); @@ -468,9 +487,9 @@ mod test { // 4 layers -> [3,3,2,2] // chunk_count_per_layer -> [1, 8, 64, 256] // total = 341 chunks - let mut merk = TempMerk::new(); + let mut merk = TempMerk::new(grove_version); let batch = make_batch_seq(0..1000); - merk.apply::<_, Vec<_>>(&batch, &[], None) + merk.apply::<_, Vec<_>>(&batch, &[], None, grove_version) .unwrap() .expect("apply failed"); assert_eq!(merk.height(), Some(10)); @@ -480,6 +499,7 @@ mod test { #[test] fn test_chunk_producer_iter() { + let grove_version = GroveVersion::latest(); // tree with height 4 // full tree // 7 @@ -492,9 +512,9 @@ mod test { // going to be broken into [2, 2] // that's a total of 5 chunks - let mut merk = TempMerk::new(); + let mut merk = TempMerk::new(grove_version); let batch = make_batch_seq(0..15); - merk.apply::<_, Vec<_>>(&batch, &[], None) + merk.apply::<_, Vec<_>>(&batch, &[], None, grove_version) .unwrap() .expect("apply failed"); assert_eq!(merk.height(), Some(4)); @@ -508,17 +528,18 @@ mod test { // as that from the chunk producer for i in 1..=5 { assert_eq!( - chunks.next().unwrap().unwrap().0, - chunk_producer.chunk_with_index(i).unwrap().0 + chunks.next(grove_version).unwrap().unwrap().0, + chunk_producer.chunk_with_index(i, grove_version).unwrap().0 ); } // returns None after max - assert!(chunks.next().is_none()); + assert!(chunks.next(grove_version).is_none()); } #[test] fn test_random_chunk_access() { + let grove_version = GroveVersion::latest(); // tree with height 4 // full tree // 7 @@ -531,9 +552,9 @@ mod test { // going to be broken into [2, 2] // that's a total of 5 chunks - let mut merk = TempMerk::new(); + let mut merk = TempMerk::new(grove_version); let batch = make_batch_seq(0..15); - merk.apply::<_, Vec<_>>(&batch, &[], None) + merk.apply::<_, Vec<_>>(&batch, &[], None, grove_version) .unwrap() .expect("apply failed"); assert_eq!(merk.height(), Some(4)); @@ -548,8 +569,8 @@ mod test { assert_eq!(chunk_producer.len(), 5); // assert bounds - assert!(chunk_producer.chunk_with_index(0).is_err()); - assert!(chunk_producer.chunk_with_index(6).is_err()); + assert!(chunk_producer.chunk_with_index(0, grove_version).is_err()); + assert!(chunk_producer.chunk_with_index(6, grove_version).is_err()); // first chunk // expected: @@ -559,24 +580,52 @@ mod test { // / \ / \ // H(1) H(5) H(9) H(13) let (chunk, next_chunk) = chunk_producer - .chunk_with_index(1) + .chunk_with_index(1, grove_version) .expect("should generate chunk"); assert_eq!(chunk.len(), 13); assert_eq!(next_chunk, Some(2)); assert_eq!( chunk, vec![ - Op::Push(traverse_get_node_hash(&mut tree_walker, &[LEFT, LEFT])), - Op::Push(traverse_get_kv_feature_type(&mut tree_walker, &[LEFT])), + Op::Push(traverse_get_node_hash( + &mut tree_walker, + &[LEFT, LEFT], + grove_version + )), + Op::Push(traverse_get_kv_feature_type( + &mut tree_walker, + &[LEFT], + grove_version + )), Op::Parent, - Op::Push(traverse_get_node_hash(&mut tree_walker, &[LEFT, RIGHT])), + Op::Push(traverse_get_node_hash( + &mut tree_walker, + &[LEFT, RIGHT], + grove_version + )), Op::Child, - Op::Push(traverse_get_kv_feature_type(&mut tree_walker, &[])), + Op::Push(traverse_get_kv_feature_type( + &mut tree_walker, + &[], + grove_version + )), Op::Parent, - Op::Push(traverse_get_node_hash(&mut tree_walker, &[RIGHT, LEFT])), - Op::Push(traverse_get_kv_feature_type(&mut tree_walker, &[RIGHT])), + Op::Push(traverse_get_node_hash( + &mut tree_walker, + &[RIGHT, LEFT], + grove_version + )), + Op::Push(traverse_get_kv_feature_type( + &mut tree_walker, + &[RIGHT], + grove_version + )), Op::Parent, - Op::Push(traverse_get_node_hash(&mut tree_walker, &[RIGHT, RIGHT])), + Op::Push(traverse_get_node_hash( + &mut tree_walker, + &[RIGHT, RIGHT], + grove_version + )), Op::Child, Op::Child ] @@ -588,7 +637,7 @@ mod test { // / \ // 0 2 let (chunk, next_chunk) = chunk_producer - .chunk_with_index(2) + .chunk_with_index(2, grove_version) .expect("should generate chunk"); assert_eq!(chunk.len(), 5); assert_eq!(next_chunk, Some(3)); @@ -597,16 +646,19 @@ mod test { vec![ Op::Push(traverse_get_kv_feature_type( &mut tree_walker, - &[LEFT, LEFT, LEFT] + &[LEFT, LEFT, LEFT], + grove_version )), Op::Push(traverse_get_kv_feature_type( &mut tree_walker, - &[LEFT, LEFT] + &[LEFT, LEFT], + grove_version )), Op::Parent, Op::Push(traverse_get_kv_feature_type( &mut tree_walker, - &[LEFT, LEFT, RIGHT] + &[LEFT, LEFT, RIGHT], + grove_version )), Op::Child ] @@ -618,7 +670,7 @@ mod test { // / \ // 4 6 let (chunk, next_chunk) = chunk_producer - .chunk_with_index(3) + .chunk_with_index(3, grove_version) .expect("should generate chunk"); assert_eq!(chunk.len(), 5); assert_eq!(next_chunk, Some(4)); @@ -627,16 +679,19 @@ mod test { vec![ Op::Push(traverse_get_kv_feature_type( &mut tree_walker, - &[LEFT, RIGHT, LEFT] + &[LEFT, RIGHT, LEFT], + grove_version )), Op::Push(traverse_get_kv_feature_type( &mut tree_walker, - &[LEFT, RIGHT] + &[LEFT, RIGHT], + grove_version )), Op::Parent, Op::Push(traverse_get_kv_feature_type( &mut tree_walker, - &[LEFT, RIGHT, RIGHT] + &[LEFT, RIGHT, RIGHT], + grove_version )), Op::Child ] @@ -648,7 +703,7 @@ mod test { // / \ // 8 10 let (chunk, next_chunk) = chunk_producer - .chunk_with_index(4) + .chunk_with_index(4, grove_version) .expect("should generate chunk"); assert_eq!(chunk.len(), 5); assert_eq!(next_chunk, Some(5)); @@ -657,16 +712,19 @@ mod test { vec![ Op::Push(traverse_get_kv_feature_type( &mut tree_walker, - &[RIGHT, LEFT, LEFT] + &[RIGHT, LEFT, LEFT], + grove_version )), Op::Push(traverse_get_kv_feature_type( &mut tree_walker, - &[RIGHT, LEFT] + &[RIGHT, LEFT], + grove_version )), Op::Parent, Op::Push(traverse_get_kv_feature_type( &mut tree_walker, - &[RIGHT, LEFT, RIGHT] + &[RIGHT, LEFT, RIGHT], + grove_version )), Op::Child ] @@ -678,7 +736,7 @@ mod test { // / \ // 12 14 let (chunk, next_chunk) = chunk_producer - .chunk_with_index(5) + .chunk_with_index(5, grove_version) .expect("should generate chunk"); assert_eq!(chunk.len(), 5); assert_eq!(next_chunk, None); @@ -687,16 +745,19 @@ mod test { vec![ Op::Push(traverse_get_kv_feature_type( &mut tree_walker, - &[RIGHT, RIGHT, LEFT] + &[RIGHT, RIGHT, LEFT], + grove_version )), Op::Push(traverse_get_kv_feature_type( &mut tree_walker, - &[RIGHT, RIGHT] + &[RIGHT, RIGHT], + grove_version )), Op::Parent, Op::Push(traverse_get_kv_feature_type( &mut tree_walker, - &[RIGHT, RIGHT, RIGHT] + &[RIGHT, RIGHT, RIGHT], + grove_version )), Op::Child ] @@ -705,11 +766,12 @@ mod test { #[test] fn test_subtree_chunk_no_limit() { + let grove_version = GroveVersion::latest(); // tree of height 4 // 5 chunks - let mut merk = TempMerk::new(); + let mut merk = TempMerk::new(grove_version); let batch = make_batch_seq(0..15); - merk.apply::<_, Vec<_>>(&batch, &[], None) + merk.apply::<_, Vec<_>>(&batch, &[], None, grove_version) .unwrap() .expect("apply failed"); assert_eq!(merk.height(), Some(4)); @@ -717,7 +779,7 @@ mod test { // generate multi chunk with no limit let mut chunk_producer = ChunkProducer::new(&merk).expect("should create chunk producer"); let chunk_result = chunk_producer - .subtree_multi_chunk_with_limit(1, None) + .subtree_multi_chunk_with_limit(1, None, grove_version) .expect("should generate chunk with limit"); assert_eq!(chunk_result.remaining_limit, None); @@ -741,11 +803,12 @@ mod test { #[test] fn test_subtree_chunk_with_limit() { + let grove_version = GroveVersion::latest(); // tree of height 4 // 5 chunks - let mut merk = TempMerk::new(); + let mut merk = TempMerk::new(grove_version); let batch = make_batch_seq(0..15); - merk.apply::<_, Vec<_>>(&batch, &[], None) + merk.apply::<_, Vec<_>>(&batch, &[], None, grove_version) .unwrap() .expect("apply failed"); assert_eq!(merk.height(), Some(4)); @@ -754,12 +817,12 @@ mod test { // initial chunk is of size 453, so limit of 10 is too small // should return an error - let chunk = chunk_producer.subtree_multi_chunk_with_limit(1, Some(10)); + let chunk = chunk_producer.subtree_multi_chunk_with_limit(1, Some(10), grove_version); assert!(chunk.is_err()); // get just the fist chunk let chunk_result = chunk_producer - .subtree_multi_chunk_with_limit(1, Some(453)) + .subtree_multi_chunk_with_limit(1, Some(453), grove_version) .expect("should generate chunk with limit"); assert_eq!(chunk_result.remaining_limit, Some(0)); assert_eq!(chunk_result.next_index, Some(2)); @@ -779,7 +842,7 @@ mod test { // get up to second chunk let chunk_result = chunk_producer - .subtree_multi_chunk_with_limit(1, Some(737)) + .subtree_multi_chunk_with_limit(1, Some(737), grove_version) .expect("should generate chunk with limit"); assert_eq!(chunk_result.remaining_limit, Some(0)); assert_eq!(chunk_result.next_index, Some(3)); @@ -799,7 +862,7 @@ mod test { // get up to third chunk let chunk_result = chunk_producer - .subtree_multi_chunk_with_limit(1, Some(1021)) + .subtree_multi_chunk_with_limit(1, Some(1021), grove_version) .expect("should generate chunk with limit"); assert_eq!(chunk_result.remaining_limit, Some(0)); assert_eq!(chunk_result.next_index, Some(4)); @@ -819,7 +882,7 @@ mod test { // get up to fourth chunk let chunk_result = chunk_producer - .subtree_multi_chunk_with_limit(1, Some(1305)) + .subtree_multi_chunk_with_limit(1, Some(1305), grove_version) .expect("should generate chunk with limit"); assert_eq!(chunk_result.remaining_limit, Some(0)); assert_eq!(chunk_result.next_index, Some(5)); @@ -839,7 +902,7 @@ mod test { // get up to fifth chunk let chunk_result = chunk_producer - .subtree_multi_chunk_with_limit(1, Some(1589)) + .subtree_multi_chunk_with_limit(1, Some(1589), grove_version) .expect("should generate chunk with limit"); assert_eq!(chunk_result.remaining_limit, Some(0)); assert_eq!(chunk_result.next_index, None); @@ -859,7 +922,7 @@ mod test { // limit larger than total chunk let chunk_result = chunk_producer - .subtree_multi_chunk_with_limit(1, Some(usize::MAX)) + .subtree_multi_chunk_with_limit(1, Some(usize::MAX), grove_version) .expect("should generate chunk with limit"); assert_eq!(chunk_result.remaining_limit, Some(18446744073709550026)); assert_eq!(chunk_result.next_index, None); @@ -880,11 +943,12 @@ mod test { #[test] fn test_multi_chunk_with_no_limit_trunk() { + let grove_version = GroveVersion::latest(); // tree of height 4 // 5 chunks - let mut merk = TempMerk::new(); + let mut merk = TempMerk::new(grove_version); let batch = make_batch_seq(0..15); - merk.apply::<_, Vec<_>>(&batch, &[], None) + merk.apply::<_, Vec<_>>(&batch, &[], None, grove_version) .unwrap() .expect("apply failed"); assert_eq!(merk.height(), Some(4)); @@ -894,7 +958,7 @@ mod test { // we generate the chunk starting from index 1, this has no hash nodes // so no multi chunk will be generated let chunk_result = chunk_producer - .multi_chunk_with_limit_and_index(1, None) + .multi_chunk_with_limit_and_index(1, None, grove_version) .expect("should generate chunk with limit"); assert_eq!(chunk_result.remaining_limit, None); @@ -917,11 +981,12 @@ mod test { #[test] fn test_multi_chunk_with_no_limit_not_trunk() { + let grove_version = GroveVersion::latest(); // tree of height 4 // 5 chunks - let mut merk = TempMerk::new(); + let mut merk = TempMerk::new(grove_version); let batch = make_batch_seq(0..15); - merk.apply::<_, Vec<_>>(&batch, &[], None) + merk.apply::<_, Vec<_>>(&batch, &[], None, grove_version) .unwrap() .expect("apply failed"); assert_eq!(merk.height(), Some(4)); @@ -931,7 +996,7 @@ mod test { // we generate the chunk starting from index 2, this has no hash nodes // so no multi chunk will be generated let chunk_result = chunk_producer - .multi_chunk_with_limit_and_index(2, None) + .multi_chunk_with_limit_and_index(2, None, grove_version) .expect("should generate chunk with limit"); assert_eq!(chunk_result.remaining_limit, None); @@ -952,7 +1017,7 @@ mod test { chunk_result.chunk[1], ChunkOp::Chunk( chunk_producer - .chunk_with_index(2) + .chunk_with_index(2, grove_version) .expect("should generate chunk") .0 ) @@ -961,7 +1026,7 @@ mod test { chunk_result.chunk[3], ChunkOp::Chunk( chunk_producer - .chunk_with_index(3) + .chunk_with_index(3, grove_version) .expect("should generate chunk") .0 ) @@ -970,7 +1035,7 @@ mod test { chunk_result.chunk[5], ChunkOp::Chunk( chunk_producer - .chunk_with_index(4) + .chunk_with_index(4, grove_version) .expect("should generate chunk") .0 ) @@ -979,7 +1044,7 @@ mod test { chunk_result.chunk[7], ChunkOp::Chunk( chunk_producer - .chunk_with_index(5) + .chunk_with_index(5, grove_version) .expect("should generate chunk") .0 ) @@ -988,11 +1053,12 @@ mod test { #[test] fn test_multi_chunk_with_limit() { + let grove_version = GroveVersion::latest(); // tree of height 4 // 5 chunks - let mut merk = TempMerk::new(); + let mut merk = TempMerk::new(grove_version); let batch = make_batch_seq(0..15); - merk.apply::<_, Vec<_>>(&batch, &[], None) + merk.apply::<_, Vec<_>>(&batch, &[], None, grove_version) .unwrap() .expect("apply failed"); assert_eq!(merk.height(), Some(4)); @@ -1001,7 +1067,8 @@ mod test { // ensure that the remaining limit, next index and values given are correct // if limit is smaller than first chunk, we should get an error - let chunk_result = chunk_producer.multi_chunk_with_limit(vec![].as_slice(), Some(5)); + let chunk_result = + chunk_producer.multi_chunk_with_limit(vec![].as_slice(), Some(5), grove_version); assert!(matches!( chunk_result, Err(Error::ChunkingError(ChunkError::LimitTooSmall(..))) @@ -1011,7 +1078,8 @@ mod test { // data size of chunk 2 is exactly 317 // chunk op encoding for chunk 2 = 321 // hence limit of 317 will be insufficient - let chunk_result = chunk_producer.multi_chunk_with_limit_and_index(2, Some(317)); + let chunk_result = + chunk_producer.multi_chunk_with_limit_and_index(2, Some(317), grove_version); assert!(matches!( chunk_result, Err(Error::ChunkingError(ChunkError::LimitTooSmall(..))) @@ -1022,7 +1090,7 @@ mod test { // chunk 3 chunk op = 321 // padding = 5 let chunk_result = chunk_producer - .multi_chunk_with_limit_and_index(2, Some(321 + 321 + 5)) + .multi_chunk_with_limit_and_index(2, Some(321 + 321 + 5), grove_version) .expect("should generate chunk"); assert_eq!( chunk_result.next_index, diff --git a/merk/src/merk/get.rs b/merk/src/merk/get.rs index 4f953d9f..f38b6fc7 100644 --- a/merk/src/merk/get.rs +++ b/merk/src/merk/get.rs @@ -1,5 +1,6 @@ use grovedb_costs::{CostContext, CostResult, CostsExt, OperationCost}; use grovedb_storage::StorageContext; +use grovedb_version::version::GroveVersion; use crate::{ tree::{kv::ValueDefinedCostType, TreeNode}, @@ -24,9 +25,12 @@ where pub fn exists( &self, key: &[u8], - value_defined_cost_fn: Option Option>, + value_defined_cost_fn: Option< + impl Fn(&[u8], &GroveVersion) -> Option, + >, + grove_version: &GroveVersion, ) -> CostResult { - self.has_node_direct(key, value_defined_cost_fn) + self.has_node_direct(key, value_defined_cost_fn, grove_version) } /// Returns if the value at the given key exists @@ -38,9 +42,12 @@ where pub fn exists_by_traversing_tree( &self, key: &[u8], - value_defined_cost_fn: Option Option>, + value_defined_cost_fn: Option< + impl Fn(&[u8], &GroveVersion) -> Option, + >, + grove_version: &GroveVersion, ) -> CostResult { - self.has_node(key, value_defined_cost_fn) + self.has_node(key, value_defined_cost_fn, grove_version) } /// Gets a value for the given key. If the key is not found, `None` is @@ -52,7 +59,10 @@ where &self, key: &[u8], allow_cache: bool, - value_defined_cost_fn: Option Option>, + value_defined_cost_fn: Option< + impl Fn(&[u8], &GroveVersion) -> Option, + >, + grove_version: &GroveVersion, ) -> CostResult>, Error> { if allow_cache { self.get_node_fn( @@ -63,6 +73,7 @@ where .wrap_with_cost(Default::default()) }, value_defined_cost_fn, + grove_version, ) } else { self.get_node_direct_fn( @@ -73,6 +84,7 @@ where .wrap_with_cost(Default::default()) }, value_defined_cost_fn, + grove_version, ) } } @@ -82,19 +94,24 @@ where &self, key: &[u8], allow_cache: bool, - value_defined_cost_fn: Option Option>, + value_defined_cost_fn: Option< + impl Fn(&[u8], &GroveVersion) -> Option, + >, + grove_version: &GroveVersion, ) -> CostResult, Error> { if allow_cache { self.get_node_fn( key, |node| node.feature_type().wrap_with_cost(Default::default()), value_defined_cost_fn, + grove_version, ) } else { self.get_node_direct_fn( key, |node| node.feature_type().wrap_with_cost(Default::default()), value_defined_cost_fn, + grove_version, ) } } @@ -105,12 +122,25 @@ where &self, key: &[u8], allow_cache: bool, - value_defined_cost_fn: Option Option>, + value_defined_cost_fn: Option< + impl Fn(&[u8], &GroveVersion) -> Option, + >, + grove_version: &GroveVersion, ) -> CostResult, Error> { if allow_cache { - self.get_node_fn(key, |node| node.hash(), value_defined_cost_fn) + self.get_node_fn( + key, + |node| node.hash(), + value_defined_cost_fn, + grove_version, + ) } else { - self.get_node_direct_fn(key, |node| node.hash(), value_defined_cost_fn) + self.get_node_direct_fn( + key, + |node| node.hash(), + value_defined_cost_fn, + grove_version, + ) } } @@ -120,19 +150,24 @@ where &self, key: &[u8], allow_cache: bool, - value_defined_cost_fn: Option Option>, + value_defined_cost_fn: Option< + impl Fn(&[u8], &GroveVersion) -> Option, + >, + grove_version: &GroveVersion, ) -> CostResult, Error> { if allow_cache { self.get_node_fn( key, |node| (*node.value_hash()).wrap_with_cost(OperationCost::default()), value_defined_cost_fn, + grove_version, ) } else { self.get_node_direct_fn( key, |node| (*node.value_hash()).wrap_with_cost(OperationCost::default()), value_defined_cost_fn, + grove_version, ) } } @@ -143,19 +178,24 @@ where &self, key: &[u8], allow_cache: bool, - value_defined_cost_fn: Option Option>, + value_defined_cost_fn: Option< + impl Fn(&[u8], &GroveVersion) -> Option, + >, + grove_version: &GroveVersion, ) -> CostResult, Error> { if allow_cache { self.get_node_fn( key, |node| (*node.inner.kv.hash()).wrap_with_cost(OperationCost::default()), value_defined_cost_fn, + grove_version, ) } else { self.get_node_direct_fn( key, |node| (*node.inner.kv.hash()).wrap_with_cost(OperationCost::default()), value_defined_cost_fn, + grove_version, ) } } @@ -166,7 +206,10 @@ where &self, key: &[u8], allow_cache: bool, - value_defined_cost_fn: Option Option>, + value_defined_cost_fn: Option< + impl Fn(&[u8], &GroveVersion) -> Option, + >, + grove_version: &GroveVersion, ) -> CostResult, CryptoHash)>, Error> { if allow_cache { self.get_node_fn( @@ -176,6 +219,7 @@ where .wrap_with_cost(OperationCost::default()) }, value_defined_cost_fn, + grove_version, ) } else { self.get_node_direct_fn( @@ -185,6 +229,7 @@ where .wrap_with_cost(OperationCost::default()) }, value_defined_cost_fn, + grove_version, ) } } @@ -193,16 +238,23 @@ where fn has_node_direct( &self, key: &[u8], - value_defined_cost_fn: Option Option>, + value_defined_cost_fn: Option< + impl Fn(&[u8], &GroveVersion) -> Option, + >, + grove_version: &GroveVersion, ) -> CostResult { - TreeNode::get(&self.storage, key, value_defined_cost_fn).map_ok(|x| x.is_some()) + TreeNode::get(&self.storage, key, value_defined_cost_fn, grove_version) + .map_ok(|x| x.is_some()) } /// See if a node's field exists fn has_node( &self, key: &[u8], - value_defined_cost_fn: Option Option>, + value_defined_cost_fn: Option< + impl Fn(&[u8], &GroveVersion) -> Option, + >, + grove_version: &GroveVersion, ) -> CostResult { self.use_tree(move |maybe_tree| { let mut cursor = match maybe_tree { @@ -225,7 +277,7 @@ where match maybe_child { None => { // fetch from RocksDB - break self.has_node_direct(key, value_defined_cost_fn); + break self.has_node_direct(key, value_defined_cost_fn, grove_version); } Some(child) => cursor = child, // traverse to child } @@ -238,15 +290,20 @@ where &self, key: &[u8], f: F, - value_defined_cost_fn: Option Option>, + value_defined_cost_fn: Option< + impl Fn(&[u8], &GroveVersion) -> Option, + >, + grove_version: &GroveVersion, ) -> CostResult, Error> where F: FnOnce(&TreeNode) -> CostContext, { - TreeNode::get(&self.storage, key, value_defined_cost_fn).flat_map_ok(|maybe_node| { - let mut cost = OperationCost::default(); - Ok(maybe_node.map(|node| f(&node).unwrap_add_cost(&mut cost))).wrap_with_cost(cost) - }) + TreeNode::get(&self.storage, key, value_defined_cost_fn, grove_version).flat_map_ok( + |maybe_node| { + let mut cost = OperationCost::default(); + Ok(maybe_node.map(|node| f(&node).unwrap_add_cost(&mut cost))).wrap_with_cost(cost) + }, + ) } /// Generic way to get a node's field @@ -254,7 +311,10 @@ where &self, key: &[u8], f: F, - value_defined_cost_fn: Option Option>, + value_defined_cost_fn: Option< + impl Fn(&[u8], &GroveVersion) -> Option, + >, + grove_version: &GroveVersion, ) -> CostResult, Error> where F: FnOnce(&TreeNode) -> CostContext, @@ -280,7 +340,12 @@ where match maybe_child { None => { // fetch from RocksDB - break self.get_node_direct_fn(key, f, value_defined_cost_fn); + break self.get_node_direct_fn( + key, + f, + value_defined_cost_fn, + grove_version, + ); } Some(child) => cursor = child, // traverse to child } @@ -291,18 +356,25 @@ where #[cfg(test)] mod test { + use grovedb_version::version::GroveVersion; + use crate::{ test_utils::TempMerk, tree::kv::ValueDefinedCostType, Op, TreeFeatureType::BasicMerkNode, }; #[test] fn test_has_node_with_empty_tree() { - let mut merk = TempMerk::new(); + let grove_version = GroveVersion::latest(); + let mut merk = TempMerk::new(grove_version); let key = b"something"; let result = merk - .has_node(key, None::<&fn(&[u8]) -> Option>) + .has_node( + key, + None::<&fn(&[u8], &GroveVersion) -> Option>, + grove_version, + ) .unwrap() .unwrap(); @@ -312,12 +384,16 @@ mod test { let batch = vec![batch_entry]; - merk.apply::<_, Vec<_>>(&batch, &[], None) + merk.apply::<_, Vec<_>>(&batch, &[], None, grove_version) .unwrap() .expect("should ..."); let result = merk - .has_node(key, None::<&fn(&[u8]) -> Option>) + .has_node( + key, + None::<&fn(&[u8], &GroveVersion) -> Option>, + grove_version, + ) .unwrap() .unwrap(); diff --git a/merk/src/merk/mod.rs b/merk/src/merk/mod.rs index e9bab4f7..ee0deccc 100644 --- a/merk/src/merk/mod.rs +++ b/merk/src/merk/mod.rs @@ -55,6 +55,7 @@ use grovedb_costs::{ CostResult, CostsExt, FeatureSumLength, OperationCost, }; use grovedb_storage::{self, Batch, RawIterator, StorageContext}; +use grovedb_version::version::GroveVersion; use source::MerkSource; use crate::{ @@ -524,7 +525,10 @@ where /// Meaning that it doesn't have a parent Merk pub(crate) fn load_base_root( &mut self, - value_defined_cost_fn: Option Option>, + value_defined_cost_fn: Option< + impl Fn(&[u8], &GroveVersion) -> Option, + >, + grove_version: &GroveVersion, ) -> CostResult<(), Error> { self.storage .get_root(ROOT_KEY_KEY) @@ -534,14 +538,18 @@ where if let Some(tree_root_key) = tree_root_key_opt { // Trying to build a tree out of it, costs will be accumulated because // `Tree::get` returns `CostContext` and this call happens inside `flat_map_ok`. - TreeNode::get(&self.storage, tree_root_key, value_defined_cost_fn).map_ok( - |tree| { - if let Some(t) = tree.as_ref() { - self.root_tree_key = Cell::new(Some(t.key().to_vec())); - } - self.tree = Cell::new(tree); - }, + TreeNode::get( + &self.storage, + tree_root_key, + value_defined_cost_fn, + grove_version, ) + .map_ok(|tree| { + if let Some(t) = tree.as_ref() { + self.root_tree_key = Cell::new(Some(t.key().to_vec())); + } + self.tree = Cell::new(tree); + }) } else { Ok(()).wrap_with_cost(Default::default()) } @@ -553,13 +561,22 @@ where /// Meaning that it doesn't have a parent Merk pub(crate) fn load_root( &mut self, - value_defined_cost_fn: Option Option>, + value_defined_cost_fn: Option< + impl Fn(&[u8], &GroveVersion) -> Option, + >, + grove_version: &GroveVersion, ) -> CostResult<(), Error> { // In case of successful seek for root key check if it exists if let Some(tree_root_key) = self.root_tree_key.get_mut() { // Trying to build a tree out of it, costs will be accumulated because // `Tree::get` returns `CostContext` and this call happens inside `flat_map_ok`. - TreeNode::get(&self.storage, tree_root_key, value_defined_cost_fn).map_ok(|tree| { + TreeNode::get( + &self.storage, + tree_root_key, + value_defined_cost_fn, + grove_version, + ) + .map_ok(|tree| { self.tree = Cell::new(tree); }) } else { @@ -575,6 +592,7 @@ where pub fn verify( &self, skip_sum_checks: bool, + grove_version: &GroveVersion, ) -> (BTreeMap, CryptoHash>, BTreeMap, Vec>) { let tree = self.tree.take(); @@ -590,6 +608,7 @@ where &mut bad_link_map, &mut parent_keys, skip_sum_checks, + grove_version, ); self.tree.set(tree); @@ -603,6 +622,7 @@ where bad_link_map: &mut BTreeMap, CryptoHash>, parent_keys: &mut BTreeMap, Vec>, skip_sum_checks: bool, + grove_version: &GroveVersion, ) { if let Some(link) = tree.link(LEFT) { traversal_instruction.push(LEFT); @@ -613,6 +633,7 @@ where bad_link_map, parent_keys, skip_sum_checks, + grove_version, ); traversal_instruction.pop(); } @@ -626,6 +647,7 @@ where bad_link_map, parent_keys, skip_sum_checks, + grove_version, ); traversal_instruction.pop(); } @@ -639,6 +661,7 @@ where bad_link_map: &mut BTreeMap, CryptoHash>, parent_keys: &mut BTreeMap, Vec>, skip_sum_checks: bool, + grove_version: &GroveVersion, ) { let (hash, key, sum) = match link { Link::Reference { hash, key, sum, .. } => { @@ -662,7 +685,8 @@ where let node = TreeNode::get( &self.storage, key, - None::<&fn(&[u8]) -> Option>, + None::<&fn(&[u8], &GroveVersion) -> Option>, + grove_version, ) .unwrap(); @@ -701,6 +725,7 @@ where bad_link_map, parent_keys, skip_sum_checks, + grove_version, ); } } @@ -708,12 +733,14 @@ where fn fetch_node<'db>( db: &impl StorageContext<'db>, key: &[u8], - value_defined_cost_fn: Option Option>, + value_defined_cost_fn: Option Option>, + grove_version: &GroveVersion, ) -> Result, Error> { let bytes = db.get(key).unwrap().map_err(StorageError)?; // TODO: get_pinned ? if let Some(bytes) = bytes { Ok(Some( - TreeNode::decode(key.to_vec(), &bytes, value_defined_cost_fn).map_err(EdError)?, + TreeNode::decode(key.to_vec(), &bytes, value_defined_cost_fn, grove_version) + .map_err(EdError)?, )) } else { Ok(None) @@ -730,6 +757,7 @@ mod test { rocksdb_storage::{PrefixedRocksDbStorageContext, RocksDbStorage}, RawIterator, Storage, StorageBatch, StorageContext, }; + use grovedb_version::version::GroveVersion; use tempfile::TempDir; use super::{Merk, RefWalker}; @@ -749,10 +777,11 @@ mod test { #[test] fn simple_insert_apply() { + let grove_version = GroveVersion::latest(); let batch_size = 20; - let mut merk = TempMerk::new(); + let mut merk = TempMerk::new(grove_version); let batch = make_batch_seq(0..batch_size); - merk.apply::<_, Vec<_>>(&batch, &[], None) + merk.apply::<_, Vec<_>>(&batch, &[], None, grove_version) .unwrap() .expect("apply failed"); @@ -768,34 +797,35 @@ mod test { #[test] fn tree_height() { - let mut merk = TempMerk::new(); + let grove_version = GroveVersion::latest(); + let mut merk = TempMerk::new(grove_version); let batch = make_batch_seq(0..1); - merk.apply::<_, Vec<_>>(&batch, &[], None) + merk.apply::<_, Vec<_>>(&batch, &[], None, grove_version) .unwrap() .expect("apply failed"); assert_eq!(merk.height(), Some(1)); // height 2 - let mut merk = TempMerk::new(); + let mut merk = TempMerk::new(grove_version); let batch = make_batch_seq(0..2); - merk.apply::<_, Vec<_>>(&batch, &[], None) + merk.apply::<_, Vec<_>>(&batch, &[], None, grove_version) .unwrap() .expect("apply failed"); assert_eq!(merk.height(), Some(2)); // height 5 // 2^5 - 1 = 31 (max number of elements in tree of height 5) - let mut merk = TempMerk::new(); + let mut merk = TempMerk::new(grove_version); let batch = make_batch_seq(0..31); - merk.apply::<_, Vec<_>>(&batch, &[], None) + merk.apply::<_, Vec<_>>(&batch, &[], None, grove_version) .unwrap() .expect("apply failed"); assert_eq!(merk.height(), Some(5)); // should still be height 5 for 29 elements - let mut merk = TempMerk::new(); + let mut merk = TempMerk::new(grove_version); let batch = make_batch_seq(0..29); - merk.apply::<_, Vec<_>>(&batch, &[], None) + merk.apply::<_, Vec<_>>(&batch, &[], None, grove_version) .unwrap() .expect("apply failed"); assert_eq!(merk.height(), Some(5)); @@ -803,17 +833,18 @@ mod test { #[test] fn insert_uncached() { + let grove_version = GroveVersion::latest(); let batch_size = 20; - let mut merk = TempMerk::new(); + let mut merk = TempMerk::new(grove_version); let batch = make_batch_seq(0..batch_size); - merk.apply::<_, Vec<_>>(&batch, &[], None) + merk.apply::<_, Vec<_>>(&batch, &[], None, grove_version) .unwrap() .expect("apply failed"); assert_invariants(&merk); let batch = make_batch_seq(batch_size..(batch_size * 2)); - merk.apply::<_, Vec<_>>(&batch, &[], None) + merk.apply::<_, Vec<_>>(&batch, &[], None, grove_version) .unwrap() .expect("apply failed"); assert_invariants(&merk); @@ -821,13 +852,14 @@ mod test { #[test] fn insert_two() { + let grove_version = GroveVersion::latest(); let tree_size = 2; let batch_size = 1; - let mut merk = TempMerk::new(); + let mut merk = TempMerk::new(grove_version); for i in 0..(tree_size / batch_size) { let batch = make_batch_rand(batch_size, i); - merk.apply::<_, Vec<_>>(&batch, &[], None) + merk.apply::<_, Vec<_>>(&batch, &[], None, grove_version) .unwrap() .expect("apply failed"); } @@ -835,14 +867,15 @@ mod test { #[test] fn insert_rand() { + let grove_version = GroveVersion::latest(); let tree_size = 40; let batch_size = 4; - let mut merk = TempMerk::new(); + let mut merk = TempMerk::new(grove_version); for i in 0..(tree_size / batch_size) { println!("i:{i}"); let batch = make_batch_rand(batch_size, i); - merk.apply::<_, Vec<_>>(&batch, &[], None) + merk.apply::<_, Vec<_>>(&batch, &[], None, grove_version) .unwrap() .expect("apply failed"); } @@ -850,15 +883,16 @@ mod test { #[test] fn actual_deletes() { - let mut merk = TempMerk::new(); + let grove_version = GroveVersion::latest(); + let mut merk = TempMerk::new(grove_version); let batch = make_batch_rand(10, 1); - merk.apply::<_, Vec<_>>(&batch, &[], None) + merk.apply::<_, Vec<_>>(&batch, &[], None, grove_version) .unwrap() .expect("apply failed"); let key = batch.first().unwrap().0.clone(); - merk.apply::<_, Vec<_>>(&[(key.clone(), Op::Delete)], &[], None) + merk.apply::<_, Vec<_>>(&[(key.clone(), Op::Delete)], &[], None, grove_version) .unwrap() .unwrap(); @@ -868,15 +902,17 @@ mod test { #[test] fn aux_data() { - let mut merk = TempMerk::new(); + let grove_version = GroveVersion::latest(); + let mut merk = TempMerk::new(grove_version); merk.apply::, _>( &[], &[(vec![1, 2, 3], Op::Put(vec![4, 5, 6], BasicMerkNode), None)], None, + grove_version, ) .unwrap() .expect("apply failed"); - merk.commit(); + merk.commit(grove_version); let val = merk.get_aux(&[1, 2, 3]).unwrap().unwrap(); assert_eq!(val, Some(vec![4, 5, 6])); @@ -884,14 +920,16 @@ mod test { #[test] fn get_not_found() { - let mut merk = TempMerk::new(); + let grove_version = GroveVersion::latest(); + let mut merk = TempMerk::new(grove_version); // no root assert!(merk .get( &[1, 2, 3], true, - None::<&fn(&[u8]) -> Option> + None::<&fn(&[u8], &GroveVersion) -> Option>, + grove_version ) .unwrap() .unwrap() @@ -902,6 +940,7 @@ mod test { &[(vec![5, 5, 5], Op::Put(vec![], BasicMerkNode))], &[], None, + grove_version, ) .unwrap() .unwrap(); @@ -909,7 +948,8 @@ mod test { .get( &[1, 2, 3], true, - None::<&fn(&[u8]) -> Option> + None::<&fn(&[u8], &GroveVersion) -> Option>, + grove_version ) .unwrap() .unwrap() @@ -924,6 +964,7 @@ mod test { ], &[], None, + grove_version, ) .unwrap() .unwrap(); @@ -931,7 +972,8 @@ mod test { .get( &[3, 3, 3], true, - None::<&fn(&[u8]) -> Option> + None::<&fn(&[u8], &GroveVersion) -> Option>, + grove_version ) .unwrap() .unwrap() @@ -941,6 +983,7 @@ mod test { // TODO: what this test should do? #[test] fn reopen_check_root_hash() { + let grove_version = GroveVersion::latest(); let tmp_dir = TempDir::new().expect("cannot open tempdir"); let storage = RocksDbStorage::default_rocksdb_with_path(tmp_dir.path()) .expect("cannot open rocksdb storage"); @@ -949,22 +992,24 @@ mod test { .get_storage_context(SubtreePath::empty(), None) .unwrap(), false, - None::<&fn(&[u8]) -> Option>, + None::<&fn(&[u8], &GroveVersion) -> Option>, + grove_version, ) .unwrap() .expect("cannot open merk"); let batch = make_batch_seq(1..10); - merk.apply::<_, Vec<_>>(batch.as_slice(), &[], None) + merk.apply::<_, Vec<_>>(batch.as_slice(), &[], None, grove_version) .unwrap() .unwrap(); let batch = make_batch_seq(11..12); - merk.apply::<_, Vec<_>>(batch.as_slice(), &[], None) + merk.apply::<_, Vec<_>>(batch.as_slice(), &[], None, grove_version) .unwrap() .unwrap(); } #[test] fn test_get_node_cost() { + let grove_version = GroveVersion::latest(); let tmp_dir = TempDir::new().expect("cannot open tempdir"); let storage = RocksDbStorage::default_rocksdb_with_path(tmp_dir.path()) .expect("cannot open rocksdb storage"); @@ -973,12 +1018,13 @@ mod test { .get_storage_context(SubtreePath::empty(), None) .unwrap(), false, - None::<&fn(&[u8]) -> Option>, + None::<&fn(&[u8], &GroveVersion) -> Option>, + grove_version, ) .unwrap() .expect("cannot open merk"); let batch = make_batch_seq(1..10); - merk.apply::<_, Vec<_>>(batch.as_slice(), &[], None) + merk.apply::<_, Vec<_>>(batch.as_slice(), &[], None, grove_version) .unwrap() .unwrap(); drop(merk); @@ -986,20 +1032,30 @@ mod test { #[test] fn reopen() { + let grove_version = GroveVersion::latest(); fn collect( mut node: RefWalker>, nodes: &mut Vec>, ) { + let grove_version = GroveVersion::latest(); nodes.push(node.tree().encode()); if let Some(c) = node - .walk(true, None::<&fn(&[u8]) -> Option>) + .walk( + true, + None::<&fn(&[u8], &GroveVersion) -> Option>, + grove_version, + ) .unwrap() .unwrap() { collect(c, nodes); } if let Some(c) = node - .walk(false, None::<&fn(&[u8]) -> Option>) + .walk( + false, + None::<&fn(&[u8], &GroveVersion) -> Option>, + grove_version, + ) .unwrap() .unwrap() { @@ -1018,12 +1074,13 @@ mod test { .get_storage_context(SubtreePath::empty(), Some(&batch)) .unwrap(), false, - None::<&fn(&[u8]) -> Option>, + None::<&fn(&[u8], &GroveVersion) -> Option>, + grove_version, ) .unwrap() .expect("cannot open merk"); let merk_batch = make_batch_seq(1..10_000); - merk.apply::<_, Vec<_>>(merk_batch.as_slice(), &[], None) + merk.apply::<_, Vec<_>>(merk_batch.as_slice(), &[], None, grove_version) .unwrap() .unwrap(); @@ -1036,7 +1093,8 @@ mod test { .get_storage_context(SubtreePath::empty(), None) .unwrap(), false, - None::<&fn(&[u8]) -> Option>, + None::<&fn(&[u8], &GroveVersion) -> Option>, + grove_version, ) .unwrap() .expect("cannot open merk"); @@ -1056,7 +1114,8 @@ mod test { .get_storage_context(SubtreePath::empty(), None) .unwrap(), false, - None::<&fn(&[u8]) -> Option>, + None::<&fn(&[u8], &GroveVersion) -> Option>, + grove_version, ) .unwrap() .expect("cannot open merk"); @@ -1074,6 +1133,7 @@ mod test { #[test] fn reopen_iter() { + let grove_version = GroveVersion::latest(); fn collect(iter: PrefixedStorageIter<'_, '_>, nodes: &mut Vec<(Vec, Vec)>) { while iter.valid().unwrap() { nodes.push(( @@ -1094,12 +1154,13 @@ mod test { .get_storage_context(SubtreePath::empty(), Some(&batch)) .unwrap(), false, - None::<&fn(&[u8]) -> Option>, + None::<&fn(&[u8], &GroveVersion) -> Option>, + grove_version, ) .unwrap() .expect("cannot open merk"); let merk_batch = make_batch_seq(1..10_000); - merk.apply::<_, Vec<_>>(merk_batch.as_slice(), &[], None) + merk.apply::<_, Vec<_>>(merk_batch.as_slice(), &[], None, grove_version) .unwrap() .unwrap(); @@ -1114,7 +1175,8 @@ mod test { .get_storage_context(SubtreePath::empty(), None) .unwrap(), false, - None::<&fn(&[u8]) -> Option>, + None::<&fn(&[u8], &GroveVersion) -> Option>, + grove_version, ) .unwrap() .expect("cannot open merk"); @@ -1128,7 +1190,8 @@ mod test { .get_storage_context(SubtreePath::empty(), None) .unwrap(), false, - None::<&fn(&[u8]) -> Option>, + None::<&fn(&[u8], &GroveVersion) -> Option>, + grove_version, ) .unwrap() .expect("cannot open merk"); @@ -1141,6 +1204,7 @@ mod test { #[test] fn update_node() { + let grove_version = GroveVersion::latest(); let tmp_dir = TempDir::new().expect("cannot open tempdir"); let storage = RocksDbStorage::default_rocksdb_with_path(tmp_dir.path()) .expect("cannot open rocksdb storage"); @@ -1150,7 +1214,8 @@ mod test { .get_storage_context(SubtreePath::empty(), Some(&batch)) .unwrap(), false, - None::<&fn(&[u8]) -> Option>, + None::<&fn(&[u8], &GroveVersion) -> Option>, + grove_version, ) .unwrap() .expect("cannot open merk"); @@ -1159,6 +1224,7 @@ mod test { &[(b"9".to_vec(), Op::Put(b"a".to_vec(), BasicMerkNode))], &[], None, + grove_version, ) .unwrap() .expect("should insert successfully"); @@ -1166,6 +1232,7 @@ mod test { &[(b"10".to_vec(), Op::Put(b"a".to_vec(), BasicMerkNode))], &[], None, + grove_version, ) .unwrap() .expect("should insert successfully"); @@ -1174,7 +1241,8 @@ mod test { .get( b"10".as_slice(), true, - None::<&fn(&[u8]) -> Option>, + None::<&fn(&[u8], &GroveVersion) -> Option>, + grove_version, ) .unwrap() .expect("should get successfully"); @@ -1185,6 +1253,7 @@ mod test { &[(b"10".to_vec(), Op::Put(b"b".to_vec(), BasicMerkNode))], &[], None, + grove_version, ) .unwrap() .expect("should insert successfully"); @@ -1192,7 +1261,8 @@ mod test { .get( b"10".as_slice(), true, - None::<&fn(&[u8]) -> Option>, + None::<&fn(&[u8], &GroveVersion) -> Option>, + grove_version, ) .unwrap() .expect("should get successfully"); @@ -1208,7 +1278,8 @@ mod test { .get_storage_context(SubtreePath::empty(), None) .unwrap(), false, - None::<&fn(&[u8]) -> Option>, + None::<&fn(&[u8], &GroveVersion) -> Option>, + grove_version, ) .unwrap() .expect("cannot open merk"); @@ -1218,6 +1289,7 @@ mod test { &[(b"10".to_vec(), Op::Put(b"c".to_vec(), BasicMerkNode))], &[], None, + grove_version, ) .unwrap() .expect("should insert successfully"); @@ -1225,7 +1297,8 @@ mod test { .get( b"10".as_slice(), true, - None::<&fn(&[u8]) -> Option>, + None::<&fn(&[u8], &GroveVersion) -> Option>, + grove_version, ) .unwrap() .expect("should get successfully"); diff --git a/merk/src/merk/open.rs b/merk/src/merk/open.rs index af15d596..c8646afa 100644 --- a/merk/src/merk/open.rs +++ b/merk/src/merk/open.rs @@ -2,6 +2,7 @@ use std::cell::Cell; use grovedb_costs::CostResult; use grovedb_storage::StorageContext; +use grovedb_version::version::GroveVersion; use crate::{ tree::kv::ValueDefinedCostType, @@ -28,7 +29,10 @@ where pub fn open_standalone( storage: S, is_sum_tree: bool, - value_defined_cost_fn: Option Option>, + value_defined_cost_fn: Option< + impl Fn(&[u8], &GroveVersion) -> Option, + >, + grove_version: &GroveVersion, ) -> CostResult { let mut merk = Self { tree: Cell::new(None), @@ -38,14 +42,18 @@ where is_sum_tree, }; - merk.load_base_root(value_defined_cost_fn).map_ok(|_| merk) + merk.load_base_root(value_defined_cost_fn, grove_version) + .map_ok(|_| merk) } /// Open base tree pub fn open_base( storage: S, is_sum_tree: bool, - value_defined_cost_fn: Option Option>, + value_defined_cost_fn: Option< + impl Fn(&[u8], &GroveVersion) -> Option, + >, + grove_version: &GroveVersion, ) -> CostResult { let mut merk = Self { tree: Cell::new(None), @@ -55,7 +63,8 @@ where is_sum_tree, }; - merk.load_base_root(value_defined_cost_fn).map_ok(|_| merk) + merk.load_base_root(value_defined_cost_fn, grove_version) + .map_ok(|_| merk) } /// Open layered tree with root key @@ -63,7 +72,10 @@ where storage: S, root_key: Option>, is_sum_tree: bool, - value_defined_cost_fn: Option Option>, + value_defined_cost_fn: Option< + impl Fn(&[u8], &GroveVersion) -> Option, + >, + grove_version: &GroveVersion, ) -> CostResult { let mut merk = Self { tree: Cell::new(None), @@ -73,7 +85,8 @@ where is_sum_tree, }; - merk.load_root(value_defined_cost_fn).map_ok(|_| merk) + merk.load_root(value_defined_cost_fn, grove_version) + .map_ok(|_| merk) } } @@ -85,12 +98,14 @@ mod test { rocksdb_storage::{test_utils::TempStorage, RocksDbStorage}, Storage, StorageBatch, }; + use grovedb_version::version::GroveVersion; use tempfile::TempDir; use crate::{tree::kv::ValueDefinedCostType, Merk, Op, TreeFeatureType::BasicMerkNode}; #[test] fn test_reopen_root_hash() { + let grove_version = GroveVersion::latest(); let tmp_dir = TempDir::new().expect("cannot open tempdir"); let storage = RocksDbStorage::default_rocksdb_with_path(tmp_dir.path()) .expect("cannot open rocksdb storage"); @@ -102,7 +117,8 @@ mod test { .get_storage_context(SubtreePath::from(test_prefix.as_ref()), Some(&batch)) .unwrap(), false, - None::<&fn(&[u8]) -> Option>, + None::<&fn(&[u8], &GroveVersion) -> Option>, + grove_version, ) .unwrap() .unwrap(); @@ -111,6 +127,7 @@ mod test { &[(vec![1, 2, 3], Op::Put(vec![4, 5, 6], BasicMerkNode))], &[], None, + grove_version, ) .unwrap() .expect("apply failed"); @@ -127,7 +144,8 @@ mod test { .get_storage_context(SubtreePath::from(test_prefix.as_ref()), None) .unwrap(), false, - None::<&fn(&[u8]) -> Option>, + None::<&fn(&[u8], &GroveVersion) -> Option>, + grove_version, ) .unwrap() .unwrap(); @@ -136,6 +154,7 @@ mod test { #[test] fn test_open_fee() { + let grove_version = GroveVersion::latest(); let storage = TempStorage::new(); let batch = StorageBatch::new(); @@ -144,7 +163,8 @@ mod test { .get_storage_context(SubtreePath::empty(), Some(&batch)) .unwrap(), false, - None::<&fn(&[u8]) -> Option>, + None::<&fn(&[u8], &GroveVersion) -> Option>, + grove_version, ); // Opening not existing merk should cost only root key seek (except context // creation) @@ -158,6 +178,7 @@ mod test { &[(vec![1, 2, 3], Op::Put(vec![4, 5, 6], BasicMerkNode))], &[], None, + grove_version, ) .unwrap() .expect("apply failed"); @@ -172,7 +193,8 @@ mod test { .get_storage_context(SubtreePath::empty(), None) .unwrap(), false, - None::<&fn(&[u8]) -> Option>, + None::<&fn(&[u8], &GroveVersion) -> Option>, + grove_version, ); // Opening existing merk should cost two seeks. (except context creation) diff --git a/merk/src/merk/prove.rs b/merk/src/merk/prove.rs index 99227c13..a92f28fb 100644 --- a/merk/src/merk/prove.rs +++ b/merk/src/merk/prove.rs @@ -2,6 +2,7 @@ use std::collections::LinkedList; use grovedb_costs::{CostResult, CostsExt}; use grovedb_storage::StorageContext; +use grovedb_version::version::GroveVersion; use crate::{ proofs::{encode_into, query::QueryItem, Op as ProofOp, Query}, @@ -29,9 +30,10 @@ where &self, query: Query, limit: Option, + grove_version: &GroveVersion, ) -> CostResult { let left_to_right = query.left_to_right; - self.prove_unchecked(query, limit, left_to_right) + self.prove_unchecked(query, limit, left_to_right, grove_version) .map_ok(|(proof, limit)| { let mut bytes = Vec::with_capacity(128); encode_into(proof.iter(), &mut bytes); @@ -54,9 +56,10 @@ where &self, query: Query, limit: Option, + grove_version: &GroveVersion, ) -> CostResult { let left_to_right = query.left_to_right; - self.prove_unchecked(query, limit, left_to_right) + self.prove_unchecked(query, limit, left_to_right, grove_version) .map_ok(|(proof, limit)| ProofWithoutEncodingResult::new(proof, limit)) } @@ -77,6 +80,7 @@ where query: I, limit: Option, left_to_right: bool, + grove_version: &GroveVersion, ) -> CostResult where Q: Into, @@ -92,7 +96,12 @@ where .wrap_with_cost(Default::default()) .flat_map_ok(|tree| { let mut ref_walker = RefWalker::new(tree, self.source()); - ref_walker.create_proof(query_vec.as_slice(), limit, left_to_right) + ref_walker.create_proof( + query_vec.as_slice(), + limit, + left_to_right, + grove_version, + ) }) .map_ok(|(proof, _, limit, ..)| (proof, limit)) }) @@ -115,6 +124,7 @@ where query_items: &[QueryItem], limit: Option, left_to_right: bool, + grove_version: &GroveVersion, ) -> CostResult { self.use_tree_mut(|maybe_tree| { maybe_tree @@ -124,7 +134,7 @@ where .wrap_with_cost(Default::default()) .flat_map_ok(|tree| { let mut ref_walker = RefWalker::new(tree, self.source()); - ref_walker.create_proof(query_items, limit, left_to_right) + ref_walker.create_proof(query_items, limit, left_to_right, grove_version) }) .map_ok(|(proof, _, limit, ..)| (proof, limit)) }) diff --git a/merk/src/merk/restore.rs b/merk/src/merk/restore.rs index c5ce1286..1082e80b 100644 --- a/merk/src/merk/restore.rs +++ b/merk/src/merk/restore.rs @@ -32,6 +32,7 @@ use std::collections::BTreeMap; use grovedb_storage::{Batch, StorageContext}; +use grovedb_version::version::GroveVersion; use crate::{ merk, @@ -87,6 +88,7 @@ impl<'db, S: StorageContext<'db>> Restorer { &mut self, chunk_id: &[u8], chunk: Vec, + grove_version: &GroveVersion, ) -> Result>, Error> { let expected_root_hash = self .chunk_id_to_root_hash @@ -106,7 +108,12 @@ impl<'db, S: StorageContext<'db>> Restorer { } else { // every non root chunk has some associated parent with an placeholder link // here we update the placeholder link to represent the true data - self.rewrite_parent_link(chunk_id, &root_traversal_instruction, &chunk_tree)?; + self.rewrite_parent_link( + chunk_id, + &root_traversal_instruction, + &chunk_tree, + grove_version, + )?; } // next up, we need to write the chunk and build the map again @@ -125,6 +132,7 @@ impl<'db, S: StorageContext<'db>> Restorer { pub fn process_multi_chunk( &mut self, multi_chunk: Vec, + grove_version: &GroveVersion, ) -> Result>, Error> { let mut expect_chunk_id = true; let mut chunk_ids = vec![]; @@ -144,7 +152,8 @@ impl<'db, S: StorageContext<'db>> Restorer { } ChunkOp::Chunk(chunk) => { // TODO: remove clone - let next_chunk_ids = self.process_chunk(¤t_chunk_id, chunk)?; + let next_chunk_ids = + self.process_chunk(¤t_chunk_id, chunk, grove_version)?; chunk_ids.extend(next_chunk_ids); } } @@ -282,6 +291,7 @@ impl<'db, S: StorageContext<'db>> Restorer { chunk_id: &[u8], traversal_instruction: &[bool], chunk_tree: &ProofTree, + grove_version: &GroveVersion, ) -> Result<(), Error> { let parent_key = self .parent_keys @@ -293,7 +303,8 @@ impl<'db, S: StorageContext<'db>> Restorer { let mut parent = merk::fetch_node( &self.merk.storage, parent_key.as_slice(), - None::<&fn(&[u8]) -> Option>, + None::<&fn(&[u8], &GroveVersion) -> Option>, + grove_version, )? .ok_or(Error::ChunkRestoringError(InternalError( "cannot find expected parent in memory, most likely state corruption issue", @@ -328,16 +339,18 @@ impl<'db, S: StorageContext<'db>> Restorer { /// Each nodes height is not added to state as such the producer could lie /// about the height values after replication we need to verify the /// heights and if invalid recompute the correct values - fn rewrite_heights(&mut self) -> Result<(), Error> { + fn rewrite_heights(&mut self, grove_version: &GroveVersion) -> Result<(), Error> { fn rewrite_child_heights<'s, 'db, S: StorageContext<'db>>( mut walker: RefWalker>, batch: &mut >::Batch, + grove_version: &GroveVersion, ) -> Result<(u8, u8), Error> { // TODO: remove unwrap let mut cloned_node = TreeNode::decode( walker.tree().key().to_vec(), walker.tree().encode().as_slice(), - None::<&fn(&[u8]) -> Option>, + None::<&fn(&[u8], &GroveVersion) -> Option>, + grove_version, ) .unwrap(); @@ -345,19 +358,28 @@ impl<'db, S: StorageContext<'db>> Restorer { let mut right_height = 0; if let Some(left_walker) = walker - .walk(LEFT, None::<&fn(&[u8]) -> Option>) + .walk( + LEFT, + None::<&fn(&[u8], &GroveVersion) -> Option>, + grove_version, + ) .unwrap()? { - let left_child_heights = rewrite_child_heights(left_walker, batch)?; + let left_child_heights = rewrite_child_heights(left_walker, batch, grove_version)?; left_height = left_child_heights.0.max(left_child_heights.1) + 1; *cloned_node.link_mut(LEFT).unwrap().child_heights_mut() = left_child_heights; } if let Some(right_walker) = walker - .walk(RIGHT, None::<&fn(&[u8]) -> Option>) + .walk( + RIGHT, + None::<&fn(&[u8], &GroveVersion) -> Option>, + grove_version, + ) .unwrap()? { - let right_child_heights = rewrite_child_heights(right_walker, batch)?; + let right_child_heights = + rewrite_child_heights(right_walker, batch, grove_version)?; right_height = right_child_heights.0.max(right_child_heights.1) + 1; *cloned_node.link_mut(RIGHT).unwrap().child_heights_mut() = right_child_heights; } @@ -375,7 +397,7 @@ impl<'db, S: StorageContext<'db>> Restorer { let mut tree = self.merk.tree.take().unwrap(); let walker = RefWalker::new(&mut tree, self.merk.source()); - rewrite_child_heights(walker, &mut batch)?; + rewrite_child_heights(walker, &mut batch, grove_version)?; self.merk.tree.set(Some(tree)); @@ -387,9 +409,9 @@ impl<'db, S: StorageContext<'db>> Restorer { } /// Rebuild restoration state from partial storage state - fn attempt_state_recovery(&mut self) -> Result<(), Error> { + fn attempt_state_recovery(&mut self, grove_version: &GroveVersion) -> Result<(), Error> { // TODO: think about the return type some more - let (bad_link_map, parent_keys) = self.merk.verify(false); + let (bad_link_map, parent_keys) = self.merk.verify(false, grove_version); if !bad_link_map.is_empty() { self.chunk_id_to_root_hash = bad_link_map; self.parent_keys = parent_keys; @@ -401,7 +423,7 @@ impl<'db, S: StorageContext<'db>> Restorer { /// Consumes the `Restorer` and returns a newly created, fully populated /// Merk instance. This method will return an error if called before /// processing all chunks. - pub fn finalize(mut self) -> Result, Error> { + pub fn finalize(mut self, grove_version: &GroveVersion) -> Result, Error> { // ensure all chunks have been processed if !self.chunk_id_to_root_hash.is_empty() || !self.parent_keys.is_empty() { return Err(Error::ChunkRestoringError( @@ -410,20 +432,27 @@ impl<'db, S: StorageContext<'db>> Restorer { } // get the latest version of the root node - let _ = self - .merk - .load_base_root(None::<&fn(&[u8]) -> Option>); + let _ = self.merk.load_base_root( + None::<&fn(&[u8], &GroveVersion) -> Option>, + grove_version, + ); // if height values are wrong, rewrite height - if self.verify_height().is_err() { - let _ = self.rewrite_heights(); + if self.verify_height(grove_version).is_err() { + let _ = self.rewrite_heights(grove_version); // update the root node after height rewrite - let _ = self - .merk - .load_base_root(None::<&fn(&[u8]) -> Option>); + let _ = self.merk.load_base_root( + None::<&fn(&[u8], &GroveVersion) -> Option>, + grove_version, + ); } - if !self.merk.verify(self.merk.is_sum_tree).0.is_empty() { + if !self + .merk + .verify(self.merk.is_sum_tree, grove_version) + .0 + .is_empty() + { return Err(Error::ChunkRestoringError(ChunkError::InternalError( "restored tree invalid", ))); @@ -434,10 +463,10 @@ impl<'db, S: StorageContext<'db>> Restorer { /// Verify that the child heights of the merk tree links correctly represent /// the tree - fn verify_height(&self) -> Result<(), Error> { + fn verify_height(&self, grove_version: &GroveVersion) -> Result<(), Error> { let tree = self.merk.tree.take(); let height_verification_result = if let Some(tree) = &tree { - self.verify_tree_height(tree, tree.height()) + self.verify_tree_height(tree, tree.height(), grove_version) } else { Ok(()) }; @@ -445,7 +474,12 @@ impl<'db, S: StorageContext<'db>> Restorer { height_verification_result } - fn verify_tree_height(&self, tree: &TreeNode, parent_height: u8) -> Result<(), Error> { + fn verify_tree_height( + &self, + tree: &TreeNode, + parent_height: u8, + grove_version: &GroveVersion, + ) -> Result<(), Error> { let (left_height, right_height) = tree.child_heights(); if (left_height.abs_diff(right_height)) > 1 { @@ -477,13 +511,14 @@ impl<'db, S: StorageContext<'db>> Restorer { let left_tree = TreeNode::get( &self.merk.storage, link.key(), - None::<&fn(&[u8]) -> Option>, + None::<&fn(&[u8], &GroveVersion) -> Option>, + grove_version, ) .unwrap()? .ok_or(Error::CorruptedState("link points to non-existent node"))?; - self.verify_tree_height(&left_tree, left_height)?; + self.verify_tree_height(&left_tree, left_height, grove_version)?; } else { - self.verify_tree_height(left_tree.unwrap(), left_height)?; + self.verify_tree_height(left_tree.unwrap(), left_height, grove_version)?; } } @@ -493,13 +528,14 @@ impl<'db, S: StorageContext<'db>> Restorer { let right_tree = TreeNode::get( &self.merk.storage, link.key(), - None::<&fn(&[u8]) -> Option>, + None::<&fn(&[u8], &GroveVersion) -> Option>, + grove_version, ) .unwrap()? .ok_or(Error::CorruptedState("link points to non-existent node"))?; - self.verify_tree_height(&right_tree, right_height)?; + self.verify_tree_height(&right_tree, right_height, grove_version)?; } else { - self.verify_tree_height(right_tree.unwrap(), right_height)?; + self.verify_tree_height(right_tree.unwrap(), right_height, grove_version)?; } } @@ -628,9 +664,10 @@ mod tests { #[test] fn test_process_chunk_correct_chunk_id_map() { - let mut merk = TempMerk::new(); + let grove_version = GroveVersion::latest(); + let mut merk = TempMerk::new(grove_version); let batch = make_batch_seq(0..15); - merk.apply::<_, Vec<_>>(&batch, &[], None) + merk.apply::<_, Vec<_>>(&batch, &[], None, grove_version) .unwrap() .expect("apply failed"); assert_eq!(merk.height(), Some(4)); @@ -646,7 +683,8 @@ mod tests { .get_immediate_storage_context(SubtreePath::empty(), &tx) .unwrap(), false, - None::<&fn(&[u8]) -> Option>, + None::<&fn(&[u8], &GroveVersion) -> Option>, + grove_version, ) .unwrap() .unwrap(); @@ -671,12 +709,13 @@ mod tests { ); // generate first chunk - let (chunk, _) = chunk_producer.chunk_with_index(1).unwrap(); + let (chunk, _) = chunk_producer.chunk_with_index(1, grove_version).unwrap(); // apply first chunk let new_chunk_ids = restorer .process_chunk( &traversal_instruction_as_vec_bytes(vec![].as_slice()), chunk, + grove_version, ) .expect("should process chunk successfully"); assert_eq!(new_chunk_ids.len(), 4); @@ -687,30 +726,62 @@ mod tests { // assert all the chunk hash values assert_eq!( restorer.chunk_id_to_root_hash.get(vec![1, 1].as_slice()), - Some(get_node_hash(traverse_get_node_hash(&mut tree_walker, &[LEFT, LEFT])).unwrap()) - .as_ref() + Some( + get_node_hash(traverse_get_node_hash( + &mut tree_walker, + &[LEFT, LEFT], + grove_version + )) + .unwrap() + ) + .as_ref() ); assert_eq!( restorer.chunk_id_to_root_hash.get(vec![1, 0].as_slice()), - Some(get_node_hash(traverse_get_node_hash(&mut tree_walker, &[LEFT, RIGHT])).unwrap()) - .as_ref() + Some( + get_node_hash(traverse_get_node_hash( + &mut tree_walker, + &[LEFT, RIGHT], + grove_version + )) + .unwrap() + ) + .as_ref() ); assert_eq!( restorer.chunk_id_to_root_hash.get(vec![0, 1].as_slice()), - Some(get_node_hash(traverse_get_node_hash(&mut tree_walker, &[RIGHT, LEFT])).unwrap()) - .as_ref() + Some( + get_node_hash(traverse_get_node_hash( + &mut tree_walker, + &[RIGHT, LEFT], + grove_version + )) + .unwrap() + ) + .as_ref() ); assert_eq!( restorer.chunk_id_to_root_hash.get(vec![0, 0].as_slice()), - Some(get_node_hash(traverse_get_node_hash(&mut tree_walker, &[RIGHT, RIGHT])).unwrap()) - .as_ref() + Some( + get_node_hash(traverse_get_node_hash( + &mut tree_walker, + &[RIGHT, RIGHT], + grove_version + )) + .unwrap() + ) + .as_ref() ); // generate second chunk - let (chunk, _) = chunk_producer.chunk_with_index(2).unwrap(); + let (chunk, _) = chunk_producer.chunk_with_index(2, grove_version).unwrap(); // apply second chunk let new_chunk_ids = restorer - .process_chunk(&traversal_instruction_as_vec_bytes(&[LEFT, LEFT]), chunk) + .process_chunk( + &traversal_instruction_as_vec_bytes(&[LEFT, LEFT]), + chunk, + grove_version, + ) .unwrap(); assert_eq!(new_chunk_ids.len(), 0); // chunk_map should have 1 less element @@ -721,10 +792,13 @@ mod tests { ); // let's try to apply the second chunk again, should not work - let (chunk, _) = chunk_producer.chunk_with_index(2).unwrap(); + let (chunk, _) = chunk_producer.chunk_with_index(2, grove_version).unwrap(); // apply second chunk - let chunk_process_result = - restorer.process_chunk(&traversal_instruction_as_vec_bytes(&[LEFT, LEFT]), chunk); + let chunk_process_result = restorer.process_chunk( + &traversal_instruction_as_vec_bytes(&[LEFT, LEFT]), + chunk, + grove_version, + ); assert!(chunk_process_result.is_err()); assert!(matches!( chunk_process_result, @@ -733,9 +807,12 @@ mod tests { // next let's get a random but expected chunk and work with that e.g. chunk 4 // but let's apply it to the wrong place - let (chunk, _) = chunk_producer.chunk_with_index(4).unwrap(); - let chunk_process_result = - restorer.process_chunk(&traversal_instruction_as_vec_bytes(&[LEFT, RIGHT]), chunk); + let (chunk, _) = chunk_producer.chunk_with_index(4, grove_version).unwrap(); + let chunk_process_result = restorer.process_chunk( + &traversal_instruction_as_vec_bytes(&[LEFT, RIGHT]), + chunk, + grove_version, + ); assert!(chunk_process_result.is_err()); assert!(matches!( chunk_process_result, @@ -745,10 +822,14 @@ mod tests { )); // correctly apply chunk 5 - let (chunk, _) = chunk_producer.chunk_with_index(5).unwrap(); + let (chunk, _) = chunk_producer.chunk_with_index(5, grove_version).unwrap(); // apply second chunk let new_chunk_ids = restorer - .process_chunk(&traversal_instruction_as_vec_bytes(&[RIGHT, RIGHT]), chunk) + .process_chunk( + &traversal_instruction_as_vec_bytes(&[RIGHT, RIGHT]), + chunk, + grove_version, + ) .unwrap(); assert_eq!(new_chunk_ids.len(), 0); // chunk_map should have 1 less element @@ -759,10 +840,14 @@ mod tests { ); // correctly apply chunk 3 - let (chunk, _) = chunk_producer.chunk_with_index(3).unwrap(); + let (chunk, _) = chunk_producer.chunk_with_index(3, grove_version).unwrap(); // apply second chunk let new_chunk_ids = restorer - .process_chunk(&traversal_instruction_as_vec_bytes(&[LEFT, RIGHT]), chunk) + .process_chunk( + &traversal_instruction_as_vec_bytes(&[LEFT, RIGHT]), + chunk, + grove_version, + ) .unwrap(); assert_eq!(new_chunk_ids.len(), 0); // chunk_map should have 1 less element @@ -773,10 +858,14 @@ mod tests { ); // correctly apply chunk 4 - let (chunk, _) = chunk_producer.chunk_with_index(4).unwrap(); + let (chunk, _) = chunk_producer.chunk_with_index(4, grove_version).unwrap(); // apply second chunk let new_chunk_ids = restorer - .process_chunk(&traversal_instruction_as_vec_bytes(&[RIGHT, LEFT]), chunk) + .process_chunk( + &traversal_instruction_as_vec_bytes(&[RIGHT, LEFT]), + chunk, + grove_version, + ) .unwrap(); assert_eq!(new_chunk_ids.len(), 0); // chunk_map should have 1 less element @@ -787,7 +876,9 @@ mod tests { ); // finalize merk - let restored_merk = restorer.finalize().expect("should finalized successfully"); + let restored_merk = restorer + .finalize(grove_version) + .expect("should finalized successfully"); assert_eq!( restored_merk.root_hash().unwrap(), @@ -833,6 +924,7 @@ mod tests { // attempts restoration on some empty merk // verifies that restoration was performed correctly. fn test_restoration_single_chunk_strategy(batch_size: u64) { + let grove_version = GroveVersion::latest(); // build the source merk let storage = TempStorage::new(); let tx = storage.start_transaction(); @@ -841,13 +933,14 @@ mod tests { .get_immediate_storage_context(SubtreePath::empty(), &tx) .unwrap(), false, - None::<&fn(&[u8]) -> Option>, + None::<&fn(&[u8], &GroveVersion) -> Option>, + grove_version, ) .unwrap() .unwrap(); let batch = make_batch_seq(0..batch_size); source_merk - .apply::<_, Vec<_>>(&batch, &[], None) + .apply::<_, Vec<_>>(&batch, &[], None, grove_version) .unwrap() .expect("apply failed"); @@ -859,7 +952,8 @@ mod tests { .get_immediate_storage_context(SubtreePath::empty(), &tx) .unwrap(), false, - None::<&fn(&[u8]) -> Option>, + None::<&fn(&[u8], &GroveVersion) -> Option>, + grove_version, ) .unwrap() .unwrap(); @@ -881,9 +975,11 @@ mod tests { // perform chunk production and processing let mut chunk_id_opt = Some(vec![]); while let Some(chunk_id) = chunk_id_opt { - let (chunk, next_chunk_id) = chunk_producer.chunk(&chunk_id).expect("should get chunk"); + let (chunk, next_chunk_id) = chunk_producer + .chunk(&chunk_id, grove_version) + .expect("should get chunk"); restorer - .process_chunk(&chunk_id, chunk) + .process_chunk(&chunk_id, chunk, grove_version) .expect("should process chunk successfully"); chunk_id_opt = next_chunk_id; } @@ -891,7 +987,7 @@ mod tests { // after chunk processing we should be able to finalize assert_eq!(restorer.chunk_id_to_root_hash.len(), 0); assert_eq!(restorer.parent_keys.len(), 0); - let restored_merk = restorer.finalize().expect("should finalize"); + let restored_merk = restorer.finalize(grove_version).expect("should finalize"); // compare root hash values assert_eq!( @@ -914,9 +1010,10 @@ mod tests { #[test] fn test_process_multi_chunk_no_limit() { - let mut merk = TempMerk::new(); + let grove_version = GroveVersion::latest(); + let mut merk = TempMerk::new(grove_version); let batch = make_batch_seq(0..15); - merk.apply::<_, Vec<_>>(&batch, &[], None) + merk.apply::<_, Vec<_>>(&batch, &[], None, grove_version) .unwrap() .expect("apply failed"); assert_eq!(merk.height(), Some(4)); @@ -928,7 +1025,8 @@ mod tests { .get_immediate_storage_context(SubtreePath::empty(), &tx) .unwrap(), false, - None::<&fn(&[u8]) -> Option>, + None::<&fn(&[u8], &GroveVersion) -> Option>, + grove_version, ) .unwrap() .unwrap(); @@ -953,7 +1051,7 @@ mod tests { // generate multi chunk from root with no limit let chunk = chunk_producer - .multi_chunk_with_limit(vec![].as_slice(), None) + .multi_chunk_with_limit(vec![].as_slice(), None, grove_version) .expect("should generate multichunk"); assert_eq!(chunk.chunk.len(), 2); @@ -961,14 +1059,16 @@ mod tests { assert_eq!(chunk.remaining_limit, None); let next_ids = restorer - .process_multi_chunk(chunk.chunk) + .process_multi_chunk(chunk.chunk, grove_version) .expect("should process chunk"); // should have replicated all chunks assert_eq!(next_ids.len(), 0); assert_eq!(restorer.chunk_id_to_root_hash.len(), 0); assert_eq!(restorer.parent_keys.len(), 0); - let restored_merk = restorer.finalize().expect("should be able to finalize"); + let restored_merk = restorer + .finalize(grove_version) + .expect("should be able to finalize"); // compare root hash values assert_eq!( @@ -979,9 +1079,10 @@ mod tests { #[test] fn test_process_multi_chunk_no_limit_but_non_root() { - let mut merk = TempMerk::new(); + let grove_version = GroveVersion::latest(); + let mut merk = TempMerk::new(grove_version); let batch = make_batch_seq(0..15); - merk.apply::<_, Vec<_>>(&batch, &[], None) + merk.apply::<_, Vec<_>>(&batch, &[], None, grove_version) .unwrap() .expect("apply failed"); assert_eq!(merk.height(), Some(4)); @@ -993,7 +1094,8 @@ mod tests { .get_immediate_storage_context(SubtreePath::empty(), &tx) .unwrap(), false, - None::<&fn(&[u8]) -> Option>, + None::<&fn(&[u8], &GroveVersion) -> Option>, + grove_version, ) .unwrap() .unwrap(); @@ -1017,9 +1119,13 @@ mod tests { ); // first restore the first chunk - let (chunk, next_chunk_index) = chunk_producer.chunk_with_index(1).unwrap(); + let (chunk, next_chunk_index) = chunk_producer.chunk_with_index(1, grove_version).unwrap(); let new_chunk_ids = restorer - .process_chunk(&traversal_instruction_as_vec_bytes(&[]), chunk) + .process_chunk( + &traversal_instruction_as_vec_bytes(&[]), + chunk, + grove_version, + ) .expect("should process chunk"); assert_eq!(new_chunk_ids.len(), 4); assert_eq!(next_chunk_index, Some(2)); @@ -1028,19 +1134,23 @@ mod tests { // generate multi chunk from the 2nd chunk with no limit let multi_chunk = chunk_producer - .multi_chunk_with_limit_and_index(next_chunk_index.unwrap(), None) + .multi_chunk_with_limit_and_index(next_chunk_index.unwrap(), None, grove_version) .unwrap(); // tree of height 4 has 5 chunks // we have restored the first leaving 4 chunks // each chunk has an extra chunk id, since they are disjoint // hence the size of the multi chunk should be 8 assert_eq!(multi_chunk.chunk.len(), 8); - let new_chunk_ids = restorer.process_multi_chunk(multi_chunk.chunk).unwrap(); + let new_chunk_ids = restorer + .process_multi_chunk(multi_chunk.chunk, grove_version) + .unwrap(); assert_eq!(new_chunk_ids.len(), 0); assert_eq!(restorer.chunk_id_to_root_hash.len(), 0); assert_eq!(restorer.parent_keys.len(), 0); - let restored_merk = restorer.finalize().expect("should be able to finalize"); + let restored_merk = restorer + .finalize(grove_version) + .expect("should be able to finalize"); // compare root hash values assert_eq!( @@ -1051,9 +1161,10 @@ mod tests { #[test] fn test_process_multi_chunk_with_limit() { - let mut merk = TempMerk::new(); + let grove_version = GroveVersion::latest(); + let mut merk = TempMerk::new(grove_version); let batch = make_batch_seq(0..15); - merk.apply::<_, Vec<_>>(&batch, &[], None) + merk.apply::<_, Vec<_>>(&batch, &[], None, grove_version) .unwrap() .expect("apply failed"); assert_eq!(merk.height(), Some(4)); @@ -1065,7 +1176,8 @@ mod tests { .get_immediate_storage_context(SubtreePath::empty(), &tx) .unwrap(), false, - None::<&fn(&[u8]) -> Option>, + None::<&fn(&[u8], &GroveVersion) -> Option>, + grove_version, ) .unwrap() .unwrap(); @@ -1084,13 +1196,15 @@ mod tests { // build multi chunk with with limit of 325 let multi_chunk = chunk_producer - .multi_chunk_with_limit(vec![].as_slice(), Some(600)) + .multi_chunk_with_limit(vec![].as_slice(), Some(600), grove_version) .unwrap(); // should only contain the first chunk assert_eq!(multi_chunk.chunk.len(), 2); // should point to chunk 2 assert_eq!(multi_chunk.next_index, Some(vec![1, 1])); - let next_ids = restorer.process_multi_chunk(multi_chunk.chunk).unwrap(); + let next_ids = restorer + .process_multi_chunk(multi_chunk.chunk, grove_version) + .unwrap(); assert_eq!(next_ids.len(), 4); assert_eq!(restorer.chunk_id_to_root_hash.len(), 4); assert_eq!(restorer.parent_keys.len(), 4); @@ -1099,11 +1213,17 @@ mod tests { // with limit just above 642 should get 2 chunks (2 and 3) // disjoint, so multi chunk len should be 4 let multi_chunk = chunk_producer - .multi_chunk_with_limit(multi_chunk.next_index.unwrap().as_slice(), Some(645)) + .multi_chunk_with_limit( + multi_chunk.next_index.unwrap().as_slice(), + Some(645), + grove_version, + ) .unwrap(); assert_eq!(multi_chunk.chunk.len(), 4); assert_eq!(multi_chunk.next_index, Some(vec![0u8, 1u8])); - let next_ids = restorer.process_multi_chunk(multi_chunk.chunk).unwrap(); + let next_ids = restorer + .process_multi_chunk(multi_chunk.chunk, grove_version) + .unwrap(); // chunks 2 and 3 are leaf chunks assert_eq!(next_ids.len(), 0); assert_eq!(restorer.chunk_id_to_root_hash.len(), 2); @@ -1111,18 +1231,24 @@ mod tests { // get the last 2 chunks let multi_chunk = chunk_producer - .multi_chunk_with_limit(multi_chunk.next_index.unwrap().as_slice(), Some(645)) + .multi_chunk_with_limit( + multi_chunk.next_index.unwrap().as_slice(), + Some(645), + grove_version, + ) .unwrap(); assert_eq!(multi_chunk.chunk.len(), 4); assert_eq!(multi_chunk.next_index, None); - let next_ids = restorer.process_multi_chunk(multi_chunk.chunk).unwrap(); + let next_ids = restorer + .process_multi_chunk(multi_chunk.chunk, grove_version) + .unwrap(); // chunks 2 and 3 are leaf chunks assert_eq!(next_ids.len(), 0); assert_eq!(restorer.chunk_id_to_root_hash.len(), 0); assert_eq!(restorer.parent_keys.len(), 0); // finalize merk - let restored_merk = restorer.finalize().unwrap(); + let restored_merk = restorer.finalize(grove_version).unwrap(); // compare root hash values assert_eq!( @@ -1135,11 +1261,12 @@ mod tests { // attempts restoration on some empty merk, with multi chunks // verifies that restoration was performed correctly. fn test_restoration_multi_chunk_strategy(batch_size: u64, limit: Option) { + let grove_version = GroveVersion::latest(); // build the source merk - let mut source_merk = TempMerk::new(); + let mut source_merk = TempMerk::new(grove_version); let batch = make_batch_seq(0..batch_size); source_merk - .apply::<_, Vec<_>>(&batch, &[], None) + .apply::<_, Vec<_>>(&batch, &[], None, grove_version) .unwrap() .expect("apply failed"); @@ -1151,7 +1278,8 @@ mod tests { .get_immediate_storage_context(SubtreePath::empty(), &tx) .unwrap(), false, - None::<&fn(&[u8]) -> Option>, + None::<&fn(&[u8], &GroveVersion) -> Option>, + grove_version, ) .unwrap() .unwrap(); @@ -1174,10 +1302,10 @@ mod tests { let mut chunk_id_opt = Some(vec![]); while let Some(chunk_id) = chunk_id_opt { let multi_chunk = chunk_producer - .multi_chunk_with_limit(&chunk_id, limit) + .multi_chunk_with_limit(&chunk_id, limit, grove_version) .expect("should get chunk"); restorer - .process_multi_chunk(multi_chunk.chunk) + .process_multi_chunk(multi_chunk.chunk, grove_version) .expect("should process chunk successfully"); chunk_id_opt = multi_chunk.next_index; } @@ -1185,7 +1313,7 @@ mod tests { // after chunk processing we should be able to finalize assert_eq!(restorer.chunk_id_to_root_hash.len(), 0); assert_eq!(restorer.parent_keys.len(), 0); - let restored_merk = restorer.finalize().expect("should finalize"); + let restored_merk = restorer.finalize(grove_version).expect("should finalize"); // compare root hash values assert_eq!( @@ -1217,9 +1345,10 @@ mod tests { #[test] fn test_restoration_interruption() { - let mut merk = TempMerk::new(); + let grove_version = GroveVersion::latest(); + let mut merk = TempMerk::new(grove_version); let batch = make_batch_seq(0..15); - merk.apply::<_, Vec<_>>(&batch, &[], None) + merk.apply::<_, Vec<_>>(&batch, &[], None, grove_version) .unwrap() .expect("apply failed"); assert_eq!(merk.height(), Some(4)); @@ -1231,7 +1360,8 @@ mod tests { .get_immediate_storage_context(SubtreePath::empty(), &tx) .unwrap(), false, - None::<&fn(&[u8]) -> Option>, + None::<&fn(&[u8], &GroveVersion) -> Option>, + grove_version, ) .unwrap() .unwrap(); @@ -1255,9 +1385,13 @@ mod tests { ); // first restore the first chunk - let (chunk, next_chunk_index) = chunk_producer.chunk_with_index(1).unwrap(); + let (chunk, next_chunk_index) = chunk_producer.chunk_with_index(1, grove_version).unwrap(); let new_chunk_ids = restorer - .process_chunk(&traversal_instruction_as_vec_bytes(&[]), chunk) + .process_chunk( + &traversal_instruction_as_vec_bytes(&[]), + chunk, + grove_version, + ) .expect("should process chunk"); assert_eq!(new_chunk_ids.len(), 4); assert_eq!(next_chunk_index, Some(2)); @@ -1276,7 +1410,8 @@ mod tests { .get_immediate_storage_context(SubtreePath::empty(), &tx) .unwrap(), false, - None::<&fn(&[u8]) -> Option>, + None::<&fn(&[u8], &GroveVersion) -> Option>, + grove_version, ) .unwrap() .unwrap(); @@ -1287,7 +1422,7 @@ mod tests { assert_eq!(restorer.parent_keys.len(), 0); // recover state - let recovery_attempt = restorer.attempt_state_recovery(); + let recovery_attempt = restorer.attempt_state_recovery(grove_version); assert!(recovery_attempt.is_ok()); assert_eq!(restorer.chunk_id_to_root_hash.len(), 4); assert_eq!(restorer.parent_keys.len(), 4); diff --git a/merk/src/merk/source.rs b/merk/src/merk/source.rs index 46782bdc..dd71e74e 100644 --- a/merk/src/merk/source.rs +++ b/merk/src/merk/source.rs @@ -1,5 +1,6 @@ use grovedb_costs::CostResult; use grovedb_storage::StorageContext; +use grovedb_version::version::GroveVersion; use crate::{ tree::{kv::ValueDefinedCostType, Fetch, TreeNode}, @@ -40,10 +41,18 @@ where fn fetch( &self, link: &Link, - value_defined_cost_fn: Option<&impl Fn(&[u8]) -> Option>, + value_defined_cost_fn: Option< + &impl Fn(&[u8], &GroveVersion) -> Option, + >, + grove_version: &GroveVersion, ) -> CostResult { - TreeNode::get(self.storage, link.key(), value_defined_cost_fn) - .map_ok(|x| x.ok_or(Error::KeyNotFoundError("Key not found for fetch"))) - .flatten() + TreeNode::get( + self.storage, + link.key(), + value_defined_cost_fn, + grove_version, + ) + .map_ok(|x| x.ok_or(Error::KeyNotFoundError("Key not found for fetch"))) + .flatten() } } diff --git a/merk/src/owner.rs b/merk/src/owner.rs index 18efb8f2..1543a089 100644 --- a/merk/src/owner.rs +++ b/merk/src/owner.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. - //! Owner use std::ops::{Deref, DerefMut}; diff --git a/merk/src/proofs/chunk/chunk.rs b/merk/src/proofs/chunk/chunk.rs index 95d888ec..4960c53f 100644 --- a/merk/src/proofs/chunk/chunk.rs +++ b/merk/src/proofs/chunk/chunk.rs @@ -27,6 +27,7 @@ // DEALINGS IN THE SOFTWARE. use grovedb_costs::{cost_return_on_error, CostResult, CostsExt, OperationCost}; +use grovedb_version::version::GroveVersion; // TODO: add copyright comment use crate::proofs::{Node, Op, Tree}; @@ -44,11 +45,15 @@ where S: Fetch + Sized + Clone, { /// Returns a chunk of a given depth from a RefWalker - pub fn create_chunk(&mut self, depth: usize) -> Result, Error> { + pub fn create_chunk( + &mut self, + depth: usize, + grove_version: &GroveVersion, + ) -> Result, Error> { // build the proof vector let mut proof = vec![]; - self.create_chunk_internal(&mut proof, depth)?; + self.create_chunk_internal(&mut proof, depth, grove_version)?; Ok(proof) } @@ -57,6 +62,7 @@ where &mut self, proof: &mut Vec, remaining_depth: usize, + grove_version: &GroveVersion, ) -> Result<(), Error> { // at some point we will reach the depth // here we need to put the node hash @@ -69,10 +75,14 @@ where let has_left_child = self.tree().link(true).is_some(); if has_left_child { let mut left = self - .walk(true, None::<&fn(&[u8]) -> Option>) + .walk( + true, + None::<&fn(&[u8], &GroveVersion) -> Option>, + grove_version, + ) .unwrap()? .expect("confirmed is some"); - left.create_chunk_internal(proof, remaining_depth - 1)?; + left.create_chunk_internal(proof, remaining_depth - 1, grove_version)?; } // add current node's data @@ -84,10 +94,14 @@ where // traverse right if let Some(mut right) = self - .walk(false, None::<&fn(&[u8]) -> Option>) + .walk( + false, + None::<&fn(&[u8], &GroveVersion) -> Option>, + grove_version, + ) .unwrap()? { - right.create_chunk_internal(proof, remaining_depth - 1)?; + right.create_chunk_internal(proof, remaining_depth - 1, grove_version)?; proof.push(Op::Child); } @@ -101,11 +115,12 @@ where &mut self, instructions: &[bool], depth: usize, + grove_version: &GroveVersion, ) -> Result, Error> { // base case if instructions.is_empty() { // we are at the desired node - return self.create_chunk(depth); + return self.create_chunk(depth, grove_version); } // link must exist @@ -120,13 +135,14 @@ where let mut child = self .walk( instructions[0], - None::<&fn(&[u8]) -> Option>, + None::<&fn(&[u8], &GroveVersion) -> Option>, + grove_version, ) .unwrap()? .expect("confirmed link exists so cannot be none"); // recurse on child - child.traverse_and_build_chunk(&instructions[1..], depth) + child.traverse_and_build_chunk(&instructions[1..], depth, grove_version) } /// Returns the smallest amount of tree ops, that can convince @@ -140,7 +156,11 @@ where /// . /// . /// . - pub fn generate_height_proof(&mut self, proof: &mut Vec) -> CostResult<(), Error> { + pub fn generate_height_proof( + &mut self, + proof: &mut Vec, + grove_version: &GroveVersion, + ) -> CostResult<(), Error> { // TODO: look into making height proofs more efficient // they will always be used in the context of some // existing chunk, we don't want to repeat nodes unnecessarily @@ -148,13 +168,17 @@ where let maybe_left = cost_return_on_error!( &mut cost, - self.walk(LEFT, None::<&fn(&[u8]) -> Option>) + self.walk( + LEFT, + None::<&fn(&[u8], &GroveVersion) -> Option>, + grove_version + ) ); let has_left_child = maybe_left.is_some(); // recurse to leftmost element if let Some(mut left) = maybe_left { - cost_return_on_error!(&mut cost, left.generate_height_proof(proof)) + cost_return_on_error!(&mut cost, left.generate_height_proof(proof, grove_version)) } proof.push(Op::Push(self.to_kvhash_node())); @@ -207,6 +231,7 @@ pub fn verify_height_tree(height_proof_tree: &Tree) -> Result { #[cfg(test)] pub mod tests { use ed::Encode; + use grovedb_version::version::GroveVersion; use crate::{ proofs::{ @@ -220,6 +245,7 @@ pub mod tests { }; fn build_tree_10_nodes() -> TreeNode { + let grove_version = GroveVersion::latest(); // 3 // / \ // 1 7 @@ -227,7 +253,7 @@ pub mod tests { // 0 2 5 8 // / \ \ // 4 6 9 - make_tree_seq_with_start_key(10, [0; 8].to_vec()) + make_tree_seq_with_start_key(10, [0; 8].to_vec(), grove_version) } /// Traverses a tree to a certain node and returns the node hash of that @@ -235,10 +261,14 @@ pub mod tests { pub fn traverse_get_node_hash( walker: &mut RefWalker, traverse_instructions: &[bool], + grove_version: &GroveVersion, ) -> Node { - traverse_and_apply(walker, traverse_instructions, |walker| { - walker.to_hash_node().unwrap() - }) + traverse_and_apply( + walker, + traverse_instructions, + |walker| walker.to_hash_node().unwrap(), + grove_version, + ) } /// Traverses a tree to a certain node and returns the kv_feature_type of @@ -246,20 +276,28 @@ pub mod tests { pub fn traverse_get_kv_feature_type( walker: &mut RefWalker, traverse_instructions: &[bool], + grove_version: &GroveVersion, ) -> Node { - traverse_and_apply(walker, traverse_instructions, |walker| { - walker.to_kv_value_hash_feature_type_node() - }) + traverse_and_apply( + walker, + traverse_instructions, + |walker| walker.to_kv_value_hash_feature_type_node(), + grove_version, + ) } /// Traverses a tree to a certain node and returns the kv_hash of /// that node pub fn traverse_get_kv_hash( walker: &mut RefWalker, traverse_instructions: &[bool], + grove_version: &GroveVersion, ) -> Node { - traverse_and_apply(walker, traverse_instructions, |walker| { - walker.to_kvhash_node() - }) + traverse_and_apply( + walker, + traverse_instructions, + |walker| walker.to_kvhash_node(), + grove_version, + ) } /// Traverses a tree to a certain node and returns the result of applying @@ -268,6 +306,7 @@ pub mod tests { walker: &mut RefWalker, traverse_instructions: &[bool], apply_fn: T, + grove_version: &GroveVersion, ) -> Node where T: Fn(&mut RefWalker) -> Node, @@ -279,25 +318,34 @@ pub mod tests { let mut child = walker .walk( traverse_instructions[0], - None::<&fn(&[u8]) -> Option>, + None::<&fn(&[u8], &GroveVersion) -> Option>, + grove_version, ) .unwrap() .unwrap() .unwrap(); - traverse_and_apply(&mut child, &traverse_instructions[1..], apply_fn) + traverse_and_apply( + &mut child, + &traverse_instructions[1..], + apply_fn, + grove_version, + ) } #[test] fn build_chunk_from_root_depth_0() { + let grove_version = GroveVersion::latest(); let mut tree = build_tree_10_nodes(); let mut tree_walker = RefWalker::new(&mut tree, PanicSource {}); // should return the node hash of the root node - let chunk = tree_walker.create_chunk(0).expect("should build chunk"); + let chunk = tree_walker + .create_chunk(0, grove_version) + .expect("should build chunk"); assert_eq!(chunk.len(), 1); assert_eq!( chunk[0], - Op::Push(traverse_get_node_hash(&mut tree_walker, &[])) + Op::Push(traverse_get_node_hash(&mut tree_walker, &[], grove_version)) ); let computed_tree = execute(chunk.into_iter().map(Ok), true, |_| Ok(())) @@ -308,6 +356,7 @@ pub mod tests { #[test] fn build_chunk_from_root_depth_1() { + let grove_version = GroveVersion::latest(); let mut tree = build_tree_10_nodes(); let mut tree_walker = RefWalker::new(&mut tree, PanicSource {}); @@ -316,15 +365,29 @@ pub mod tests { // 3 // / \ // Hash(1) Hash(7) - let chunk = tree_walker.create_chunk(1).expect("should build chunk"); + let chunk = tree_walker + .create_chunk(1, grove_version) + .expect("should build chunk"); assert_eq!(chunk.len(), 5); assert_eq!( chunk, vec![ - Op::Push(traverse_get_node_hash(&mut tree_walker, &[LEFT])), - Op::Push(traverse_get_kv_feature_type(&mut tree_walker, &[])), + Op::Push(traverse_get_node_hash( + &mut tree_walker, + &[LEFT], + grove_version + )), + Op::Push(traverse_get_kv_feature_type( + &mut tree_walker, + &[], + grove_version + )), Op::Parent, - Op::Push(traverse_get_node_hash(&mut tree_walker, &[RIGHT])), + Op::Push(traverse_get_node_hash( + &mut tree_walker, + &[RIGHT], + grove_version + )), Op::Child ] ); @@ -337,6 +400,7 @@ pub mod tests { #[test] fn build_chunk_from_root_depth_3() { + let grove_version = GroveVersion::latest(); let mut tree = build_tree_10_nodes(); let mut tree_walker = RefWalker::new(&mut tree, PanicSource {}); @@ -349,47 +413,68 @@ pub mod tests { // 0 2 5 8 // / \ \ // H(4) H(6) H(9) - let chunk = tree_walker.create_chunk(3).expect("should build chunk"); + let chunk = tree_walker + .create_chunk(3, grove_version) + .expect("should build chunk"); assert_eq!(chunk.len(), 19); assert_eq!( chunk, vec![ Op::Push(traverse_get_kv_feature_type( &mut tree_walker, - &[LEFT, LEFT] + &[LEFT, LEFT], + grove_version + )), + Op::Push(traverse_get_kv_feature_type( + &mut tree_walker, + &[LEFT], + grove_version )), - Op::Push(traverse_get_kv_feature_type(&mut tree_walker, &[LEFT])), Op::Parent, Op::Push(traverse_get_kv_feature_type( &mut tree_walker, - &[LEFT, RIGHT] + &[LEFT, RIGHT], + grove_version )), Op::Child, - Op::Push(traverse_get_kv_feature_type(&mut tree_walker, &[])), + Op::Push(traverse_get_kv_feature_type( + &mut tree_walker, + &[], + grove_version + )), Op::Parent, Op::Push(traverse_get_node_hash( &mut tree_walker, - &[RIGHT, LEFT, LEFT] + &[RIGHT, LEFT, LEFT], + grove_version )), Op::Push(traverse_get_kv_feature_type( &mut tree_walker, - &[RIGHT, LEFT] + &[RIGHT, LEFT], + grove_version )), Op::Parent, Op::Push(traverse_get_node_hash( &mut tree_walker, - &[RIGHT, LEFT, RIGHT] + &[RIGHT, LEFT, RIGHT], + grove_version )), Op::Child, - Op::Push(traverse_get_kv_feature_type(&mut tree_walker, &[RIGHT])), + Op::Push(traverse_get_kv_feature_type( + &mut tree_walker, + &[RIGHT], + grove_version + )), Op::Parent, Op::Push(traverse_get_kv_feature_type( &mut tree_walker, - &[RIGHT, RIGHT] + &[RIGHT, RIGHT], + grove_version )), Op::Push(traverse_get_node_hash( &mut tree_walker, - &[RIGHT, RIGHT, RIGHT] + &[RIGHT, RIGHT, RIGHT], + grove_version )), Op::Child, Op::Child, @@ -405,6 +490,7 @@ pub mod tests { #[test] fn build_chunk_from_root_depth_max_depth() { + let grove_version = GroveVersion::latest(); let mut tree = build_tree_10_nodes(); let mut tree_walker = RefWalker::new(&mut tree, PanicSource {}); @@ -416,47 +502,68 @@ pub mod tests { // 0 2 5 8 // / \ \ // 4 6 9 - let chunk = tree_walker.create_chunk(4).expect("should build chunk"); + let chunk = tree_walker + .create_chunk(4, grove_version) + .expect("should build chunk"); assert_eq!(chunk.len(), 19); assert_eq!( chunk, vec![ Op::Push(traverse_get_kv_feature_type( &mut tree_walker, - &[LEFT, LEFT] + &[LEFT, LEFT], + grove_version + )), + Op::Push(traverse_get_kv_feature_type( + &mut tree_walker, + &[LEFT], + grove_version )), - Op::Push(traverse_get_kv_feature_type(&mut tree_walker, &[LEFT])), Op::Parent, Op::Push(traverse_get_kv_feature_type( &mut tree_walker, - &[LEFT, RIGHT] + &[LEFT, RIGHT], + grove_version )), Op::Child, - Op::Push(traverse_get_kv_feature_type(&mut tree_walker, &[])), + Op::Push(traverse_get_kv_feature_type( + &mut tree_walker, + &[], + grove_version + )), Op::Parent, Op::Push(traverse_get_kv_feature_type( &mut tree_walker, - &[RIGHT, LEFT, LEFT] + &[RIGHT, LEFT, LEFT], + grove_version )), Op::Push(traverse_get_kv_feature_type( &mut tree_walker, - &[RIGHT, LEFT] + &[RIGHT, LEFT], + grove_version )), Op::Parent, Op::Push(traverse_get_kv_feature_type( &mut tree_walker, - &[RIGHT, LEFT, RIGHT] + &[RIGHT, LEFT, RIGHT], + grove_version )), Op::Child, - Op::Push(traverse_get_kv_feature_type(&mut tree_walker, &[RIGHT])), + Op::Push(traverse_get_kv_feature_type( + &mut tree_walker, + &[RIGHT], + grove_version + )), Op::Parent, Op::Push(traverse_get_kv_feature_type( &mut tree_walker, - &[RIGHT, RIGHT] + &[RIGHT, RIGHT], + grove_version )), Op::Push(traverse_get_kv_feature_type( &mut tree_walker, - &[RIGHT, RIGHT, RIGHT] + &[RIGHT, RIGHT, RIGHT], + grove_version )), Op::Child, Op::Child, @@ -472,13 +579,18 @@ pub mod tests { #[test] fn chunk_greater_than_max_should_equal_max_depth() { + let grove_version = GroveVersion::latest(); let mut tree = build_tree_10_nodes(); let mut tree_walker = RefWalker::new(&mut tree, PanicSource {}); // build chunk with depth greater than tree // we should get the same result as building with the exact depth - let large_depth_chunk = tree_walker.create_chunk(100).expect("should build chunk"); - let exact_depth_chunk = tree_walker.create_chunk(4).expect("should build chunk"); + let large_depth_chunk = tree_walker + .create_chunk(100, grove_version) + .expect("should build chunk"); + let exact_depth_chunk = tree_walker + .create_chunk(4, grove_version) + .expect("should build chunk"); assert_eq!(large_depth_chunk, exact_depth_chunk); let tree_a = execute(large_depth_chunk.into_iter().map(Ok), true, |_| Ok(())) @@ -492,6 +604,7 @@ pub mod tests { #[test] fn build_chunk_after_traversal_depth_2() { + let grove_version = GroveVersion::latest(); let mut tree = build_tree_10_nodes(); let mut tree_walker = RefWalker::new(&mut tree, PanicSource {}); @@ -505,34 +618,43 @@ pub mod tests { // right traversal let chunk = tree_walker - .traverse_and_build_chunk(&[RIGHT], 2) + .traverse_and_build_chunk(&[RIGHT], 2, grove_version) .expect("should build chunk"); assert_eq!( chunk, vec![ Op::Push(traverse_get_node_hash( &mut tree_walker, - &[RIGHT, LEFT, LEFT] + &[RIGHT, LEFT, LEFT], + grove_version )), Op::Push(traverse_get_kv_feature_type( &mut tree_walker, - &[RIGHT, LEFT] + &[RIGHT, LEFT], + grove_version )), Op::Parent, Op::Push(traverse_get_node_hash( &mut tree_walker, - &[RIGHT, LEFT, RIGHT] + &[RIGHT, LEFT, RIGHT], + grove_version )), Op::Child, - Op::Push(traverse_get_kv_feature_type(&mut tree_walker, &[RIGHT])), + Op::Push(traverse_get_kv_feature_type( + &mut tree_walker, + &[RIGHT], + grove_version + )), Op::Parent, Op::Push(traverse_get_kv_feature_type( &mut tree_walker, - &[RIGHT, RIGHT] + &[RIGHT, RIGHT], + grove_version )), Op::Push(traverse_get_node_hash( &mut tree_walker, - &[RIGHT, RIGHT, RIGHT] + &[RIGHT, RIGHT, RIGHT], + grove_version )), Op::Child, Op::Child, @@ -547,12 +669,13 @@ pub mod tests { .expect("should reconstruct tree"); assert_eq!( Node::Hash(computed_tree.hash().unwrap()), - traverse_get_node_hash(&mut tree_walker, &[RIGHT]) + traverse_get_node_hash(&mut tree_walker, &[RIGHT], grove_version) ); } #[test] fn build_chunk_after_traversal_depth_1() { + let grove_version = GroveVersion::latest(); let mut tree = build_tree_10_nodes(); let mut tree_walker = RefWalker::new(&mut tree, PanicSource {}); @@ -564,23 +687,26 @@ pub mod tests { // instruction traversal let chunk = tree_walker - .traverse_and_build_chunk(&[RIGHT, LEFT], 1) + .traverse_and_build_chunk(&[RIGHT, LEFT], 1, grove_version) .expect("should build chunk"); assert_eq!( chunk, vec![ Op::Push(traverse_get_node_hash( &mut tree_walker, - &[RIGHT, LEFT, LEFT] + &[RIGHT, LEFT, LEFT], + grove_version )), Op::Push(traverse_get_kv_feature_type( &mut tree_walker, - &[RIGHT, LEFT] + &[RIGHT, LEFT], + grove_version )), Op::Parent, Op::Push(traverse_get_node_hash( &mut tree_walker, - &[RIGHT, LEFT, RIGHT] + &[RIGHT, LEFT, RIGHT], + grove_version )), Op::Child, ] @@ -591,7 +717,7 @@ pub mod tests { .expect("should reconstruct tree"); assert_eq!( Node::Hash(computed_tree.hash().unwrap()), - traverse_get_node_hash(&mut tree_walker, &[RIGHT, LEFT]) + traverse_get_node_hash(&mut tree_walker, &[RIGHT, LEFT], grove_version) ); } @@ -616,12 +742,13 @@ pub mod tests { #[test] fn test_height_proof_generation() { + let grove_version = GroveVersion::latest(); let mut tree = build_tree_10_nodes(); let mut tree_walker = RefWalker::new(&mut tree, PanicSource {}); let mut height_proof = vec![]; tree_walker - .generate_height_proof(&mut height_proof) + .generate_height_proof(&mut height_proof, grove_version) .unwrap() .expect("should generate height proof"); @@ -629,14 +756,30 @@ pub mod tests { assert_eq!( height_proof, vec![ - Op::Push(traverse_get_kv_hash(&mut tree_walker, &[LEFT, LEFT])), - Op::Push(traverse_get_kv_hash(&mut tree_walker, &[LEFT])), + Op::Push(traverse_get_kv_hash( + &mut tree_walker, + &[LEFT, LEFT], + grove_version + )), + Op::Push(traverse_get_kv_hash( + &mut tree_walker, + &[LEFT], + grove_version + )), Op::Parent, - Op::Push(traverse_get_node_hash(&mut tree_walker, &[LEFT, RIGHT])), + Op::Push(traverse_get_node_hash( + &mut tree_walker, + &[LEFT, RIGHT], + grove_version + )), Op::Child, - Op::Push(traverse_get_kv_hash(&mut tree_walker, &[])), + Op::Push(traverse_get_kv_hash(&mut tree_walker, &[], grove_version)), Op::Parent, - Op::Push(traverse_get_node_hash(&mut tree_walker, &[RIGHT])), + Op::Push(traverse_get_node_hash( + &mut tree_walker, + &[RIGHT], + grove_version + )), Op::Child, ] ); @@ -644,12 +787,13 @@ pub mod tests { #[test] fn test_height_proof_verification() { + let grove_version = GroveVersion::latest(); let mut tree = build_tree_10_nodes(); let mut tree_walker = RefWalker::new(&mut tree, PanicSource {}); let mut height_proof = vec![]; tree_walker - .generate_height_proof(&mut height_proof) + .generate_height_proof(&mut height_proof, grove_version) .unwrap() .expect("should generate height proof"); diff --git a/merk/src/proofs/chunk/util.rs b/merk/src/proofs/chunk/util.rs index fab2024a..3cbc0942 100644 --- a/merk/src/proofs/chunk/util.rs +++ b/merk/src/proofs/chunk/util.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. - //! Collection of state independent algorithms needed for facilitate chunk //! production and restoration @@ -573,7 +545,7 @@ mod test { #[test] fn test_traversal_instruction_as_string() { - assert_eq!(traversal_instruction_as_vec_bytes(&[]), vec![]); + assert_eq!(traversal_instruction_as_vec_bytes(&[]), Vec::::new()); assert_eq!(traversal_instruction_as_vec_bytes(&[LEFT]), vec![1u8]); assert_eq!(traversal_instruction_as_vec_bytes(&[RIGHT]), vec![0u8]); assert_eq!( diff --git a/merk/src/proofs/query/map.rs b/merk/src/proofs/query/map.rs index 757403a2..9e741cea 100644 --- a/merk/src/proofs/query/map.rs +++ b/merk/src/proofs/query/map.rs @@ -236,38 +236,6 @@ impl<'a> Iterator for Range<'a> { } } -#[cfg(feature = "full")] -/// `BTreeMapExtras` provides extra functionality to work with `BTreeMap` that -/// either missed or unstable -/// NOTE: We can easily remove this when the following feature will be rolled -/// out into stable rust: https://github.com/rust-lang/rust/issues/62924 -trait BTreeMapExtras { - type K; - type V; - - /// Returns `None` if `BTreeMap` is empty otherwise the first key-value pair - /// in the map. The key in this pair is the minimum key in the map. - fn first_key_value(&self) -> Option<(&Self::K, &Self::V)>; - - /// Returns `None` if `BTreeMap` is empty otherwise the last key-value pair - /// in the map. The key in this pair is the maximum key in the map. - fn last_key_value(&self) -> Option<(&Self::K, &Self::V)>; -} - -#[cfg(feature = "full")] -impl BTreeMapExtras for BTreeMap { - type K = KK; - type V = VV; - - fn first_key_value(&self) -> Option<(&Self::K, &Self::V)> { - self.iter().next() - } - - fn last_key_value(&self) -> Option<(&Self::K, &Self::V)> { - self.iter().next_back() - } -} - #[cfg(feature = "full")] #[cfg(test)] mod tests { diff --git a/merk/src/proofs/query/mod.rs b/merk/src/proofs/query/mod.rs index 107a1ec8..669940cc 100644 --- a/merk/src/proofs/query/mod.rs +++ b/merk/src/proofs/query/mod.rs @@ -20,6 +20,7 @@ use std::{collections::HashSet, fmt, ops::RangeFull}; #[cfg(feature = "full")] use grovedb_costs::{cost_return_on_error, CostContext, CostResult, CostsExt, OperationCost}; +use grovedb_version::version::GroveVersion; #[cfg(any(feature = "full", feature = "verify"))] use indexmap::IndexMap; #[cfg(feature = "full")] @@ -71,7 +72,7 @@ pub struct SubqueryBranch { #[cfg(any(feature = "full", feature = "verify"))] /// `Query` represents one or more keys or ranges of keys, which can be used to -/// resolve a proof which will include all of the requested values. +/// resolve a proof which will include all the requested values. #[derive(Debug, Default, Clone, PartialEq)] pub struct Query { /// Items @@ -458,7 +459,7 @@ impl Query { } } - /// Check if has subquery + /// Check if there is a subquery pub fn has_subquery(&self) -> bool { // checks if a query has subquery items if self.default_subquery_branch.subquery.is_some() @@ -470,7 +471,7 @@ impl Query { false } - /// Check if has only keys + /// Check if there are only keys pub fn has_only_keys(&self) -> bool { // checks if all searched for items are keys self.items.iter().all(|a| a.is_key()) @@ -579,18 +580,6 @@ where self.tree().hash().map(Node::Hash) } - #[cfg(feature = "full")] - #[allow(dead_code)] // TODO: remove when proofs will be enabled - /// Create a full proof - pub(crate) fn create_full_proof( - &mut self, - query: &[QueryItem], - limit: Option, - left_to_right: bool, - ) -> CostResult { - self.create_proof(query, limit, left_to_right) - } - /// Generates a proof for the list of queried keys. Returns a tuple /// containing the generated proof operators, and a tuple representing if /// any keys were queried were less than the left edge or greater than the @@ -603,6 +592,7 @@ where query: &[QueryItem], limit: Option, left_to_right: bool, + grove_version: &GroveVersion, ) -> CostResult { let mut cost = OperationCost::default(); @@ -678,12 +668,24 @@ where let (mut proof, left_absence, mut new_limit) = if left_to_right { cost_return_on_error!( &mut cost, - self.create_child_proof(proof_direction, left_items, limit, left_to_right) + self.create_child_proof( + proof_direction, + left_items, + limit, + left_to_right, + grove_version + ) ) } else { cost_return_on_error!( &mut cost, - self.create_child_proof(proof_direction, right_items, limit, left_to_right) + self.create_child_proof( + proof_direction, + right_items, + limit, + left_to_right, + grove_version + ) ) }; @@ -717,12 +719,24 @@ where let (mut right_proof, right_absence, new_limit) = if left_to_right { cost_return_on_error!( &mut cost, - self.create_child_proof(proof_direction, right_items, new_limit, left_to_right,) + self.create_child_proof( + proof_direction, + right_items, + new_limit, + left_to_right, + grove_version + ) ) } else { cost_return_on_error!( &mut cost, - self.create_child_proof(proof_direction, left_items, new_limit, left_to_right,) + self.create_child_proof( + proof_direction, + left_items, + new_limit, + left_to_right, + grove_version + ) ) }; @@ -786,17 +800,21 @@ where query: &[QueryItem], limit: Option, left_to_right: bool, + grove_version: &GroveVersion, ) -> CostResult { if !query.is_empty() { - self.walk(left, None::<&fn(&[u8]) -> Option>) - .flat_map_ok(|child_opt| { - if let Some(mut child) = child_opt { - child.create_proof(query, limit, left_to_right) - } else { - Ok((LinkedList::new(), (true, true), limit)) - .wrap_with_cost(Default::default()) - } - }) + self.walk( + left, + None::<&fn(&[u8], &GroveVersion) -> Option>, + grove_version, + ) + .flat_map_ok(|child_opt| { + if let Some(mut child) = child_opt { + child.create_proof(query, limit, left_to_right, grove_version) + } else { + Ok((LinkedList::new(), (true, true), limit)).wrap_with_cost(Default::default()) + } + }) } else if let Some(link) = self.tree().link(left) { let mut proof = LinkedList::new(); proof.push_back(if left_to_right { @@ -844,7 +862,7 @@ mod test { *, }; use crate::{ - proofs::query::{query_item::QueryItem::RangeAfter, verify}, + proofs::query::verify, test_utils::make_tree_seq, tree::{NoopCommit, PanicSource, RefWalker, TreeNode}, TreeFeatureType::BasicMerkNode, @@ -901,11 +919,12 @@ mod test { } fn verify_keys_test(keys: Vec>, expected_result: Vec>>) { + let grove_version = GroveVersion::latest(); let mut tree = make_3_node_tree(); let mut walker = RefWalker::new(&mut tree, PanicSource {}); let (proof, ..) = walker - .create_full_proof( + .create_proof( keys.clone() .into_iter() .map(QueryItem::Key) @@ -913,6 +932,7 @@ mod test { .as_slice(), None, true, + grove_version, ) .unwrap() .expect("failed to create proof"); @@ -1141,11 +1161,12 @@ mod test { #[test] fn empty_proof() { + let grove_version = GroveVersion::latest(); let mut tree = make_3_node_tree(); let mut walker = RefWalker::new(&mut tree, PanicSource {}); let (proof, absence, ..) = walker - .create_full_proof(vec![].as_slice(), None, true) + .create_proof(vec![].as_slice(), None, true, grove_version) .unwrap() .expect("create_proof errored"); @@ -1187,12 +1208,13 @@ mod test { #[test] fn root_proof() { + let grove_version = GroveVersion::latest(); let mut tree = make_3_node_tree(); let mut walker = RefWalker::new(&mut tree, PanicSource {}); let query_items = vec![QueryItem::Key(vec![5])]; let (proof, absence, ..) = walker - .create_full_proof(query_items.as_slice(), None, true) + .create_proof(query_items.as_slice(), None, true, grove_version) .unwrap() .expect("create_proof errored"); @@ -1242,12 +1264,13 @@ mod test { #[test] fn leaf_proof() { + let grove_version = GroveVersion::latest(); let mut tree = make_3_node_tree(); let mut walker = RefWalker::new(&mut tree, PanicSource {}); let query_items = vec![QueryItem::Key(vec![3])]; let (proof, absence, ..) = walker - .create_full_proof(query_items.as_slice(), None, true) + .create_proof(query_items.as_slice(), None, true, grove_version) .unwrap() .expect("create_proof errored"); @@ -1297,12 +1320,13 @@ mod test { #[test] fn double_leaf_proof() { + let grove_version = GroveVersion::latest(); let mut tree = make_3_node_tree(); let mut walker = RefWalker::new(&mut tree, PanicSource {}); let query_items = vec![QueryItem::Key(vec![3]), QueryItem::Key(vec![7])]; let (proof, absence, ..) = walker - .create_full_proof(query_items.as_slice(), None, true) + .create_proof(query_items.as_slice(), None, true, grove_version) .unwrap() .expect("create_proof errored"); @@ -1359,6 +1383,7 @@ mod test { #[test] fn all_nodes_proof() { + let grove_version = GroveVersion::latest(); let mut tree = make_3_node_tree(); let mut walker = RefWalker::new(&mut tree, PanicSource {}); @@ -1368,7 +1393,7 @@ mod test { QueryItem::Key(vec![7]), ]; let (proof, absence, ..) = walker - .create_full_proof(query_items.as_slice(), None, true) + .create_proof(query_items.as_slice(), None, true, grove_version) .unwrap() .expect("create_proof errored"); @@ -1429,12 +1454,13 @@ mod test { #[test] fn global_edge_absence_proof() { + let grove_version = GroveVersion::latest(); let mut tree = make_3_node_tree(); let mut walker = RefWalker::new(&mut tree, PanicSource {}); let query_items = vec![QueryItem::Key(vec![8])]; let (proof, absence, ..) = walker - .create_full_proof(query_items.as_slice(), None, true) + .create_proof(query_items.as_slice(), None, true, grove_version) .unwrap() .expect("create_proof errored"); @@ -1483,12 +1509,13 @@ mod test { #[test] fn absence_proof() { + let grove_version = GroveVersion::latest(); let mut tree = make_3_node_tree(); let mut walker = RefWalker::new(&mut tree, PanicSource {}); let query_items = vec![QueryItem::Key(vec![6])]; let (proof, absence, ..) = walker - .create_full_proof(query_items.as_slice(), None, true) + .create_proof(query_items.as_slice(), None, true, grove_version) .unwrap() .expect("create_proof errored"); @@ -1540,6 +1567,7 @@ mod test { #[test] fn doc_proof() { + let grove_version = GroveVersion::latest(); let mut tree = TreeNode::new(vec![5], vec![5], None, BasicMerkNode) .unwrap() .attach( @@ -1622,7 +1650,7 @@ mod test { QueryItem::Key(vec![4]), ]; let (proof, absence, ..) = walker - .create_full_proof(query_items.as_slice(), None, true) + .create_proof(query_items.as_slice(), None, true, grove_version) .unwrap() .expect("create_proof errored"); @@ -1779,14 +1807,15 @@ mod test { #[test] fn range_proof() { - let mut tree = make_tree_seq(10); + let grove_version = GroveVersion::latest(); + let mut tree = make_tree_seq(10, grove_version); let mut walker = RefWalker::new(&mut tree, PanicSource {}); let query_items = vec![QueryItem::Range( vec![0, 0, 0, 0, 0, 0, 0, 5]..vec![0, 0, 0, 0, 0, 0, 0, 7], )]; let (proof, absence, ..) = walker - .create_full_proof(query_items.as_slice(), None, true) + .create_proof(query_items.as_slice(), None, true, grove_version) .unwrap() .expect("create_proof errored"); @@ -1880,14 +1909,14 @@ mod test { assert_eq!(res.limit, None); // right to left test - let mut tree = make_tree_seq(10); + let mut tree = make_tree_seq(10, grove_version); let mut walker = RefWalker::new(&mut tree, PanicSource {}); let query_items = vec![QueryItem::Range( vec![0, 0, 0, 0, 0, 0, 0, 5]..vec![0, 0, 0, 0, 0, 0, 0, 7], )]; let (proof, ..) = walker - .create_full_proof(query_items.as_slice(), None, false) + .create_proof(query_items.as_slice(), None, false, grove_version) .unwrap() .expect("create_proof errored"); @@ -1912,14 +1941,15 @@ mod test { #[test] fn range_proof_inclusive() { - let mut tree = make_tree_seq(10); + let grove_version = GroveVersion::latest(); + let mut tree = make_tree_seq(10, grove_version); let mut walker = RefWalker::new(&mut tree, PanicSource {}); let query_items = vec![QueryItem::RangeInclusive( vec![0, 0, 0, 0, 0, 0, 0, 5]..=vec![0, 0, 0, 0, 0, 0, 0, 7], )]; let (proof, absence, ..) = walker - .create_full_proof(query_items.as_slice(), None, true) + .create_proof(query_items.as_slice(), None, true, grove_version) .unwrap() .expect("create_proof errored"); @@ -2015,14 +2045,14 @@ mod test { assert_eq!(res.limit, None); // right_to_left proof - let mut tree = make_tree_seq(10); + let mut tree = make_tree_seq(10, grove_version); let mut walker = RefWalker::new(&mut tree, PanicSource {}); let query_items = vec![QueryItem::RangeInclusive( vec![0, 0, 0, 0, 0, 0, 0, 5]..=vec![0, 0, 0, 0, 0, 0, 0, 7], )]; let (proof, ..) = walker - .create_full_proof(query_items.as_slice(), None, false) + .create_proof(query_items.as_slice(), None, false, grove_version) .unwrap() .expect("create_proof errored"); @@ -2049,12 +2079,13 @@ mod test { #[test] fn range_from_proof() { + let grove_version = GroveVersion::latest(); let mut tree = make_6_node_tree(); let mut walker = RefWalker::new(&mut tree, PanicSource {}); let query_items = vec![QueryItem::RangeFrom(vec![5]..)]; let (proof, absence, ..) = walker - .create_full_proof(query_items.as_slice(), None, true) + .create_proof(query_items.as_slice(), None, true, grove_version) .unwrap() .expect("create_proof errored"); @@ -2127,13 +2158,13 @@ mod test { let query_items = vec![QueryItem::RangeFrom(vec![5]..)]; let (proof, absence, ..) = walker - .create_full_proof(query_items.as_slice(), Some(1), true) + .create_proof(query_items.as_slice(), Some(1), true, grove_version) .unwrap() .expect("create_proof errored"); let equivalent_query_items = vec![QueryItem::Key(vec![5])]; let (equivalent_proof, equivalent_absence, ..) = walker - .create_full_proof(equivalent_query_items.as_slice(), None, true) + .create_proof(equivalent_query_items.as_slice(), None, true, grove_version) .unwrap() .expect("create_proof errored"); @@ -2159,7 +2190,7 @@ mod test { let query_items = vec![QueryItem::RangeFrom(vec![5]..)]; let (proof, absence, ..) = walker - .create_full_proof(query_items.as_slice(), Some(2), true) + .create_proof(query_items.as_slice(), Some(2), true, grove_version) .unwrap() .expect("create_proof errored"); @@ -2169,7 +2200,7 @@ mod test { QueryItem::Key(vec![7]), ]; let (equivalent_proof, equivalent_absence, ..) = walker - .create_full_proof(equivalent_query_items.as_slice(), None, true) + .create_proof(equivalent_query_items.as_slice(), None, true, grove_version) .unwrap() .expect("create_proof errored"); @@ -2198,13 +2229,13 @@ mod test { let query_items = vec![QueryItem::RangeFrom(vec![5]..)]; let (proof, absence, ..) = walker - .create_full_proof(query_items.as_slice(), Some(100), true) + .create_proof(query_items.as_slice(), Some(100), true, grove_version) .unwrap() .expect("create_proof errored"); let equivalent_query_items = vec![QueryItem::RangeFrom(vec![5]..)]; let (equivalent_proof, equivalent_absence, ..) = walker - .create_full_proof(equivalent_query_items.as_slice(), None, true) + .create_proof(equivalent_query_items.as_slice(), None, true, grove_version) .unwrap() .expect("create_proof errored"); @@ -2233,7 +2264,7 @@ mod test { let query_items = vec![QueryItem::RangeFrom(vec![5]..)]; let (proof, absence, ..) = walker - .create_full_proof(query_items.as_slice(), None, false) + .create_proof(query_items.as_slice(), None, false, grove_version) .unwrap() .expect("create_proof errored"); @@ -2257,12 +2288,13 @@ mod test { #[test] fn range_to_proof() { + let grove_version = GroveVersion::latest(); let mut tree = make_6_node_tree(); let mut walker = RefWalker::new(&mut tree, PanicSource {}); let query_items = vec![QueryItem::RangeTo(..vec![6])]; let (proof, absence, ..) = walker - .create_full_proof(query_items.as_slice(), None, true) + .create_proof(query_items.as_slice(), None, true, grove_version) .unwrap() .expect("create_proof errored"); @@ -2363,13 +2395,13 @@ mod test { let query_items = vec![QueryItem::RangeTo(..vec![6])]; let (proof, absence, ..) = walker - .create_full_proof(query_items.as_slice(), Some(1), true) + .create_proof(query_items.as_slice(), Some(1), true, grove_version) .unwrap() .expect("create_proof errored"); let equivalent_query_items = vec![QueryItem::RangeToInclusive(..=vec![2])]; let (equivalent_proof, equivalent_absence, ..) = walker - .create_full_proof(equivalent_query_items.as_slice(), None, true) + .create_proof(equivalent_query_items.as_slice(), None, true, grove_version) .unwrap() .expect("create_proof errored"); @@ -2395,13 +2427,13 @@ mod test { let query_items = vec![QueryItem::RangeTo(..vec![6])]; let (proof, absence, ..) = walker - .create_full_proof(query_items.as_slice(), Some(2), true) + .create_proof(query_items.as_slice(), Some(2), true, grove_version) .unwrap() .expect("create_proof errored"); let equivalent_query_items = vec![QueryItem::RangeToInclusive(..=vec![3])]; let (equivalent_proof, equivalent_absence, ..) = walker - .create_full_proof(equivalent_query_items.as_slice(), None, true) + .create_proof(equivalent_query_items.as_slice(), None, true, grove_version) .unwrap() .expect("create_proof errored"); @@ -2430,13 +2462,13 @@ mod test { let query_items = vec![QueryItem::RangeTo(..vec![6])]; let (proof, absence, ..) = walker - .create_full_proof(query_items.as_slice(), Some(100), true) + .create_proof(query_items.as_slice(), Some(100), true, grove_version) .unwrap() .expect("create_proof errored"); let equivalent_query_items = vec![QueryItem::RangeTo(..vec![6])]; let (equivalent_proof, equivalent_absence, ..) = walker - .create_full_proof(equivalent_query_items.as_slice(), None, true) + .create_proof(equivalent_query_items.as_slice(), None, true, grove_version) .unwrap() .expect("create_proof errored"); @@ -2470,7 +2502,7 @@ mod test { let query_items = vec![QueryItem::RangeTo(..vec![6])]; let (proof, absence, ..) = walker - .create_full_proof(query_items.as_slice(), None, false) + .create_proof(query_items.as_slice(), None, false, grove_version) .unwrap() .expect("create_proof errored"); @@ -2501,7 +2533,7 @@ mod test { let query_items = vec![QueryItem::RangeTo(..vec![6])]; let (proof, absence, ..) = walker - .create_full_proof(query_items.as_slice(), Some(2), false) + .create_proof(query_items.as_slice(), Some(2), false, grove_version) .unwrap() .expect("create_proof errored"); @@ -2526,12 +2558,13 @@ mod test { #[test] fn range_to_proof_inclusive() { + let grove_version = GroveVersion::latest(); let mut tree = make_6_node_tree(); let mut walker = RefWalker::new(&mut tree, PanicSource {}); let query_items = vec![QueryItem::RangeToInclusive(..=vec![6])]; let (proof, absence, ..) = walker - .create_full_proof(query_items.as_slice(), None, true) + .create_proof(query_items.as_slice(), None, true, grove_version) .unwrap() .expect("create_proof errored"); @@ -2632,13 +2665,13 @@ mod test { let query_items = vec![QueryItem::RangeToInclusive(..=vec![6])]; let (proof, absence, ..) = walker - .create_full_proof(query_items.as_slice(), Some(1), true) + .create_proof(query_items.as_slice(), Some(1), true, grove_version) .unwrap() .expect("create_proof errored"); let equivalent_query_items = vec![QueryItem::RangeToInclusive(..=vec![2])]; let (equivalent_proof, equivalent_absence, ..) = walker - .create_full_proof(equivalent_query_items.as_slice(), None, true) + .create_proof(equivalent_query_items.as_slice(), None, true, grove_version) .unwrap() .expect("create_proof errored"); @@ -2664,13 +2697,13 @@ mod test { let query_items = vec![QueryItem::RangeToInclusive(..=vec![6])]; let (proof, absence, ..) = walker - .create_full_proof(query_items.as_slice(), Some(2), true) + .create_proof(query_items.as_slice(), Some(2), true, grove_version) .unwrap() .expect("create_proof errored"); let equivalent_query_items = vec![QueryItem::RangeToInclusive(..=vec![3])]; let (equivalent_proof, equivalent_absence, ..) = walker - .create_full_proof(equivalent_query_items.as_slice(), None, true) + .create_proof(equivalent_query_items.as_slice(), None, true, grove_version) .unwrap() .expect("create_proof errored"); @@ -2699,13 +2732,13 @@ mod test { let query_items = vec![QueryItem::RangeToInclusive(..=vec![6])]; let (proof, absence, ..) = walker - .create_full_proof(query_items.as_slice(), Some(100), true) + .create_proof(query_items.as_slice(), Some(100), true, grove_version) .unwrap() .expect("create_proof errored"); let equivalent_query_items = vec![QueryItem::RangeToInclusive(..=vec![6])]; let (equivalent_proof, equivalent_absence, ..) = walker - .create_full_proof(equivalent_query_items.as_slice(), None, true) + .create_proof(equivalent_query_items.as_slice(), None, true, grove_version) .unwrap() .expect("create_proof errored"); @@ -2739,7 +2772,7 @@ mod test { let query_items = vec![QueryItem::RangeToInclusive(..=vec![6])]; let (proof, absence, ..) = walker - .create_full_proof(query_items.as_slice(), None, false) + .create_proof(query_items.as_slice(), None, false, grove_version) .unwrap() .expect("create_proof errored"); @@ -2770,7 +2803,7 @@ mod test { let query_items = vec![QueryItem::RangeToInclusive(..=vec![6])]; let (proof, absence, ..) = walker - .create_full_proof(query_items.as_slice(), Some(1), false) + .create_proof(query_items.as_slice(), Some(1), false, grove_version) .unwrap() .expect("create_proof errored"); @@ -2792,12 +2825,13 @@ mod test { #[test] fn range_after_proof() { + let grove_version = GroveVersion::latest(); let mut tree = make_6_node_tree(); let mut walker = RefWalker::new(&mut tree, PanicSource {}); - let query_items = vec![RangeAfter(vec![3]..)]; + let query_items = vec![QueryItem::RangeAfter(vec![3]..)]; let (proof, absence, ..) = walker - .create_full_proof(query_items.as_slice(), None, true) + .create_proof(query_items.as_slice(), None, true, grove_version) .unwrap() .expect("create_proof errored"); @@ -2898,13 +2932,13 @@ mod test { let query_items = vec![QueryItem::RangeAfter(vec![3]..)]; let (proof, absence, ..) = walker - .create_full_proof(query_items.as_slice(), Some(1), true) + .create_proof(query_items.as_slice(), Some(1), true, grove_version) .unwrap() .expect("create_proof errored"); let equivalent_query_items = vec![QueryItem::RangeAfterToInclusive(vec![3]..=vec![4])]; let (equivalent_proof, equivalent_absence, ..) = walker - .create_full_proof(equivalent_query_items.as_slice(), None, true) + .create_proof(equivalent_query_items.as_slice(), None, true, grove_version) .unwrap() .expect("create_proof errored"); @@ -2930,13 +2964,13 @@ mod test { let query_items = vec![QueryItem::RangeAfter(vec![3]..)]; let (proof, absence, ..) = walker - .create_full_proof(query_items.as_slice(), Some(2), true) + .create_proof(query_items.as_slice(), Some(2), true, grove_version) .unwrap() .expect("create_proof errored"); let equivalent_query_items = vec![QueryItem::RangeAfterToInclusive(vec![3]..=vec![5])]; let (equivalent_proof, equivalent_absence, ..) = walker - .create_full_proof(equivalent_query_items.as_slice(), None, true) + .create_proof(equivalent_query_items.as_slice(), None, true, grove_version) .unwrap() .expect("create_proof errored"); @@ -2965,13 +2999,13 @@ mod test { let query_items = vec![QueryItem::RangeAfter(vec![3]..)]; let (proof, absence, ..) = walker - .create_full_proof(query_items.as_slice(), Some(100), true) + .create_proof(query_items.as_slice(), Some(100), true, grove_version) .unwrap() .expect("create_proof errored"); let equivalent_query_items = vec![QueryItem::RangeAfter(vec![3]..)]; let (equivalent_proof, equivalent_absence, ..) = walker - .create_full_proof(equivalent_query_items.as_slice(), None, true) + .create_proof(equivalent_query_items.as_slice(), None, true, grove_version) .unwrap() .expect("create_proof errored"); @@ -3003,9 +3037,9 @@ mod test { let mut tree = make_6_node_tree(); let mut walker = RefWalker::new(&mut tree, PanicSource {}); - let query_items = vec![RangeAfter(vec![3]..)]; + let query_items = vec![QueryItem::RangeAfter(vec![3]..)]; let (proof, absence, ..) = walker - .create_full_proof(query_items.as_slice(), None, false) + .create_proof(query_items.as_slice(), None, false, grove_version) .unwrap() .expect("create_proof errored"); @@ -3034,9 +3068,9 @@ mod test { let mut tree = make_6_node_tree(); let mut walker = RefWalker::new(&mut tree, PanicSource {}); - let query_items = vec![RangeAfter(vec![3]..)]; + let query_items = vec![QueryItem::RangeAfter(vec![3]..)]; let (proof, absence, ..) = walker - .create_full_proof(query_items.as_slice(), Some(3), false) + .create_proof(query_items.as_slice(), Some(3), false, grove_version) .unwrap() .expect("create_proof errored"); @@ -3061,12 +3095,13 @@ mod test { #[test] fn range_after_to_proof() { + let grove_version = GroveVersion::latest(); let mut tree = make_6_node_tree(); let mut walker = RefWalker::new(&mut tree, PanicSource {}); let query_items = vec![QueryItem::RangeAfterTo(vec![3]..vec![7])]; let (proof, absence, ..) = walker - .create_full_proof(query_items.as_slice(), None, true) + .create_proof(query_items.as_slice(), None, true, grove_version) .unwrap() .expect("create_proof errored"); @@ -3157,13 +3192,13 @@ mod test { let query_items = vec![QueryItem::RangeAfterTo(vec![3]..vec![7])]; let (proof, absence, ..) = walker - .create_full_proof(query_items.as_slice(), Some(1), true) + .create_proof(query_items.as_slice(), Some(1), true, grove_version) .unwrap() .expect("create_proof errored"); let equivalent_query_items = vec![QueryItem::RangeAfterToInclusive(vec![3]..=vec![4])]; let (equivalent_proof, equivalent_absence, ..) = walker - .create_full_proof(equivalent_query_items.as_slice(), None, true) + .create_proof(equivalent_query_items.as_slice(), None, true, grove_version) .unwrap() .expect("create_proof errored"); @@ -3189,13 +3224,13 @@ mod test { let query_items = vec![QueryItem::RangeAfterTo(vec![3]..vec![7])]; let (proof, absence, ..) = walker - .create_full_proof(query_items.as_slice(), Some(2), true) + .create_proof(query_items.as_slice(), Some(2), true, grove_version) .unwrap() .expect("create_proof errored"); let equivalent_query_items = vec![QueryItem::RangeAfterToInclusive(vec![3]..=vec![5])]; let (equivalent_proof, equivalent_absence, ..) = walker - .create_full_proof(equivalent_query_items.as_slice(), None, true) + .create_proof(equivalent_query_items.as_slice(), None, true, grove_version) .unwrap() .expect("create_proof errored"); @@ -3224,13 +3259,13 @@ mod test { let query_items = vec![QueryItem::RangeAfterTo(vec![3]..vec![7])]; let (proof, absence, ..) = walker - .create_full_proof(query_items.as_slice(), Some(100), true) + .create_proof(query_items.as_slice(), Some(100), true, grove_version) .unwrap() .expect("create_proof errored"); let equivalent_query_items = vec![QueryItem::RangeAfterTo(vec![3]..vec![7])]; let (equivalent_proof, equivalent_absence, ..) = walker - .create_full_proof(equivalent_query_items.as_slice(), None, true) + .create_proof(equivalent_query_items.as_slice(), None, true, grove_version) .unwrap() .expect("create_proof errored"); @@ -3259,7 +3294,7 @@ mod test { let query_items = vec![QueryItem::RangeAfterTo(vec![3]..vec![7])]; let (proof, absence, ..) = walker - .create_full_proof(query_items.as_slice(), None, false) + .create_proof(query_items.as_slice(), None, false, grove_version) .unwrap() .expect("create_proof errored"); @@ -3285,7 +3320,7 @@ mod test { let query_items = vec![QueryItem::RangeAfterTo(vec![3]..vec![7])]; let (proof, absence, ..) = walker - .create_full_proof(query_items.as_slice(), Some(300), false) + .create_proof(query_items.as_slice(), Some(300), false, grove_version) .unwrap() .expect("create_proof errored"); @@ -3310,12 +3345,13 @@ mod test { #[test] fn range_after_to_proof_inclusive() { + let grove_version = GroveVersion::latest(); let mut tree = make_6_node_tree(); let mut walker = RefWalker::new(&mut tree, PanicSource {}); let query_items = vec![QueryItem::RangeAfterToInclusive(vec![3]..=vec![7])]; let (proof, absence, ..) = walker - .create_full_proof(query_items.as_slice(), None, true) + .create_proof(query_items.as_slice(), None, true, grove_version) .unwrap() .expect("create_proof errored"); @@ -3405,13 +3441,13 @@ mod test { let query_items = vec![QueryItem::RangeAfterToInclusive(vec![3]..=vec![7])]; let (proof, absence, ..) = walker - .create_full_proof(query_items.as_slice(), Some(1), true) + .create_proof(query_items.as_slice(), Some(1), true, grove_version) .unwrap() .expect("create_proof errored"); let equivalent_query_items = vec![QueryItem::RangeAfterToInclusive(vec![3]..=vec![4])]; let (equivalent_proof, equivalent_absence, ..) = walker - .create_full_proof(equivalent_query_items.as_slice(), None, true) + .create_proof(equivalent_query_items.as_slice(), None, true, grove_version) .unwrap() .expect("create_proof errored"); @@ -3437,13 +3473,13 @@ mod test { let query_items = vec![QueryItem::RangeAfterToInclusive(vec![3]..=vec![7])]; let (proof, absence, ..) = walker - .create_full_proof(query_items.as_slice(), Some(2), true) + .create_proof(query_items.as_slice(), Some(2), true, grove_version) .unwrap() .expect("create_proof errored"); let equivalent_query_items = vec![QueryItem::RangeAfterToInclusive(vec![3]..=vec![5])]; let (equivalent_proof, equivalent_absence, ..) = walker - .create_full_proof(equivalent_query_items.as_slice(), None, true) + .create_proof(equivalent_query_items.as_slice(), None, true, grove_version) .unwrap() .expect("create_proof errored"); @@ -3472,13 +3508,13 @@ mod test { let query_items = vec![QueryItem::RangeAfterToInclusive(vec![3]..=vec![7])]; let (proof, absence, ..) = walker - .create_full_proof(query_items.as_slice(), Some(100), true) + .create_proof(query_items.as_slice(), Some(100), true, grove_version) .unwrap() .expect("create_proof errored"); let equivalent_query_items = vec![QueryItem::RangeAfterToInclusive(vec![3]..=vec![7])]; let (equivalent_proof, equivalent_absence, ..) = walker - .create_full_proof(equivalent_query_items.as_slice(), None, true) + .create_proof(equivalent_query_items.as_slice(), None, true, grove_version) .unwrap() .expect("create_proof errored"); @@ -3507,7 +3543,7 @@ mod test { let query_items = vec![QueryItem::RangeAfterToInclusive(vec![3]..=vec![7])]; let (proof, absence, ..) = walker - .create_full_proof(query_items.as_slice(), None, false) + .create_proof(query_items.as_slice(), None, false, grove_version) .unwrap() .expect("create_proof errored"); @@ -3531,12 +3567,13 @@ mod test { #[test] fn range_full_proof() { + let grove_version = GroveVersion::latest(); let mut tree = make_6_node_tree(); let mut walker = RefWalker::new(&mut tree, PanicSource {}); let query_items = vec![QueryItem::RangeFull(..)]; let (proof, absence, ..) = walker - .create_full_proof(query_items.as_slice(), None, true) + .create_proof(query_items.as_slice(), None, true, grove_version) .unwrap() .expect("create_proof errored"); @@ -3645,13 +3682,13 @@ mod test { let query_items = vec![QueryItem::RangeFull(..)]; let (proof, absence, ..) = walker - .create_full_proof(query_items.as_slice(), Some(1), true) + .create_proof(query_items.as_slice(), Some(1), true, grove_version) .unwrap() .expect("create_proof errored"); let equivalent_query_items = vec![QueryItem::RangeToInclusive(..=vec![2])]; let (equivalent_proof, equivalent_absence, ..) = walker - .create_full_proof(equivalent_query_items.as_slice(), None, true) + .create_proof(equivalent_query_items.as_slice(), None, true, grove_version) .unwrap() .expect("create_proof errored"); @@ -3677,13 +3714,13 @@ mod test { let query_items = vec![QueryItem::RangeFull(..)]; let (proof, absence, ..) = walker - .create_full_proof(query_items.as_slice(), Some(2), true) + .create_proof(query_items.as_slice(), Some(2), true, grove_version) .unwrap() .expect("create_proof errored"); let equivalent_query_items = vec![QueryItem::RangeToInclusive(..=vec![3])]; let (equivalent_proof, equivalent_absence, ..) = walker - .create_full_proof(equivalent_query_items.as_slice(), None, true) + .create_proof(equivalent_query_items.as_slice(), None, true, grove_version) .unwrap() .expect("create_proof errored"); @@ -3712,13 +3749,13 @@ mod test { let query_items = vec![QueryItem::RangeFull(..)]; let (proof, absence, ..) = walker - .create_full_proof(query_items.as_slice(), Some(100), true) + .create_proof(query_items.as_slice(), Some(100), true, grove_version) .unwrap() .expect("create_proof errored"); let equivalent_query_items = vec![QueryItem::RangeFull(..)]; let (equivalent_proof, equivalent_absence, ..) = walker - .create_full_proof(equivalent_query_items.as_slice(), None, true) + .create_proof(equivalent_query_items.as_slice(), None, true, grove_version) .unwrap() .expect("create_proof errored"); @@ -3754,7 +3791,7 @@ mod test { let query_items = vec![QueryItem::RangeFull(..)]; let (proof, absence, ..) = walker - .create_full_proof(query_items.as_slice(), None, false) + .create_proof(query_items.as_slice(), None, false, grove_version) .unwrap() .expect("create_proof errored"); @@ -3787,7 +3824,7 @@ mod test { let query_items = vec![QueryItem::RangeFull(..)]; let (proof, absence, ..) = walker - .create_full_proof(query_items.as_slice(), Some(2), false) + .create_proof(query_items.as_slice(), Some(2), false, grove_version) .unwrap() .expect("create_proof errored"); @@ -3812,12 +3849,13 @@ mod test { #[test] fn proof_with_limit() { + let grove_version = GroveVersion::latest(); let mut tree = make_6_node_tree(); let mut walker = RefWalker::new(&mut tree, PanicSource {}); let query_items = vec![QueryItem::RangeFrom(vec![2]..)]; let (proof, _, limit) = walker - .create_full_proof(query_items.as_slice(), Some(1), true) + .create_proof(query_items.as_slice(), Some(1), true, grove_version) .unwrap() .expect("create_proof errored"); @@ -3886,12 +3924,13 @@ mod test { #[test] fn right_to_left_proof() { + let grove_version = GroveVersion::latest(); let mut tree = make_6_node_tree(); let mut walker = RefWalker::new(&mut tree, PanicSource {}); let query_items = vec![QueryItem::RangeFrom(vec![3]..)]; let (proof, absence, ..) = walker - .create_full_proof(query_items.as_slice(), None, false) + .create_proof(query_items.as_slice(), None, false, grove_version) .unwrap() .expect("create_proof errored"); @@ -3991,14 +4030,15 @@ mod test { #[test] fn range_proof_missing_upper_bound() { - let mut tree = make_tree_seq(10); + let grove_version = GroveVersion::latest(); + let mut tree = make_tree_seq(10, grove_version); let mut walker = RefWalker::new(&mut tree, PanicSource {}); let query_items = vec![QueryItem::Range( vec![0, 0, 0, 0, 0, 0, 0, 5]..vec![0, 0, 0, 0, 0, 0, 0, 6, 5], )]; let (proof, absence, ..) = walker - .create_full_proof(query_items.as_slice(), None, true) + .create_proof(query_items.as_slice(), None, true, grove_version) .unwrap() .expect("create_proof errored"); @@ -4093,7 +4133,8 @@ mod test { #[test] fn range_proof_missing_lower_bound() { - let mut tree = make_tree_seq(10); + let grove_version = GroveVersion::latest(); + let mut tree = make_tree_seq(10, grove_version); let mut walker = RefWalker::new(&mut tree, PanicSource {}); let query_items = vec![ @@ -4101,7 +4142,7 @@ mod test { QueryItem::Range(vec![0, 0, 0, 0, 0, 0, 0, 5, 5]..vec![0, 0, 0, 0, 0, 0, 0, 7]), ]; let (proof, absence, ..) = walker - .create_full_proof(query_items.as_slice(), None, true) + .create_proof(query_items.as_slice(), None, true, grove_version) .unwrap() .expect("create_proof errored"); @@ -4192,7 +4233,8 @@ mod test { #[test] fn subset_proof() { - let mut tree = make_tree_seq(10); + let grove_version = GroveVersion::latest(); + let mut tree = make_tree_seq(10, grove_version); let expected_hash = tree.hash().unwrap().to_owned(); let mut walker = RefWalker::new(&mut tree, PanicSource {}); @@ -4201,7 +4243,7 @@ mod test { query.insert_all(); let (proof, ..) = walker - .create_full_proof(query.items.as_slice(), None, true) + .create_proof(query.items.as_slice(), None, true, grove_version) .unwrap() .expect("create_proof errored"); @@ -4228,7 +4270,7 @@ mod test { query.insert_range_inclusive(vec![0, 0, 0, 0, 0, 0, 0, 2]..=vec![0, 0, 0, 0, 0, 0, 0, 5]); query.insert_range(vec![0, 0, 0, 0, 0, 0, 0, 7]..vec![0, 0, 0, 0, 0, 0, 0, 10]); let (proof, ..) = walker - .create_full_proof(query.items.as_slice(), None, true) + .create_proof(query.items.as_slice(), None, true, grove_version) .unwrap() .expect("create_proof errored"); @@ -4259,7 +4301,7 @@ mod test { query.insert_range_inclusive(vec![0, 0, 0, 0, 0, 0, 0, 2]..=vec![0, 0, 0, 0, 0, 0, 0, 5]); query.insert_range(vec![0, 0, 0, 0, 0, 0, 0, 6]..vec![0, 0, 0, 0, 0, 0, 0, 10]); let (proof, ..) = walker - .create_full_proof(query.items.as_slice(), None, true) + .create_proof(query.items.as_slice(), None, true, grove_version) .unwrap() .expect("create_proof errored"); @@ -4290,7 +4332,7 @@ mod test { query.insert_range_inclusive(vec![0, 0, 0, 0, 0, 0, 0, 1]..=vec![0, 0, 0, 0, 0, 0, 0, 3]); query.insert_range_inclusive(vec![0, 0, 0, 0, 0, 0, 0, 2]..=vec![0, 0, 0, 0, 0, 0, 0, 5]); let (proof, ..) = walker - .create_full_proof(query.items.as_slice(), None, true) + .create_proof(query.items.as_slice(), None, true, grove_version) .unwrap() .expect("create_proof errored"); @@ -4320,7 +4362,7 @@ mod test { let mut query = Query::new(); query.insert_range_from(vec![0, 0, 0, 0, 0, 0, 0, 1]..); let (proof, ..) = walker - .create_full_proof(query.items.as_slice(), Some(5), true) + .create_proof(query.items.as_slice(), Some(5), true, grove_version) .unwrap() .expect("create_proof errored"); @@ -4349,6 +4391,7 @@ mod test { #[test] fn break_subset_proof() { + let grove_version = GroveVersion::latest(); // TODO: move this to where you'd set the constraints for this definition // goal is to show that ones limit and offset values are involved // whether a query is subset or not now also depends on the state @@ -4358,7 +4401,7 @@ mod test { // with limit and offset the nodes a query highlights now depends on state // hence it's impossible to know if something is subset at definition time - let mut tree = make_tree_seq(10); + let mut tree = make_tree_seq(10, grove_version); let expected_hash = tree.hash().unwrap().to_owned(); let mut walker = RefWalker::new(&mut tree, PanicSource {}); @@ -4366,7 +4409,7 @@ mod test { let mut query = Query::new(); query.insert_range_from(vec![0, 0, 0, 0, 0, 0, 0, 1]..); let (proof, ..) = walker - .create_full_proof(query.items.as_slice(), Some(3), true) + .create_proof(query.items.as_slice(), Some(3), true, grove_version) .unwrap() .expect("create_proof errored"); @@ -4444,6 +4487,7 @@ mod test { #[test] fn verify_ops() { + let grove_version = GroveVersion::latest(); let mut tree = TreeNode::new(vec![5], vec![5], None, BasicMerkNode).unwrap(); tree.commit(&mut NoopCommit {}, &|_, _| Ok(0)) .unwrap() @@ -4453,7 +4497,12 @@ mod test { let mut walker = RefWalker::new(&mut tree, PanicSource {}); let (proof, ..) = walker - .create_full_proof(vec![QueryItem::Key(vec![5])].as_slice(), None, true) + .create_proof( + vec![QueryItem::Key(vec![5])].as_slice(), + None, + true, + grove_version, + ) .unwrap() .expect("failed to create proof"); let mut bytes = vec![]; @@ -4470,6 +4519,7 @@ mod test { #[test] #[should_panic(expected = "verify failed")] fn verify_ops_mismatched_hash() { + let grove_version = GroveVersion::latest(); let mut tree = TreeNode::new(vec![5], vec![5], None, BasicMerkNode).unwrap(); tree.commit(&mut NoopCommit {}, &|_, _| Ok(0)) .unwrap() @@ -4478,7 +4528,12 @@ mod test { let mut walker = RefWalker::new(&mut tree, PanicSource {}); let (proof, ..) = walker - .create_full_proof(vec![QueryItem::Key(vec![5])].as_slice(), None, true) + .create_proof( + vec![QueryItem::Key(vec![5])].as_slice(), + None, + true, + grove_version, + ) .unwrap() .expect("failed to create proof"); let mut bytes = vec![]; @@ -4493,11 +4548,12 @@ mod test { #[test] #[should_panic(expected = "verify failed")] fn verify_query_mismatched_hash() { + let grove_version = GroveVersion::latest(); let mut tree = make_3_node_tree(); let mut walker = RefWalker::new(&mut tree, PanicSource {}); let keys = vec![vec![5], vec![7]]; let (proof, ..) = walker - .create_full_proof( + .create_proof( keys.clone() .into_iter() .map(QueryItem::Key) @@ -4505,6 +4561,7 @@ mod test { .as_slice(), None, true, + grove_version, ) .unwrap() .expect("failed to create proof"); diff --git a/merk/src/test_utils/mod.rs b/merk/src/test_utils/mod.rs index d5d76673..397ad13a 100644 --- a/merk/src/test_utils/mod.rs +++ b/merk/src/test_utils/mod.rs @@ -35,6 +35,7 @@ use std::{convert::TryInto, ops::Range}; use grovedb_costs::storage_cost::removal::StorageRemovedBytes::BasicStorageRemoval; use grovedb_path::SubtreePath; use grovedb_storage::{Storage, StorageBatch}; +use grovedb_version::version::GroveVersion; use rand::prelude::*; pub use temp_merk::TempMerk; @@ -74,7 +75,11 @@ pub fn assert_tree_invariants(tree: &TreeNode) { /// Apply given batch to given tree and commit using memory only. /// Used by `apply_memonly` which also performs checks using /// `assert_tree_invariants`. Return Tree. -pub fn apply_memonly_unchecked(tree: TreeNode, batch: &MerkBatch>) -> TreeNode { +pub fn apply_memonly_unchecked( + tree: TreeNode, + batch: &MerkBatch>, + grove_version: &GroveVersion, +) -> TreeNode { let is_sum_node = tree.is_sum_node(); let walker = Walker::::new(tree, PanicSource {}); let mut tree = Walker::::apply_to( @@ -88,7 +93,7 @@ pub fn apply_memonly_unchecked(tree: TreeNode, batch: &MerkBatch>) -> Tr is_sum_node, )) }, - None::<&fn(&[u8]) -> Option>, + None::<&fn(&[u8], &GroveVersion) -> Option>, &mut |_, _, _| Ok((false, None)), &mut |_flags, key_bytes_to_remove, value_bytes_to_remove| { Ok(( @@ -96,6 +101,7 @@ pub fn apply_memonly_unchecked(tree: TreeNode, batch: &MerkBatch>) -> Tr BasicStorageRemoval(value_bytes_to_remove), )) }, + grove_version, ) .unwrap() .expect("apply failed") @@ -116,8 +122,12 @@ pub fn apply_memonly_unchecked(tree: TreeNode, batch: &MerkBatch>) -> Tr /// Apply given batch to given tree and commit using memory only. /// Perform checks using `assert_tree_invariants`. Return Tree. -pub fn apply_memonly(tree: TreeNode, batch: &MerkBatch>) -> TreeNode { - let tree = apply_memonly_unchecked(tree, batch); +pub fn apply_memonly( + tree: TreeNode, + batch: &MerkBatch>, + grove_version: &GroveVersion, +) -> TreeNode { + let tree = apply_memonly_unchecked(tree, batch, grove_version); assert_tree_invariants(&tree); tree } @@ -128,6 +138,7 @@ pub fn apply_to_memonly( maybe_tree: Option, batch: &MerkBatch>, is_sum_tree: bool, + grove_version: &GroveVersion, ) -> Option { let maybe_walker = maybe_tree.map(|tree| Walker::::new(tree, PanicSource {})); Walker::::apply_to( @@ -141,7 +152,7 @@ pub fn apply_to_memonly( is_sum_tree, )) }, - None::<&fn(&[u8]) -> Option>, + None::<&fn(&[u8], &GroveVersion) -> Option>, &mut |_, _, _| Ok((false, None)), &mut |_flags, key_bytes_to_remove, value_bytes_to_remove| { Ok(( @@ -149,6 +160,7 @@ pub fn apply_to_memonly( BasicStorageRemoval(value_bytes_to_remove), )) }, + grove_version, ) .unwrap() .expect("apply failed") @@ -234,6 +246,7 @@ pub fn make_tree_rand( batch_size: u64, initial_seed: u64, is_sum_tree: bool, + grove_version: &GroveVersion, ) -> TreeNode { assert!(node_count >= batch_size); assert_eq!((node_count % batch_size), 0); @@ -251,7 +264,7 @@ pub fn make_tree_rand( let batch_count = node_count / batch_size; for _ in 0..batch_count { let batch = make_batch_rand(batch_size, seed); - tree = apply_memonly(tree, &batch); + tree = apply_memonly(tree, &batch, grove_version); seed += 1; } @@ -261,14 +274,18 @@ pub fn make_tree_rand( /// Create tree with initial fixed values and apply `node count` Put ops using /// sequential keys using memory only /// starting tree node is [0; 20] -pub fn make_tree_seq(node_count: u64) -> TreeNode { - make_tree_seq_with_start_key(node_count, [0; 20].to_vec()) +pub fn make_tree_seq(node_count: u64, grove_version: &GroveVersion) -> TreeNode { + make_tree_seq_with_start_key(node_count, [0; 20].to_vec(), grove_version) } /// Create tree with initial fixed values and apply `node count` Put ops using /// sequential keys using memory only /// requires a starting key vector -pub fn make_tree_seq_with_start_key(node_count: u64, start_key: Vec) -> TreeNode { +pub fn make_tree_seq_with_start_key( + node_count: u64, + start_key: Vec, + grove_version: &GroveVersion, +) -> TreeNode { let batch_size = if node_count >= 10_000 { assert_eq!(node_count % 10_000, 0); 10_000 @@ -283,7 +300,7 @@ pub fn make_tree_seq_with_start_key(node_count: u64, start_key: Vec) -> Tree let batch_count = node_count / batch_size; for i in 0..batch_count { let batch = make_batch_seq((i * batch_size)..((i + 1) * batch_size)); - tree = apply_memonly(tree, &batch); + tree = apply_memonly(tree, &batch, grove_version); } tree @@ -292,6 +309,7 @@ pub fn make_tree_seq_with_start_key(node_count: u64, start_key: Vec) -> Tree pub fn empty_path_merk<'db, S>( storage: &'db S, batch: &'db StorageBatch, + grove_version: &GroveVersion, ) -> Merk<>::BatchStorageContext> where S: Storage<'db>, @@ -301,7 +319,8 @@ where .get_storage_context(SubtreePath::empty(), Some(batch)) .unwrap(), false, - None:: Option>, + None:: Option>, + grove_version, ) .unwrap() .unwrap() @@ -310,6 +329,7 @@ where /// Shortcut to open a Merk for read only pub fn empty_path_merk_read_only<'db, S>( storage: &'db S, + grove_version: &GroveVersion, ) -> Merk<>::BatchStorageContext> where S: Storage<'db>, @@ -319,7 +339,8 @@ where .get_storage_context(SubtreePath::empty(), None) .unwrap(), false, - None:: Option>, + None:: Option>, + grove_version, ) .unwrap() .unwrap() diff --git a/merk/src/test_utils/temp_merk.rs b/merk/src/test_utils/temp_merk.rs index 25e5b75c..69e5b555 100644 --- a/merk/src/test_utils/temp_merk.rs +++ b/merk/src/test_utils/temp_merk.rs @@ -38,6 +38,7 @@ use grovedb_storage::{ rocksdb_storage::{test_utils::TempStorage, PrefixedRocksDbStorageContext}, Storage, }; +use grovedb_version::version::GroveVersion; use crate::tree::kv::ValueDefinedCostType; #[cfg(feature = "full")] @@ -55,7 +56,7 @@ pub struct TempMerk { impl TempMerk { /// Opens a `TempMerk` at the given file path, creating a new one if it /// does not exist. - pub fn new() -> Self { + pub fn new(grove_version: &GroveVersion) -> Self { let storage = Box::leak(Box::new(TempStorage::new())); let batch = Box::leak(Box::new(StorageBatch::new())); @@ -66,7 +67,8 @@ impl TempMerk { let merk = Merk::open_base( context, false, - None:: Option>, + None:: Option>, + grove_version, ) .unwrap() .unwrap(); @@ -78,7 +80,7 @@ impl TempMerk { } /// Commits pending batch operations. - pub fn commit(&mut self) { + pub fn commit(&mut self, grove_version: &GroveVersion) { let batch = unsafe { Box::from_raw(self.batch as *const _ as *mut StorageBatch) }; self.storage .commit_multi_context_batch(*batch, None) @@ -92,7 +94,8 @@ impl TempMerk { self.merk = Merk::open_base( context, false, - None:: Option>, + None:: Option>, + grove_version, ) .unwrap() .unwrap(); @@ -113,7 +116,7 @@ impl Drop for TempMerk { #[cfg(feature = "full")] impl Default for TempMerk { fn default() -> Self { - Self::new() + Self::new(GroveVersion::latest()) } } diff --git a/merk/src/tree/encoding.rs b/merk/src/tree/encoding.rs index 3a97c895..cd10937d 100644 --- a/merk/src/tree/encoding.rs +++ b/merk/src/tree/encoding.rs @@ -8,6 +8,7 @@ use grovedb_costs::{ }; #[cfg(feature = "full")] use grovedb_storage::StorageContext; +use grovedb_version::version::GroveVersion; #[cfg(feature = "full")] use super::TreeNode; @@ -26,16 +27,22 @@ impl TreeNode { pub fn decode_raw( bytes: &[u8], key: Vec, - value_defined_cost_fn: Option Option>, + value_defined_cost_fn: Option< + impl Fn(&[u8], &GroveVersion) -> Option, + >, + grove_version: &GroveVersion, ) -> Result { - TreeNode::decode(key, bytes, value_defined_cost_fn).map_err(EdError) + TreeNode::decode(key, bytes, value_defined_cost_fn, grove_version).map_err(EdError) } /// Get value from storage given key. pub(crate) fn get<'db, S, K>( storage: &S, key: K, - value_defined_cost_fn: Option Option>, + value_defined_cost_fn: Option< + impl Fn(&[u8], &GroveVersion) -> Option, + >, + grove_version: &GroveVersion, ) -> CostResult, Error> where S: StorageContext<'db>, @@ -47,7 +54,12 @@ impl TreeNode { let tree_opt = cost_return_on_error_no_add!( &cost, tree_bytes - .map(|x| TreeNode::decode_raw(&x, key.as_ref().to_vec(), value_defined_cost_fn)) + .map(|x| TreeNode::decode_raw( + &x, + key.as_ref().to_vec(), + value_defined_cost_fn, + grove_version + )) .transpose() ); @@ -96,13 +108,16 @@ impl TreeNode { &mut self, key: Vec, input: &[u8], - value_defined_cost_fn: Option Option>, + value_defined_cost_fn: Option< + impl Fn(&[u8], &GroveVersion) -> Option, + >, + grove_version: &GroveVersion, ) -> ed::Result<()> { let mut tree_inner: TreeNodeInner = Decode::decode(input)?; tree_inner.kv.key = key; if let Some(value_defined_cost_fn) = value_defined_cost_fn { tree_inner.kv.value_defined_cost = - value_defined_cost_fn(tree_inner.kv.value.as_slice()); + value_defined_cost_fn(tree_inner.kv.value.as_slice(), grove_version); } self.inner = Box::new(tree_inner); Ok(()) @@ -113,13 +128,16 @@ impl TreeNode { pub fn decode( key: Vec, input: &[u8], - value_defined_cost_fn: Option Option>, + value_defined_cost_fn: Option< + impl Fn(&[u8], &GroveVersion) -> Option, + >, + grove_version: &GroveVersion, ) -> ed::Result { let mut tree_inner: TreeNodeInner = Decode::decode(input)?; tree_inner.kv.key = key; if let Some(value_defined_cost_fn) = value_defined_cost_fn { tree_inner.kv.value_defined_cost = - value_defined_cost_fn(tree_inner.kv.value.as_slice()); + value_defined_cost_fn(tree_inner.kv.value.as_slice(), grove_version); } Ok(TreeNode::new_with_tree_inner(tree_inner)) } @@ -268,6 +286,7 @@ mod tests { #[test] fn decode_leaf_tree() { + let grove_version = GroveVersion::latest(); let bytes = vec![ 0, 0, 0, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 32, 34, 236, 157, 87, 27, 167, 116, 207, 158, @@ -277,7 +296,8 @@ mod tests { let tree = TreeNode::decode( vec![0], bytes.as_slice(), - None::<&fn(&[u8]) -> Option>, + None::<&fn(&[u8], &GroveVersion) -> Option>, + grove_version, ) .expect("should decode correctly"); assert_eq!(tree.key(), &[0]); @@ -287,6 +307,7 @@ mod tests { #[test] fn decode_reference_tree() { + let grove_version = GroveVersion::latest(); let bytes = vec![ 1, 1, 2, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 123, 124, 0, 0, 0, 55, 55, 55, 55, @@ -297,7 +318,8 @@ mod tests { let tree = TreeNode::decode( vec![0], bytes.as_slice(), - None::<&fn(&[u8]) -> Option>, + None::<&fn(&[u8], &GroveVersion) -> Option>, + grove_version, ) .expect("should decode correctly"); assert_eq!(tree.key(), &[0]); @@ -319,11 +341,13 @@ mod tests { #[test] fn decode_invalid_bytes_as_tree() { + let grove_version = GroveVersion::latest(); let bytes = vec![2, 3, 4, 5]; let tree = TreeNode::decode( vec![0], bytes.as_slice(), - None::<&fn(&[u8]) -> Option>, + None::<&fn(&[u8], &GroveVersion) -> Option>, + grove_version, ); assert!(tree.is_err()); } diff --git a/merk/src/tree/fuzz_tests.rs b/merk/src/tree/fuzz_tests.rs index 2f3067d1..eb026f56 100644 --- a/merk/src/tree/fuzz_tests.rs +++ b/merk/src/tree/fuzz_tests.rs @@ -43,7 +43,13 @@ fn fuzz_396148930387069749() { fn fuzz_case(seed: u64, using_sum_trees: bool) { let mut rng: SmallRng = SeedableRng::seed_from_u64(seed); let initial_size = (rng.gen::() % 10) + 1; - let tree = make_tree_rand(initial_size, initial_size, seed, using_sum_trees); + let tree = make_tree_rand( + initial_size, + initial_size, + seed, + using_sum_trees, + grove_version, + ); let mut map = Map::from_iter(tree.iter()); let mut maybe_tree = Some(tree); println!("====== MERK FUZZ ======"); @@ -55,7 +61,7 @@ fn fuzz_case(seed: u64, using_sum_trees: bool) { let batch = make_batch(maybe_tree.as_ref(), batch_size, rng.gen::()); println!("BATCH {}", j); println!("{:?}", batch); - maybe_tree = apply_to_memonly(maybe_tree, &batch, using_sum_trees); + maybe_tree = apply_to_memonly(maybe_tree, &batch, using_sum_trees, grove_version); apply_to_map(&mut map, &batch); assert_map(maybe_tree.as_ref(), &map); if let Some(tree) = &maybe_tree { diff --git a/merk/src/tree/mod.rs b/merk/src/tree/mod.rs index 9a29dc8e..6b2710b6 100644 --- a/merk/src/tree/mod.rs +++ b/merk/src/tree/mod.rs @@ -42,6 +42,7 @@ use grovedb_costs::{ }, CostContext, CostResult, CostsExt, OperationCost, }; +use grovedb_version::version::GroveVersion; #[cfg(any(feature = "full", feature = "verify"))] pub use hash::{ combine_hash, kv_digest_to_kv_hash, kv_hash, node_hash, value_hash, CryptoHash, HASH_LENGTH, @@ -922,9 +923,10 @@ impl TreeNode { left: bool, source: &S, value_defined_cost_fn: Option<&V>, + grove_version: &GroveVersion, ) -> CostResult<(), Error> where - V: Fn(&[u8]) -> Option, + V: Fn(&[u8], &GroveVersion) -> Option, { // TODO: return Err instead of panic? let link = self.link(left).expect("Expected link"); @@ -939,7 +941,10 @@ impl TreeNode { }; let mut cost = OperationCost::default(); - let tree = cost_return_on_error!(&mut cost, source.fetch(link, value_defined_cost_fn)); + let tree = cost_return_on_error!( + &mut cost, + source.fetch(link, value_defined_cost_fn, grove_version) + ); debug_assert_eq!(tree.key(), link.key()); *self.slot_mut(left) = Some(Link::Loaded { tree, diff --git a/merk/src/tree/ops.rs b/merk/src/tree/ops.rs index 738a89df..156c7e60 100644 --- a/merk/src/tree/ops.rs +++ b/merk/src/tree/ops.rs @@ -16,6 +16,7 @@ use grovedb_costs::{ }, CostContext, CostResult, CostsExt, OperationCost, }; +use grovedb_version::version::GroveVersion; #[cfg(feature = "full")] use integer_encoding::VarInt; #[cfg(feature = "full")] @@ -40,18 +41,18 @@ pub enum Op { /// cost into the Merk tree. This is ideal for sum items where /// we want sizes to always be fixed PutWithSpecializedCost(Vec, u32, TreeFeatureType), - /// Combined references include the value in the node hash + /// `Combined references` include the value in the node hash /// because the value is independent of the reference hash /// In GroveDB this is used for references PutCombinedReference(Vec, CryptoHash, TreeFeatureType), - /// Layered references include the value in the node hash + /// `Layered references` include the value in the node hash /// because the value is independent of the reference hash /// In GroveDB this is used for trees /// A layered reference does not pay for the tree's value, /// instead providing a cost for the value PutLayeredReference(Vec, u32, CryptoHash, TreeFeatureType), /// Replacing a layered reference is slightly more efficient - /// than putting it as the replace will not modify the size + /// than putting it as the replace operation will not modify the size /// hence there is no need to calculate a difference in /// costs ReplaceLayeredReference(Vec, u32, CryptoHash, TreeFeatureType), @@ -125,7 +126,10 @@ impl Fetch for PanicSource { fn fetch( &self, _link: &Link, - _value_defined_cost_fn: Option<&impl Fn(&[u8]) -> Option>, + _value_defined_cost_fn: Option< + &impl Fn(&[u8], &GroveVersion) -> Option, + >, + _grove_version: &GroveVersion, ) -> CostResult { unreachable!("'fetch' should not have been called") } @@ -149,10 +153,11 @@ where value_defined_cost_fn: Option<&V>, update_tree_value_based_on_costs: &mut U, section_removal_bytes: &mut R, + grove_version: &GroveVersion, ) -> CostContext, KeyUpdates), Error>> where C: Fn(&Vec, &Vec) -> Result, - V: Fn(&[u8]) -> Option, + V: Fn(&[u8], &GroveVersion) -> Option, U: FnMut( &StorageCost, &Vec, @@ -182,6 +187,7 @@ where value_defined_cost_fn, update_tree_value_based_on_costs, section_removal_bytes, + grove_version, ) .map_ok(|tree| { let new_keys: BTreeSet> = batch @@ -207,7 +213,8 @@ where old_tree_cost, value_defined_cost_fn, update_tree_value_based_on_costs, - section_removal_bytes + section_removal_bytes, + grove_version ) ) } @@ -228,10 +235,11 @@ where value_defined_cost_fn: Option<&V>, update_tree_value_based_on_costs: &mut U, section_removal_bytes: &mut R, + grove_version: &GroveVersion, ) -> CostResult, Error> where C: Fn(&Vec, &Vec) -> Result, - V: Fn(&[u8]) -> Option, + V: Fn(&[u8], &GroveVersion) -> Option, U: FnMut( &StorageCost, &Vec, @@ -260,7 +268,8 @@ where old_tree_cost, value_defined_cost_fn, update_tree_value_based_on_costs, - section_removal_bytes + section_removal_bytes, + grove_version ) ) .map(|tree| Self::new(tree, source.clone())); @@ -273,7 +282,8 @@ where old_tree_cost, value_defined_cost_fn, update_tree_value_based_on_costs, - section_removal_bytes + section_removal_bytes, + grove_version ) ) .0 @@ -286,7 +296,8 @@ where old_tree_cost, value_defined_cost_fn, update_tree_value_based_on_costs, - section_removal_bytes + section_removal_bytes, + grove_version ) ) .map(|tree| Self::new(tree, source.clone())), @@ -358,6 +369,7 @@ where value_defined_cost_fn, update_tree_value_based_on_costs, section_removal_bytes, + grove_version, ) ) .0 @@ -369,11 +381,12 @@ where fn apply_sorted_without_costs>( self, batch: &MerkBatch, + grove_version: &GroveVersion, ) -> CostResult<(Option, KeyUpdates), Error> { self.apply_sorted( batch, &|_, _| Ok(0), - None::<&fn(&[u8]) -> Option>, + None::<&fn(&[u8], &GroveVersion) -> Option>, &mut |_, _, _| Ok((false, None)), &mut |_flags, key_bytes_to_remove, value_bytes_to_remove| { Ok(( @@ -381,6 +394,7 @@ where BasicStorageRemoval(value_bytes_to_remove), )) }, + grove_version, ) } @@ -395,10 +409,11 @@ where value_defined_cost_fn: Option<&V>, update_tree_value_based_on_costs: &mut U, section_removal_bytes: &mut R, + grove_version: &GroveVersion, ) -> CostResult<(Option, KeyUpdates), Error> where C: Fn(&Vec, &Vec) -> Result, - V: Fn(&[u8]) -> Option, + V: Fn(&[u8], &GroveVersion) -> Option, U: FnMut( &StorageCost, &Vec, @@ -427,7 +442,7 @@ where feature_type.to_owned(), old_specialized_cost, update_tree_value_based_on_costs, - section_removal_bytes + section_removal_bytes, ) ) } @@ -493,7 +508,7 @@ where old_specialized_cost(&key_vec, value) ) } - _ => 0, // can't get here anyways + _ => 0, // can't get here anyway }; let key_len = key_vec.len() as u32; @@ -522,8 +537,10 @@ where needs_value_verification: false, }; - let maybe_tree_walker = - cost_return_on_error!(&mut cost, self.remove(value_defined_cost_fn)); + let maybe_tree_walker = cost_return_on_error!( + &mut cost, + self.remove(value_defined_cost_fn, grove_version) + ); // If there are no more batch updates to the left this means that the index is 0 // There would be no key updates to the left of this part of the tree. @@ -550,6 +567,7 @@ where value_defined_cost_fn, update_tree_value_based_on_costs, section_removal_bytes, + grove_version, ) ); let new_keys: BTreeSet> = batch[..index] @@ -574,7 +592,8 @@ where old_specialized_cost, value_defined_cost_fn, update_tree_value_based_on_costs, - section_removal_bytes + section_removal_bytes, + grove_version ) ) } @@ -606,6 +625,7 @@ where value_defined_cost_fn, update_tree_value_based_on_costs, section_removal_bytes, + grove_version, ) ); let new_keys: BTreeSet> = batch[index + 1..] @@ -630,7 +650,8 @@ where old_specialized_cost, value_defined_cost_fn, update_tree_value_based_on_costs, - section_removal_bytes + section_removal_bytes, + grove_version ) ) } @@ -678,6 +699,7 @@ where value_defined_cost_fn, update_tree_value_based_on_costs, section_removal_bytes, + grove_version, ) .add_cost(cost) } @@ -697,6 +719,7 @@ where value_defined_cost_fn: Option<&V>, update_tree_value_based_on_costs: &mut U, section_removal_bytes: &mut R, + grove_version: &GroveVersion, ) -> CostResult<(Option, KeyUpdates), Error> where C: Fn(&Vec, &Vec) -> Result, @@ -705,7 +728,7 @@ where &Vec, &mut Vec, ) -> Result<(bool, Option), Error>, - V: Fn(&[u8]) -> Option, + V: Fn(&[u8], &GroveVersion) -> Option, R: FnMut(&Vec, u32, u32) -> Result<(StorageRemovedBytes, StorageRemovedBytes), Error>, { let mut cost = OperationCost::default(); @@ -734,6 +757,7 @@ where value_defined_cost_fn, update_tree_value_based_on_costs, section_removal_bytes, + grove_version, ) .map_ok(|(maybe_left, mut key_updates_left)| { key_updates.new_keys.append(&mut key_updates_left.new_keys); @@ -746,7 +770,8 @@ where maybe_left }) }, - value_defined_cost_fn + value_defined_cost_fn, + grove_version, ) ) } else { @@ -768,6 +793,7 @@ where value_defined_cost_fn, update_tree_value_based_on_costs, section_removal_bytes, + grove_version, ) .map_ok(|(maybe_right, mut key_updates_right)| { key_updates.new_keys.append(&mut key_updates_right.new_keys); @@ -780,14 +806,18 @@ where maybe_right }) }, - value_defined_cost_fn + value_defined_cost_fn, + grove_version ) ) } else { tree }; - let tree = cost_return_on_error!(&mut cost, tree.maybe_balance(value_defined_cost_fn)); + let tree = cost_return_on_error!( + &mut cost, + tree.maybe_balance(value_defined_cost_fn, grove_version) + ); let new_root_key = tree.tree().key(); @@ -808,11 +838,15 @@ where } /// Checks if the tree is unbalanced and if so, applies AVL tree rotation(s) - /// to rebalance the tree and its subtrees. Returns the root node of the + /// to re-balance the tree and its subtrees. Returns the root node of the /// balanced tree after applying the rotations. - fn maybe_balance(self, value_defined_cost_fn: Option<&V>) -> CostResult + fn maybe_balance( + self, + value_defined_cost_fn: Option<&V>, + grove_version: &GroveVersion, + ) -> CostResult where - V: Fn(&[u8]) -> Option, + V: Fn(&[u8], &GroveVersion) -> Option, { let mut cost = OperationCost::default(); @@ -830,9 +864,10 @@ where self.walk_expect( left, |child| child - .rotate(!left, value_defined_cost_fn) - .map_ok(Option::Some), - value_defined_cost_fn + .rotate(!left, value_defined_cost_fn, grove_version) + .map_ok(Some), + value_defined_cost_fn, + grove_version, ) ) } else { @@ -840,41 +875,54 @@ where }; let rotate = tree - .rotate(left, value_defined_cost_fn) + .rotate(left, value_defined_cost_fn, grove_version) .unwrap_add_cost(&mut cost); rotate.wrap_with_cost(cost) } /// Applies an AVL tree rotation, a constant-time operation which only needs - /// to swap pointers in order to rebalance a tree. - fn rotate(self, left: bool, value_defined_cost_fn: Option<&V>) -> CostResult + /// to swap pointers in order to re-balance a tree. + fn rotate( + self, + left: bool, + value_defined_cost_fn: Option<&V>, + grove_version: &GroveVersion, + ) -> CostResult where - V: Fn(&[u8]) -> Option, + V: Fn(&[u8], &GroveVersion) -> Option, { let mut cost = OperationCost::default(); - let (tree, child) = - cost_return_on_error!(&mut cost, self.detach_expect(left, value_defined_cost_fn)); - let (child, maybe_grandchild) = - cost_return_on_error!(&mut cost, child.detach(!left, value_defined_cost_fn)); + let (tree, child) = cost_return_on_error!( + &mut cost, + self.detach_expect(left, value_defined_cost_fn, grove_version) + ); + let (child, maybe_grandchild) = cost_return_on_error!( + &mut cost, + child.detach(!left, value_defined_cost_fn, grove_version) + ); // attach grandchild to self tree.attach(left, maybe_grandchild) - .maybe_balance(value_defined_cost_fn) + .maybe_balance(value_defined_cost_fn, grove_version) .flat_map_ok(|tree| { // attach self to child, return child child .attach(!left, Some(tree)) - .maybe_balance(value_defined_cost_fn) + .maybe_balance(value_defined_cost_fn, grove_version) }) .add_cost(cost) } - /// Removes the root node from the tree. Rearranges and rebalances + /// Removes the root node from the tree. Rearranges and re-balances /// descendants (if any) in order to maintain a valid tree. - pub fn remove(self, value_defined_cost_fn: Option<&V>) -> CostResult, Error> + pub fn remove( + self, + value_defined_cost_fn: Option<&V>, + grove_version: &GroveVersion, + ) -> CostResult, Error> where - V: Fn(&[u8]) -> Option, + V: Fn(&[u8], &GroveVersion) -> Option, { let mut cost = OperationCost::default(); @@ -885,19 +933,27 @@ where let maybe_tree = if has_left && has_right { // two children, promote edge of taller child - let (tree, tall_child) = - cost_return_on_error!(&mut cost, self.detach_expect(left, value_defined_cost_fn)); - let (_, short_child) = - cost_return_on_error!(&mut cost, tree.detach_expect(!left, value_defined_cost_fn)); + let (tree, tall_child) = cost_return_on_error!( + &mut cost, + self.detach_expect(left, value_defined_cost_fn, grove_version) + ); + let (_, short_child) = cost_return_on_error!( + &mut cost, + tree.detach_expect(!left, value_defined_cost_fn, grove_version) + ); let promoted = cost_return_on_error!( &mut cost, - tall_child.promote_edge(!left, short_child, value_defined_cost_fn) + tall_child.promote_edge(!left, short_child, value_defined_cost_fn, grove_version) ); Some(promoted) } else if has_left || has_right { // single child, promote it Some( - cost_return_on_error!(&mut cost, self.detach_expect(left, value_defined_cost_fn)).1, + cost_return_on_error!( + &mut cost, + self.detach_expect(left, value_defined_cost_fn, grove_version) + ) + .1, ) } else { // no child @@ -916,15 +972,16 @@ where left: bool, attach: Self, value_defined_cost_fn: Option<&V>, + grove_version: &GroveVersion, ) -> CostResult where - V: Fn(&[u8]) -> Option, + V: Fn(&[u8], &GroveVersion) -> Option, { - self.remove_edge(left, value_defined_cost_fn) + self.remove_edge(left, value_defined_cost_fn, grove_version) .flat_map_ok(|(edge, maybe_child)| { edge.attach(!left, maybe_child) .attach(left, Some(attach)) - .maybe_balance(value_defined_cost_fn) + .maybe_balance(value_defined_cost_fn, grove_version) }) } @@ -935,25 +992,30 @@ where self, left: bool, value_defined_cost_fn: Option<&V>, + grove_version: &GroveVersion, ) -> CostResult<(Self, Option), Error> where - V: Fn(&[u8]) -> Option, + V: Fn(&[u8], &GroveVersion) -> Option, { let mut cost = OperationCost::default(); if self.tree().link(left).is_some() { // this node is not the edge, recurse - let (tree, child) = - cost_return_on_error!(&mut cost, self.detach_expect(left, value_defined_cost_fn)); - let (edge, maybe_child) = - cost_return_on_error!(&mut cost, child.remove_edge(left, value_defined_cost_fn)); + let (tree, child) = cost_return_on_error!( + &mut cost, + self.detach_expect(left, value_defined_cost_fn, grove_version) + ); + let (edge, maybe_child) = cost_return_on_error!( + &mut cost, + child.remove_edge(left, value_defined_cost_fn, grove_version) + ); tree.attach(left, maybe_child) - .maybe_balance(value_defined_cost_fn) + .maybe_balance(value_defined_cost_fn, grove_version) .map_ok(|tree| (edge, Some(tree))) .add_cost(cost) } else { // this node is the edge, detach its child if present - self.detach(!left, value_defined_cost_fn) + self.detach(!left, value_defined_cost_fn, grove_version) } } } @@ -969,10 +1031,11 @@ mod test { #[test] fn simple_insert() { - let batch = [(b"foo2".to_vec(), Op::Put(b"bar2".to_vec(), BasicMerkNode))]; + let grove_version = GroveVersion::latest(); + let batch = [(b"foo2".to_vec(), Put(b"bar2".to_vec(), BasicMerkNode))]; let tree = TreeNode::new(b"foo".to_vec(), b"bar".to_vec(), None, BasicMerkNode).unwrap(); let (maybe_walker, key_updates) = Walker::new(tree, PanicSource {}) - .apply_sorted_without_costs(&batch) + .apply_sorted_without_costs(&batch, grove_version) .unwrap() .expect("apply errored"); let walker = maybe_walker.expect("should be Some"); @@ -985,10 +1048,11 @@ mod test { #[test] fn simple_update() { - let batch = [(b"foo".to_vec(), Op::Put(b"bar2".to_vec(), BasicMerkNode))]; + let grove_version = GroveVersion::latest(); + let batch = [(b"foo".to_vec(), Put(b"bar2".to_vec(), BasicMerkNode))]; let tree = TreeNode::new(b"foo".to_vec(), b"bar".to_vec(), None, BasicMerkNode).unwrap(); let (maybe_walker, key_updates) = Walker::new(tree, PanicSource {}) - .apply_sorted_without_costs(&batch) + .apply_sorted_without_costs(&batch, grove_version) .unwrap() .expect("apply errored"); let walker = maybe_walker.expect("should be Some"); @@ -1002,7 +1066,8 @@ mod test { #[test] fn simple_delete() { - let batch = [(b"foo2".to_vec(), Op::Delete)]; + let grove_version = GroveVersion::latest(); + let batch = [(b"foo2".to_vec(), Delete)]; let tree = TreeNode::from_fields( b"foo".to_vec(), b"bar".to_vec(), @@ -1019,7 +1084,7 @@ mod test { ) .unwrap(); let (maybe_walker, key_updates) = Walker::new(tree, PanicSource {}) - .apply_sorted_without_costs(&batch) + .apply_sorted_without_costs(&batch, grove_version) .unwrap() .expect("apply errored"); let walker = maybe_walker.expect("should be Some"); @@ -1037,20 +1102,22 @@ mod test { #[test] fn delete_non_existent() { - let batch = [(b"foo2".to_vec(), Op::Delete)]; + let grove_version = GroveVersion::latest(); + let batch = [(b"foo2".to_vec(), Delete)]; let tree = TreeNode::new(b"foo".to_vec(), b"bar".to_vec(), None, BasicMerkNode).unwrap(); Walker::new(tree, PanicSource {}) - .apply_sorted_without_costs(&batch) + .apply_sorted_without_costs(&batch, grove_version) .unwrap() .unwrap(); } #[test] fn delete_only_node() { - let batch = [(b"foo".to_vec(), Op::Delete)]; + let grove_version = GroveVersion::latest(); + let batch = [(b"foo".to_vec(), Delete)]; let tree = TreeNode::new(b"foo".to_vec(), b"bar".to_vec(), None, BasicMerkNode).unwrap(); let (maybe_walker, key_updates) = Walker::new(tree, PanicSource {}) - .apply_sorted_without_costs(&batch) + .apply_sorted_without_costs(&batch, grove_version) .unwrap() .expect("apply errored"); assert!(maybe_walker.is_none()); @@ -1064,10 +1131,11 @@ mod test { #[test] fn delete_deep() { - let tree = make_tree_seq(50); + let grove_version = GroveVersion::latest(); + let tree = make_tree_seq(50, grove_version); let batch = [del_entry(5)]; let (maybe_walker, key_updates) = Walker::new(tree, PanicSource {}) - .apply_sorted_without_costs(&batch) + .apply_sorted_without_costs(&batch, grove_version) .unwrap() .expect("apply errored"); maybe_walker.expect("should be Some"); @@ -1081,10 +1149,11 @@ mod test { #[test] fn delete_recursive() { - let tree = make_tree_seq(50); + let grove_version = GroveVersion::latest(); + let tree = make_tree_seq(50, grove_version); let batch = [del_entry(29), del_entry(34)]; let (maybe_walker, mut key_updates) = Walker::new(tree, PanicSource {}) - .apply_sorted_without_costs(&batch) + .apply_sorted_without_costs(&batch, grove_version) .unwrap() .expect("apply errored"); maybe_walker.expect("should be Some"); @@ -1102,10 +1171,11 @@ mod test { #[test] fn delete_recursive_2() { - let tree = make_tree_seq(10); + let grove_version = GroveVersion::latest(); + let tree = make_tree_seq(10, grove_version); let batch = [del_entry(7), del_entry(9)]; let (maybe_walker, key_updates) = Walker::new(tree, PanicSource {}) - .apply_sorted_without_costs(&batch) + .apply_sorted_without_costs(&batch, grove_version) .unwrap() .expect("apply errored"); maybe_walker.expect("should be Some"); @@ -1118,12 +1188,13 @@ mod test { #[test] fn apply_empty_none() { + let grove_version = GroveVersion::latest(); let (maybe_tree, key_updates) = Walker::::apply_to::, _, _, _, _>( None, &[], PanicSource {}, &|_, _| Ok(0), - None::<&fn(&[u8]) -> Option>, + None::<&fn(&[u8], &GroveVersion) -> Option>, &mut |_, _, _| Ok((false, None)), &mut |_flags, key_bytes_to_remove, value_bytes_to_remove| { Ok(( @@ -1131,6 +1202,7 @@ mod test { BasicStorageRemoval(value_bytes_to_remove), )) }, + grove_version, ) .unwrap() .expect("apply_to failed"); @@ -1141,13 +1213,14 @@ mod test { #[test] fn insert_empty_single() { - let batch = vec![(vec![0], Op::Put(vec![1], BasicMerkNode))]; + let grove_version = GroveVersion::latest(); + let batch = vec![(vec![0], Put(vec![1], BasicMerkNode))]; let (maybe_tree, key_updates) = Walker::::apply_to( None, &batch, PanicSource {}, &|_, _| Ok(0), - None::<&fn(&[u8]) -> Option>, + None::<&fn(&[u8], &GroveVersion) -> Option>, &mut |_, _, _| Ok((false, None)), &mut |_flags, key_bytes_to_remove, value_bytes_to_remove| { Ok(( @@ -1155,6 +1228,7 @@ mod test { BasicStorageRemoval(value_bytes_to_remove), )) }, + grove_version, ) .unwrap() .expect("apply_to failed"); @@ -1168,13 +1242,14 @@ mod test { #[test] fn insert_updated_single() { - let batch = vec![(vec![0], Op::Put(vec![1], BasicMerkNode))]; + let grove_version = GroveVersion::latest(); + let batch = vec![(vec![0], Put(vec![1], BasicMerkNode))]; let (maybe_tree, key_updates) = Walker::::apply_to( None, &batch, PanicSource {}, &|_, _| Ok(0), - None::<&fn(&[u8]) -> Option>, + None::<&fn(&[u8], &GroveVersion) -> Option>, &mut |_, _, _| Ok((false, None)), &mut |_flags, key_bytes_to_remove, value_bytes_to_remove| { Ok(( @@ -1182,6 +1257,7 @@ mod test { BasicStorageRemoval(value_bytes_to_remove), )) }, + grove_version, ) .unwrap() .expect("apply_to failed"); @@ -1190,15 +1266,15 @@ mod test { let maybe_walker = maybe_tree.map(|tree| Walker::::new(tree, PanicSource {})); let batch = vec![ - (vec![0], Op::Put(vec![2], BasicMerkNode)), - (vec![1], Op::Put(vec![2], BasicMerkNode)), + (vec![0], Put(vec![2], BasicMerkNode)), + (vec![1], Put(vec![2], BasicMerkNode)), ]; let (maybe_tree, key_updates) = Walker::::apply_to( maybe_walker, &batch, PanicSource {}, &|_, _| Ok(0), - None::<&fn(&[u8]) -> Option>, + None::<&fn(&[u8], &GroveVersion) -> Option>, &mut |_, _, _| Ok((false, None)), &mut |_flags, key_bytes_to_remove, value_bytes_to_remove| { Ok(( @@ -1206,6 +1282,7 @@ mod test { BasicStorageRemoval(value_bytes_to_remove), )) }, + grove_version, ) .unwrap() .expect("apply_to failed"); @@ -1218,17 +1295,18 @@ mod test { #[test] fn insert_updated_multiple() { + let grove_version = GroveVersion::latest(); let batch = vec![ - (vec![0], Op::Put(vec![1], BasicMerkNode)), - (vec![1], Op::Put(vec![2], BasicMerkNode)), - (vec![2], Op::Put(vec![3], BasicMerkNode)), + (vec![0], Put(vec![1], BasicMerkNode)), + (vec![1], Put(vec![2], BasicMerkNode)), + (vec![2], Put(vec![3], BasicMerkNode)), ]; let (maybe_tree, key_updates) = Walker::::apply_to( None, &batch, PanicSource {}, &|_, _| Ok(0), - None::<&fn(&[u8]) -> Option>, + None::<&fn(&[u8], &GroveVersion) -> Option>, &mut |_, _, _| Ok((false, None)), &mut |_flags, key_bytes_to_remove, value_bytes_to_remove| { Ok(( @@ -1236,6 +1314,7 @@ mod test { BasicStorageRemoval(value_bytes_to_remove), )) }, + grove_version, ) .unwrap() .expect("apply_to failed"); @@ -1244,16 +1323,16 @@ mod test { let maybe_walker = maybe_tree.map(|tree| Walker::::new(tree, PanicSource {})); let batch = vec![ - (vec![0], Op::Put(vec![5], BasicMerkNode)), - (vec![1], Op::Put(vec![8], BasicMerkNode)), - (vec![2], Op::Delete), + (vec![0], Put(vec![5], BasicMerkNode)), + (vec![1], Put(vec![8], BasicMerkNode)), + (vec![2], Delete), ]; let (maybe_tree, key_updates) = Walker::::apply_to( maybe_walker, &batch, PanicSource {}, &|_, _| Ok(0), - None::<&fn(&[u8]) -> Option>, + None::<&fn(&[u8], &GroveVersion) -> Option>, &mut |_, _, _| Ok((false, None)), &mut |_flags, key_bytes_to_remove, value_bytes_to_remove| { Ok(( @@ -1261,6 +1340,7 @@ mod test { BasicStorageRemoval(value_bytes_to_remove), )) }, + grove_version, ) .unwrap() .expect("apply_to failed"); @@ -1274,9 +1354,10 @@ mod test { #[test] fn insert_root_single() { + let grove_version = GroveVersion::latest(); let tree = TreeNode::new(vec![5], vec![123], None, BasicMerkNode).unwrap(); - let batch = vec![(vec![6], Op::Put(vec![123], BasicMerkNode))]; - let tree = apply_memonly(tree, &batch); + let batch = vec![(vec![6], Put(vec![123], BasicMerkNode))]; + let tree = apply_memonly(tree, &batch, grove_version); assert_eq!(tree.key(), &[5]); assert!(tree.child(true).is_none()); assert_eq!(tree.child(false).expect("expected child").key(), &[6]); @@ -1284,12 +1365,13 @@ mod test { #[test] fn insert_root_double() { + let grove_version = GroveVersion::latest(); let tree = TreeNode::new(vec![5], vec![123], None, BasicMerkNode).unwrap(); let batch = vec![ - (vec![4], Op::Put(vec![123], BasicMerkNode)), - (vec![6], Op::Put(vec![123], BasicMerkNode)), + (vec![4], Put(vec![123], BasicMerkNode)), + (vec![6], Put(vec![123], BasicMerkNode)), ]; - let tree = apply_memonly(tree, &batch); + let tree = apply_memonly(tree, &batch, grove_version); assert_eq!(tree.key(), &[5]); assert_eq!(tree.child(true).expect("expected child").key(), &[4]); assert_eq!(tree.child(false).expect("expected child").key(), &[6]); @@ -1297,13 +1379,14 @@ mod test { #[test] fn insert_rebalance() { + let grove_version = GroveVersion::latest(); let tree = TreeNode::new(vec![5], vec![123], None, BasicMerkNode).unwrap(); - let batch = vec![(vec![6], Op::Put(vec![123], BasicMerkNode))]; - let tree = apply_memonly(tree, &batch); + let batch = vec![(vec![6], Put(vec![123], BasicMerkNode))]; + let tree = apply_memonly(tree, &batch, grove_version); - let batch = vec![(vec![7], Op::Put(vec![123], BasicMerkNode))]; - let tree = apply_memonly(tree, &batch); + let batch = vec![(vec![7], Put(vec![123], BasicMerkNode))]; + let tree = apply_memonly(tree, &batch, grove_version); assert_eq!(tree.key(), &[6]); assert_eq!(tree.child(true).expect("expected child").key(), &[5]); @@ -1312,11 +1395,12 @@ mod test { #[test] fn insert_100_sequential() { + let grove_version = GroveVersion::latest(); let mut tree = TreeNode::new(vec![0], vec![123], None, BasicMerkNode).unwrap(); for i in 0..100 { - let batch = vec![(vec![i + 1], Op::Put(vec![123], BasicMerkNode))]; - tree = apply_memonly(tree, &batch); + let batch = vec![(vec![i + 1], Put(vec![123], BasicMerkNode))]; + tree = apply_memonly(tree, &batch, grove_version); } assert_eq!(tree.key(), &[63]); diff --git a/merk/src/tree/walk/fetch.rs b/merk/src/tree/walk/fetch.rs index e99df5bd..0ba657f2 100644 --- a/merk/src/tree/walk/fetch.rs +++ b/merk/src/tree/walk/fetch.rs @@ -2,6 +2,7 @@ #[cfg(feature = "full")] use grovedb_costs::CostResult; +use grovedb_version::version::GroveVersion; #[cfg(feature = "full")] use super::super::{Link, TreeNode}; @@ -20,6 +21,9 @@ pub trait Fetch { fn fetch( &self, link: &Link, - value_defined_cost_fn: Option<&impl Fn(&[u8]) -> Option>, + value_defined_cost_fn: Option< + &impl Fn(&[u8], &GroveVersion) -> Option, + >, + grove_version: &GroveVersion, ) -> CostResult; } diff --git a/merk/src/tree/walk/mod.rs b/merk/src/tree/walk/mod.rs index adf2a07d..a84a1d4c 100644 --- a/merk/src/tree/walk/mod.rs +++ b/merk/src/tree/walk/mod.rs @@ -13,6 +13,7 @@ use grovedb_costs::{ cost_return_on_error_no_add, storage_cost::{removal::StorageRemovedBytes, StorageCost}, }; +use grovedb_version::version::GroveVersion; #[cfg(feature = "full")] pub use ref_walker::RefWalker; @@ -53,9 +54,10 @@ where mut self, left: bool, value_defined_cost_fn: Option<&V>, + grove_version: &GroveVersion, ) -> CostResult<(Self, Option), Error> where - V: Fn(&[u8]) -> Option, + V: Fn(&[u8], &GroveVersion) -> Option, { let mut cost = OperationCost::default(); @@ -77,7 +79,8 @@ where } cost_return_on_error!( &mut cost, - self.source.fetch(&link.unwrap(), value_defined_cost_fn) + self.source + .fetch(&link.unwrap(), value_defined_cost_fn, grove_version) ) }; @@ -92,11 +95,12 @@ where self, left: bool, value_defined_cost_fn: Option<&V>, + grove_version: &GroveVersion, ) -> CostResult<(Self, Self), Error> where - V: Fn(&[u8]) -> Option, + V: Fn(&[u8], &GroveVersion) -> Option, { - self.detach(left, value_defined_cost_fn) + self.detach(left, value_defined_cost_fn, grove_version) .map_ok(|(walker, maybe_child)| { if let Some(child) = maybe_child { (walker, child) @@ -116,16 +120,19 @@ where left: bool, f: F, value_defined_cost_fn: Option<&V>, + grove_version: &GroveVersion, ) -> CostResult where F: FnOnce(Option) -> CostResult, Error>, T: Into, - V: Fn(&[u8]) -> Option, + V: Fn(&[u8], &GroveVersion) -> Option, { let mut cost = OperationCost::default(); - let (mut walker, maybe_child) = - cost_return_on_error!(&mut cost, self.detach(left, value_defined_cost_fn)); + let (mut walker, maybe_child) = cost_return_on_error!( + &mut cost, + self.detach(left, value_defined_cost_fn, grove_version) + ); let new_child = match f(maybe_child).unwrap_add_cost(&mut cost) { Ok(x) => x.map(|t| t.into()), Err(e) => return Err(e).wrap_with_cost(cost), @@ -141,16 +148,19 @@ where left: bool, f: F, value_defined_cost_fn: Option<&V>, + grove_version: &GroveVersion, ) -> CostResult where F: FnOnce(Self) -> CostResult, Error>, T: Into, - V: Fn(&[u8]) -> Option, + V: Fn(&[u8], &GroveVersion) -> Option, { let mut cost = OperationCost::default(); - let (mut walker, child) = - cost_return_on_error!(&mut cost, self.detach_expect(left, value_defined_cost_fn)); + let (mut walker, child) = cost_return_on_error!( + &mut cost, + self.detach_expect(left, value_defined_cost_fn, grove_version) + ); let new_child = match f(child).unwrap_add_cost(&mut cost) { Ok(x) => x.map(|t| t.into()), Err(e) => return Err(e).wrap_with_cost(cost), @@ -370,6 +380,7 @@ where #[cfg(test)] mod test { use grovedb_costs::CostsExt; + use grovedb_version::version::GroveVersion; use super::{super::NoopCommit, *}; use crate::tree::{TreeFeatureType::BasicMerkNode, TreeNode}; @@ -381,7 +392,10 @@ mod test { fn fetch( &self, link: &Link, - _value_defined_cost_fn: Option<&impl Fn(&[u8]) -> Option>, + _value_defined_cost_fn: Option< + &impl Fn(&[u8], &GroveVersion) -> Option, + >, + _grove_version: &GroveVersion, ) -> CostResult { TreeNode::new(link.key().to_vec(), b"foo".to_vec(), None, BasicMerkNode).map(Ok) } @@ -389,6 +403,7 @@ mod test { #[test] fn walk_modified() { + let grove_version = GroveVersion::latest(); let tree = TreeNode::new(b"test".to_vec(), b"abc".to_vec(), None, BasicMerkNode) .unwrap() .attach( @@ -406,7 +421,8 @@ mod test { assert_eq!(child.expect("should have child").tree().key(), b"foo"); Ok(None).wrap_with_cost(Default::default()) }, - None::<&fn(&[u8]) -> Option>, + None::<&fn(&[u8], &GroveVersion) -> Option>, + grove_version, ) .unwrap() .expect("walk failed"); @@ -415,6 +431,7 @@ mod test { #[test] fn walk_stored() { + let grove_version = GroveVersion::latest(); let mut tree = TreeNode::new(b"test".to_vec(), b"abc".to_vec(), None, BasicMerkNode) .unwrap() .attach( @@ -435,7 +452,8 @@ mod test { assert_eq!(child.expect("should have child").tree().key(), b"foo"); Ok(None).wrap_with_cost(Default::default()) }, - None::<&fn(&[u8]) -> Option>, + None::<&fn(&[u8], &GroveVersion) -> Option>, + grove_version, ) .unwrap() .expect("walk failed"); @@ -444,6 +462,7 @@ mod test { #[test] fn walk_pruned() { + let grove_version = GroveVersion::latest(); let tree = TreeNode::from_fields( b"test".to_vec(), b"abc".to_vec(), @@ -469,7 +488,8 @@ mod test { assert_eq!(child.tree().key(), b"foo"); Ok(None).wrap_with_cost(Default::default()) }, - None::<&fn(&[u8]) -> Option>, + None::<&fn(&[u8], &GroveVersion) -> Option>, + grove_version, ) .unwrap() .expect("walk failed"); @@ -478,6 +498,7 @@ mod test { #[test] fn walk_none() { + let grove_version = GroveVersion::latest(); let tree = TreeNode::new(b"test".to_vec(), b"abc".to_vec(), None, BasicMerkNode).unwrap(); let source = MockSource {}; @@ -490,7 +511,8 @@ mod test { assert!(child.is_none()); Ok(None).wrap_with_cost(Default::default()) }, - None::<&fn(&[u8]) -> Option>, + None::<&fn(&[u8], &GroveVersion) -> Option>, + grove_version, ) .unwrap() .expect("walk failed"); diff --git a/merk/src/tree/walk/ref_walker.rs b/merk/src/tree/walk/ref_walker.rs index 17f4e6c4..189bc7ee 100644 --- a/merk/src/tree/walk/ref_walker.rs +++ b/merk/src/tree/walk/ref_walker.rs @@ -2,6 +2,7 @@ #[cfg(feature = "full")] use grovedb_costs::{CostResult, CostsExt, OperationCost}; +use grovedb_version::version::GroveVersion; #[cfg(feature = "full")] use super::{ @@ -50,9 +51,10 @@ where &mut self, left: bool, value_defined_cost_fn: Option<&V>, + grove_version: &GroveVersion, ) -> CostResult>, Error> where - V: Fn(&[u8]) -> Option, + V: Fn(&[u8], &GroveVersion) -> Option, { let link = match self.tree.link(left) { None => return Ok(None).wrap_with_cost(Default::default()), @@ -64,7 +66,7 @@ where Link::Reference { .. } => { let load_res = self .tree - .load(left, &self.source, value_defined_cost_fn) + .load(left, &self.source, value_defined_cost_fn, grove_version) .unwrap_add_cost(&mut cost); if let Err(e) = load_res { return Err(e).wrap_with_cost(cost); diff --git a/node-grove/Cargo.toml b/node-grove/Cargo.toml index 1e18a6f3..7656ea7d 100644 --- a/node-grove/Cargo.toml +++ b/node-grove/Cargo.toml @@ -11,6 +11,7 @@ crate-type = ["cdylib"] [dependencies] grovedb = { path = "../grovedb", features = ["full", "estimated_costs"] } +grovedb-version = { path = "../grovedb-version" } [dependencies.neon] version = "0.10.1" diff --git a/node-grove/src/lib.rs b/node-grove/src/lib.rs index d3d6e0a6..e9e4ac0a 100644 --- a/node-grove/src/lib.rs +++ b/node-grove/src/lib.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. - //! GroveDB binding for Node.JS #![deny(missing_docs)] @@ -35,6 +7,7 @@ mod converter; use std::{option::Option::None, path::Path, sync::mpsc, thread}; use grovedb::{GroveDb, Transaction, TransactionArg}; +use grovedb_version::version::GroveVersion; use neon::prelude::*; type DbCallback = Box FnOnce(&'a GroveDb, TransactionArg, &Channel) + Send>; @@ -348,6 +321,7 @@ impl GroveDbWrapper { path.as_slice(), &key, using_transaction.then_some(transaction).flatten(), + GroveVersion::latest(), ) .unwrap(); // Todo: Costs @@ -397,6 +371,7 @@ impl GroveDbWrapper { &key, None, using_transaction.then_some(transaction).flatten(), + GroveVersion::latest(), ) .unwrap(); // Todo: Costs; @@ -446,6 +421,7 @@ impl GroveDbWrapper { element, None, using_transaction.then_some(transaction).flatten(), + GroveVersion::latest(), ) .unwrap(); // Todo: Costs; @@ -488,6 +464,7 @@ impl GroveDbWrapper { &key, element, using_transaction.then_some(transaction).flatten(), + GroveVersion::latest(), ) .unwrap(); // Todo: Costs; @@ -666,6 +643,7 @@ impl GroveDbWrapper { true, true, using_transaction.then_some(transaction).flatten(), + GroveVersion::latest(), ) .unwrap(); // Todo: Costs; @@ -760,7 +738,10 @@ impl GroveDbWrapper { db.send_to_db_thread(move |grove_db: &GroveDb, transaction, channel| { let result = grove_db - .root_hash(using_transaction.then_some(transaction).flatten()) + .root_hash( + using_transaction.then_some(transaction).flatten(), + GroveVersion::latest(), + ) .unwrap(); // Todo: Costs; channel.send(move |mut task_context| { diff --git a/tutorials/src/bin/delete.rs b/tutorials/src/bin/delete.rs index 5ff6beab..063243fd 100644 --- a/tutorials/src/bin/delete.rs +++ b/tutorials/src/bin/delete.rs @@ -20,6 +20,7 @@ fn main() { Element::Item(val1.to_vec(), None), None, None, + grove_version, ) .unwrap() .expect("successful key1 insert"); @@ -31,13 +32,14 @@ fn main() { Element::Item(val2.to_vec(), None), None, None, + grove_version, ) .unwrap() .expect("successful key2 insert"); // Check the key-values are there - let result1 = db.get(root_path, key1, None).unwrap(); - let result2 = db.get(root_path, key2, None).unwrap(); + let result1 = db.get(root_path, key1, None, grove_version).unwrap(); + let result2 = db.get(root_path, key2, None, grove_version).unwrap(); println!("Before deleting, we have key1: {:?}", result1); println!("Before deleting, we have key2: {:?}", result2); @@ -50,8 +52,8 @@ fn main() { .expect("successfully deleted key2"); // Check the key-values again - let result3 = db.get(root_path, key1, None).unwrap(); - let result4 = db.get(root_path, key2, None).unwrap(); + let result3 = db.get(root_path, key1, None, grove_version).unwrap(); + let result4 = db.get(root_path, key2, None, grove_version).unwrap(); println!("After deleting, we have key1: {:?}", result3); println!("After deleting, we have key2: {:?}", result4); } diff --git a/tutorials/src/bin/insert.rs b/tutorials/src/bin/insert.rs index 5b1a4cd1..3d9f9b2a 100644 --- a/tutorials/src/bin/insert.rs +++ b/tutorials/src/bin/insert.rs @@ -20,6 +20,7 @@ fn main() { Element::Item(val1.to_vec(), None), None, None, + grove_version, ) .unwrap() .expect("successful key1 insert"); @@ -31,6 +32,7 @@ fn main() { Element::Item(val2.to_vec(), None), None, None, + grove_version, ) .unwrap() .expect("successful key2 insert"); @@ -42,10 +44,10 @@ fn main() { // function to get them from the RocksDB backing store. // Get value 1 - let result1 = db.get(root_path, key1, None).unwrap(); + let result1 = db.get(root_path, key1, None, grove_version).unwrap(); // Get value 2 - let result2 = db.get(root_path, key2, None).unwrap(); + let result2 = db.get(root_path, key2, None, grove_version).unwrap(); // Print the values to terminal println!("{:?}", result1); diff --git a/tutorials/src/bin/proofs.rs b/tutorials/src/bin/proofs.rs index d56abbda..02596919 100644 --- a/tutorials/src/bin/proofs.rs +++ b/tutorials/src/bin/proofs.rs @@ -33,14 +33,14 @@ fn main() { .expect("expected successful get_path_query"); // Generate proof. - let proof = db.prove_query(&path_query, None).unwrap().unwrap(); + let proof = db.prove_query(&path_query, None, grove_version).unwrap().unwrap(); // Get hash from query proof and print to terminal along with GroveDB root hash. - let (hash, _result_set) = GroveDb::verify_query(&proof, &path_query).unwrap(); + let (hash, _result_set) = GroveDb::verify_query(&proof, &path_query, grove_version).unwrap(); // See if the query proof hash matches the GroveDB root hash println!("Does the hash generated from the query proof match the GroveDB root hash?"); - if hash == db.root_hash(None).unwrap().unwrap() { + if hash == db.root_hash(None, grove_version).unwrap().unwrap() { println!("Yes"); } else { println!("No"); @@ -52,13 +52,13 @@ fn populate(db: &GroveDb) { // Put an empty subtree into the root tree nodes at KEY1. // Call this SUBTREE1. - db.insert(root_path, KEY1, Element::empty_tree(), INSERT_OPTIONS, None) + db.insert(root_path, KEY1, Element::empty_tree(), INSERT_OPTIONS, None, grove_version) .unwrap() .expect("successful SUBTREE1 insert"); // Put an empty subtree into subtree1 at KEY2. // Call this SUBTREE2. - db.insert(&[KEY1], KEY2, Element::empty_tree(), INSERT_OPTIONS, None) + db.insert(&[KEY1], KEY2, Element::empty_tree(), INSERT_OPTIONS, None, grove_version) .unwrap() .expect("successful SUBTREE2 insert"); @@ -71,6 +71,7 @@ fn populate(db: &GroveDb) { Element::new_item(i_vec.clone()), INSERT_OPTIONS, None, + grove_version, ) .unwrap() .expect("successfully inserted values"); diff --git a/tutorials/src/bin/query-complex.rs b/tutorials/src/bin/query-complex.rs index 131faa92..b4fb78cf 100644 --- a/tutorials/src/bin/query-complex.rs +++ b/tutorials/src/bin/query-complex.rs @@ -78,13 +78,13 @@ fn populate(db: &GroveDb) { let root_path: &[&[u8]] = &[]; // Put an empty subtree into the root tree nodes at KEY1. // Call this SUBTREE1. - db.insert(root_path, KEY1, Element::empty_tree(), INSERT_OPTIONS, None) + db.insert(root_path, KEY1, Element::empty_tree(), INSERT_OPTIONS, None, grove_version) .unwrap() .expect("successful SUBTREE1 insert"); // Put an empty subtree into subtree1 at KEY2. // Call this SUBTREE2. - db.insert(&[KEY1], KEY2, Element::empty_tree(), INSERT_OPTIONS, None) + db.insert(&[KEY1], KEY2, Element::empty_tree(), INSERT_OPTIONS, None, grove_version) .unwrap() .expect("successful SUBTREE2 insert"); @@ -97,6 +97,7 @@ fn populate(db: &GroveDb) { Element::new_item(i_vec.clone()), INSERT_OPTIONS, None, + grove_version, ) .unwrap() .expect("successfully inserted values in SUBTREE2"); @@ -115,6 +116,7 @@ fn populate(db: &GroveDb) { Element::empty_tree(), INSERT_OPTIONS, None, + grove_version, ) .unwrap() .expect("successful SUBTREE3 insert"); @@ -128,6 +130,7 @@ fn populate(db: &GroveDb) { Element::new_item(i_vec.clone()), INSERT_OPTIONS, None, + grove_version, ) .unwrap() .expect("successfully inserted values in SUBTREE3"); @@ -141,6 +144,7 @@ fn populate(db: &GroveDb) { Element::empty_tree(), INSERT_OPTIONS, None, + grove_version, ) .unwrap() .expect("successful SUBTREE4 insert"); @@ -153,6 +157,7 @@ fn populate(db: &GroveDb) { Element::empty_tree(), INSERT_OPTIONS, None, + grove_version, ) .unwrap() .expect("successful SUBTREE5 insert"); @@ -166,6 +171,7 @@ fn populate(db: &GroveDb) { Element::new_item(i_vec.clone()), INSERT_OPTIONS, None, + grove_version, ) .unwrap() .expect("successfully inserted values in SUBTREE5"); diff --git a/tutorials/src/bin/query-simple.rs b/tutorials/src/bin/query-simple.rs index 6bc7a2fd..ab888873 100644 --- a/tutorials/src/bin/query-simple.rs +++ b/tutorials/src/bin/query-simple.rs @@ -48,13 +48,13 @@ fn populate(db: &GroveDb) { let root_path: &[&[u8]] = &[]; // Put an empty subtree into the root tree nodes at KEY1. // Call this SUBTREE1. - db.insert(root_path, KEY1, Element::empty_tree(), INSERT_OPTIONS, None) + db.insert(root_path, KEY1, Element::empty_tree(), INSERT_OPTIONS, None, grove_version) .unwrap() .expect("successful SUBTREE1 insert"); // Put an empty subtree into subtree1 at KEY2. // Call this SUBTREE2. - db.insert(&[KEY1], KEY2, Element::empty_tree(), INSERT_OPTIONS, None) + db.insert(&[KEY1], KEY2, Element::empty_tree(), INSERT_OPTIONS, None, grove_version) .unwrap() .expect("successful SUBTREE2 insert"); @@ -67,6 +67,7 @@ fn populate(db: &GroveDb) { Element::new_item(i_vec.clone()), INSERT_OPTIONS, None, + grove_version, ) .unwrap() .expect("successfully inserted values"); diff --git a/tutorials/src/bin/replication.rs b/tutorials/src/bin/replication.rs index 6b5f0626..5ed6ab5b 100644 --- a/tutorials/src/bin/replication.rs +++ b/tutorials/src/bin/replication.rs @@ -89,15 +89,15 @@ fn main() { let db_destination = create_empty_db(path_destination.clone()); println!("\n######### root_hashes:"); - let root_hash_source = db_source.root_hash(None).unwrap().unwrap(); + let root_hash_source = db_source.root_hash(None, grove_version).unwrap().unwrap(); println!("root_hash_source: {:?}", hex::encode(root_hash_source)); - let root_hash_checkpoint_0 = db_checkpoint_0.root_hash(None).unwrap().unwrap(); + let root_hash_checkpoint_0 = db_checkpoint_0.root_hash(None, grove_version).unwrap().unwrap(); println!("root_hash_checkpoint_0: {:?}", hex::encode(root_hash_checkpoint_0)); - let root_hash_destination = db_destination.root_hash(None).unwrap().unwrap(); + let root_hash_destination = db_destination.root_hash(None, grove_version).unwrap().unwrap(); println!("root_hash_destination: {:?}", hex::encode(root_hash_destination)); println!("\n######### source_subtree_metadata of db_source"); - let subtrees_metadata_source = db_source.get_subtrees_metadata(None).unwrap(); + let subtrees_metadata_source = db_source.get_subtrees_metadata(None, grove_version).unwrap(); println!("{:?}", subtrees_metadata_source); println!("\n######### db_checkpoint_0 -> db_destination state sync"); @@ -107,7 +107,7 @@ fn main() { db_destination.commit_transaction(tx).unwrap().expect("expected to commit transaction"); println!("\n######### verify db_destination"); - let incorrect_hashes = db_destination.verify_grovedb(None).unwrap(); + let incorrect_hashes = db_destination.verify_grovedb(None, grove_version).unwrap(); if incorrect_hashes.len() > 0 { println!("DB verification failed!"); } @@ -116,11 +116,11 @@ fn main() { } println!("\n######### root_hashes:"); - let root_hash_source = db_source.root_hash(None).unwrap().unwrap(); + let root_hash_source = db_source.root_hash(None, grove_version).unwrap().unwrap(); println!("root_hash_source: {:?}", hex::encode(root_hash_source)); - let root_hash_checkpoint_0 = db_checkpoint_0.root_hash(None).unwrap().unwrap(); + let root_hash_checkpoint_0 = db_checkpoint_0.root_hash(None, grove_version).unwrap().unwrap(); println!("root_hash_checkpoint_0: {:?}", hex::encode(root_hash_checkpoint_0)); - let root_hash_destination = db_destination.root_hash(None).unwrap().unwrap(); + let root_hash_destination = db_destination.root_hash(None, grove_version).unwrap().unwrap(); println!("root_hash_destination: {:?}", hex::encode(root_hash_destination)); let query_path = &[MAIN_ΚΕΥ, KEY_INT_0]; @@ -136,7 +136,7 @@ fn main() { fn insert_empty_tree_db(db: &GroveDb, path: &[&[u8]], key: &[u8]) { - db.insert(path, key, Element::empty_tree(), INSERT_OPTIONS, None) + db.insert(path, key, Element::empty_tree(), INSERT_OPTIONS, None, grove_version) .unwrap() .expect("successfully inserted tree"); } @@ -150,6 +150,7 @@ fn insert_range_values_db(db: &GroveDb, path: &[&[u8]], min_i: u32, max_i: u32, Element::new_item(i_vec.to_vec()), INSERT_OPTIONS, Some(&transaction), + grove_version, ) .unwrap() .expect("successfully inserted values"); @@ -172,6 +173,7 @@ fn insert_range_ref_double_values_db(db: &GroveDb, path: &[&[u8]], ref_key: &[u8 ])), INSERT_OPTIONS, Some(&transaction), + grove_version, ) .unwrap() .expect("successfully inserted values"); @@ -180,7 +182,7 @@ fn insert_range_ref_double_values_db(db: &GroveDb, path: &[&[u8]], ref_key: &[u8 fn insert_empty_sum_tree_db(db: &GroveDb, path: &[&[u8]], key: &[u8]) { - db.insert(path, key, Element::empty_sum_tree(), INSERT_OPTIONS, None) + db.insert(path, key, Element::empty_sum_tree(), INSERT_OPTIONS, None, grove_version) .unwrap() .expect("successfully inserted tree"); } @@ -197,6 +199,7 @@ fn insert_sum_element_db(db: &GroveDb, path: &[&[u8]], min_i: u32, max_i: u32, t Element::new_sum_item(value as SumValue), INSERT_OPTIONS, Some(&transaction), + grove_version, ) .unwrap() .expect("successfully inserted values"); @@ -229,11 +232,11 @@ fn query_db(db: &GroveDb, path: &[&[u8]], key: Vec) { println!(">> {:?}", e); } - let proof = db.prove_query(&path_query, None).unwrap().unwrap(); + let proof = db.prove_query(&path_query, None, grove_version).unwrap().unwrap(); // Get hash from query proof and print to terminal along with GroveDB root hash. - let (verify_hash, _) = GroveDb::verify_query(&proof, &path_query).unwrap(); + let (verify_hash, _) = GroveDb::verify_query(&proof, &path_query, grove_version).unwrap(); println!("verify_hash: {:?}", hex::encode(verify_hash)); - if verify_hash == db.root_hash(None).unwrap().unwrap() { + if verify_hash == db.root_hash(None, grove_version).unwrap().unwrap() { println!("Query verified"); } else { println!("Verification FAILED"); }; } @@ -244,8 +247,8 @@ fn sync_db_demo( state_sync_info: MultiStateSyncInfo, target_tx: &Transaction, ) -> Result<(), grovedb::Error> { - let app_hash = source_db.root_hash(None).value.unwrap(); - let mut state_sync_info = target_db.start_snapshot_syncing(state_sync_info, app_hash, target_tx, CURRENT_STATE_SYNC_VERSION)?; + let app_hash = source_db.root_hash(None, grove_version).value.unwrap(); + let mut state_sync_info = target_db.start_snapshot_syncing(state_sync_info, app_hash, target_tx, CURRENT_STATE_SYNC_VERSION, grove_version)?; let mut chunk_queue : VecDeque> = VecDeque::new(); @@ -253,8 +256,8 @@ fn sync_db_demo( chunk_queue.push_back(app_hash.to_vec()); while let Some(chunk_id) = chunk_queue.pop_front() { - let ops = source_db.fetch_chunk(chunk_id.as_slice(), None, CURRENT_STATE_SYNC_VERSION)?; - let (more_chunks, new_state_sync_info) = target_db.apply_chunk(state_sync_info, chunk_id.as_slice(), ops, target_tx, CURRENT_STATE_SYNC_VERSION)?; + let ops = source_db.fetch_chunk(chunk_id.as_slice(), None, CURRENT_STATE_SYNC_VERSION, grove_version)?; + let (more_chunks, new_state_sync_info) = target_db.apply_chunk(state_sync_info, chunk_id.as_slice(), ops, target_tx, CURRENT_STATE_SYNC_VERSION, grove_version)?; state_sync_info = new_state_sync_info; chunk_queue.extend(more_chunks); }