diff --git a/Cargo.lock b/Cargo.lock index 83c098169ca..2b169644ccf 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -576,7 +576,7 @@ dependencies = [ "bitflags 2.13.0", "cexpr", "clang-sys", - "itertools 0.13.0", + "itertools 0.10.5", "proc-macro2", "quote", "regex", @@ -1229,7 +1229,7 @@ version = "3.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "faf9468729b8cbcea668e36183cb69d317348c2e08e994829fb56ebfdfbaac34" dependencies = [ - "windows-sys 0.59.0", + "windows-sys 0.61.2", ] [[package]] @@ -2195,6 +2195,7 @@ dependencies = [ "grovedb-costs", "grovedb-epoch-based-storage-flags", "grovedb-path", + "grovedb-query", "grovedb-storage", "grovedb-version", "hex", @@ -2494,7 +2495,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb" dependencies = [ "libc", - "windows-sys 0.59.0", + "windows-sys 0.61.2", ] [[package]] @@ -2974,7 +2975,7 @@ dependencies = [ [[package]] name = "grovedb" version = "5.0.1" -source = "git+https://github.com/dashpay/grovedb?rev=753a11f14c9a4bc72bf2d5302751dd43d174621e#753a11f14c9a4bc72bf2d5302751dd43d174621e" +source = "git+https://github.com/dashpay/grovedb?rev=6c882c3ee7d2c331f1feda2eb4223add9a6f0e45#6c882c3ee7d2c331f1feda2eb4223add9a6f0e45" dependencies = [ "axum 0.8.9", "bincode", @@ -3013,7 +3014,7 @@ dependencies = [ [[package]] name = "grovedb-bulk-append-tree" version = "5.0.1" -source = "git+https://github.com/dashpay/grovedb?rev=753a11f14c9a4bc72bf2d5302751dd43d174621e#753a11f14c9a4bc72bf2d5302751dd43d174621e" +source = "git+https://github.com/dashpay/grovedb?rev=6c882c3ee7d2c331f1feda2eb4223add9a6f0e45#6c882c3ee7d2c331f1feda2eb4223add9a6f0e45" dependencies = [ "bincode", "blake3", @@ -3031,7 +3032,7 @@ dependencies = [ [[package]] name = "grovedb-commitment-tree" version = "5.0.1" -source = "git+https://github.com/dashpay/grovedb?rev=753a11f14c9a4bc72bf2d5302751dd43d174621e#753a11f14c9a4bc72bf2d5302751dd43d174621e" +source = "git+https://github.com/dashpay/grovedb?rev=6c882c3ee7d2c331f1feda2eb4223add9a6f0e45#6c882c3ee7d2c331f1feda2eb4223add9a6f0e45" dependencies = [ "blake3", "grovedb-bulk-append-tree", @@ -3048,7 +3049,7 @@ dependencies = [ [[package]] name = "grovedb-costs" version = "5.0.1" -source = "git+https://github.com/dashpay/grovedb?rev=753a11f14c9a4bc72bf2d5302751dd43d174621e#753a11f14c9a4bc72bf2d5302751dd43d174621e" +source = "git+https://github.com/dashpay/grovedb?rev=6c882c3ee7d2c331f1feda2eb4223add9a6f0e45#6c882c3ee7d2c331f1feda2eb4223add9a6f0e45" dependencies = [ "integer-encoding", "intmap", @@ -3058,7 +3059,7 @@ dependencies = [ [[package]] name = "grovedb-dense-fixed-sized-merkle-tree" version = "5.0.1" -source = "git+https://github.com/dashpay/grovedb?rev=753a11f14c9a4bc72bf2d5302751dd43d174621e#753a11f14c9a4bc72bf2d5302751dd43d174621e" +source = "git+https://github.com/dashpay/grovedb?rev=6c882c3ee7d2c331f1feda2eb4223add9a6f0e45#6c882c3ee7d2c331f1feda2eb4223add9a6f0e45" dependencies = [ "bincode", "blake3", @@ -3072,7 +3073,7 @@ dependencies = [ [[package]] name = "grovedb-element" version = "5.0.1" -source = "git+https://github.com/dashpay/grovedb?rev=753a11f14c9a4bc72bf2d5302751dd43d174621e#753a11f14c9a4bc72bf2d5302751dd43d174621e" +source = "git+https://github.com/dashpay/grovedb?rev=6c882c3ee7d2c331f1feda2eb4223add9a6f0e45#6c882c3ee7d2c331f1feda2eb4223add9a6f0e45" dependencies = [ "bincode", "bincode_derive", @@ -3088,7 +3089,7 @@ dependencies = [ [[package]] name = "grovedb-epoch-based-storage-flags" version = "5.0.1" -source = "git+https://github.com/dashpay/grovedb?rev=753a11f14c9a4bc72bf2d5302751dd43d174621e#753a11f14c9a4bc72bf2d5302751dd43d174621e" +source = "git+https://github.com/dashpay/grovedb?rev=6c882c3ee7d2c331f1feda2eb4223add9a6f0e45#6c882c3ee7d2c331f1feda2eb4223add9a6f0e45" dependencies = [ "grovedb-costs", "hex", @@ -3100,7 +3101,7 @@ dependencies = [ [[package]] name = "grovedb-merk" version = "5.0.1" -source = "git+https://github.com/dashpay/grovedb?rev=753a11f14c9a4bc72bf2d5302751dd43d174621e#753a11f14c9a4bc72bf2d5302751dd43d174621e" +source = "git+https://github.com/dashpay/grovedb?rev=6c882c3ee7d2c331f1feda2eb4223add9a6f0e45#6c882c3ee7d2c331f1feda2eb4223add9a6f0e45" dependencies = [ "bincode", "bincode_derive", @@ -3126,7 +3127,7 @@ dependencies = [ [[package]] name = "grovedb-merkle-mountain-range" version = "5.0.1" -source = "git+https://github.com/dashpay/grovedb?rev=753a11f14c9a4bc72bf2d5302751dd43d174621e#753a11f14c9a4bc72bf2d5302751dd43d174621e" +source = "git+https://github.com/dashpay/grovedb?rev=6c882c3ee7d2c331f1feda2eb4223add9a6f0e45#6c882c3ee7d2c331f1feda2eb4223add9a6f0e45" dependencies = [ "bincode", "blake3", @@ -3139,7 +3140,7 @@ dependencies = [ [[package]] name = "grovedb-path" version = "5.0.1" -source = "git+https://github.com/dashpay/grovedb?rev=753a11f14c9a4bc72bf2d5302751dd43d174621e#753a11f14c9a4bc72bf2d5302751dd43d174621e" +source = "git+https://github.com/dashpay/grovedb?rev=6c882c3ee7d2c331f1feda2eb4223add9a6f0e45#6c882c3ee7d2c331f1feda2eb4223add9a6f0e45" dependencies = [ "hex", ] @@ -3147,7 +3148,7 @@ dependencies = [ [[package]] name = "grovedb-private-document-store" version = "5.0.1" -source = "git+https://github.com/dashpay/grovedb?rev=753a11f14c9a4bc72bf2d5302751dd43d174621e#753a11f14c9a4bc72bf2d5302751dd43d174621e" +source = "git+https://github.com/dashpay/grovedb?rev=6c882c3ee7d2c331f1feda2eb4223add9a6f0e45#6c882c3ee7d2c331f1feda2eb4223add9a6f0e45" dependencies = [ "blake3", "grovedb-bulk-append-tree", @@ -3160,7 +3161,7 @@ dependencies = [ [[package]] name = "grovedb-query" version = "5.0.1" -source = "git+https://github.com/dashpay/grovedb?rev=753a11f14c9a4bc72bf2d5302751dd43d174621e#753a11f14c9a4bc72bf2d5302751dd43d174621e" +source = "git+https://github.com/dashpay/grovedb?rev=6c882c3ee7d2c331f1feda2eb4223add9a6f0e45#6c882c3ee7d2c331f1feda2eb4223add9a6f0e45" dependencies = [ "bincode", "byteorder", @@ -3176,7 +3177,7 @@ dependencies = [ [[package]] name = "grovedb-storage" version = "5.0.1" -source = "git+https://github.com/dashpay/grovedb?rev=753a11f14c9a4bc72bf2d5302751dd43d174621e#753a11f14c9a4bc72bf2d5302751dd43d174621e" +source = "git+https://github.com/dashpay/grovedb?rev=6c882c3ee7d2c331f1feda2eb4223add9a6f0e45#6c882c3ee7d2c331f1feda2eb4223add9a6f0e45" dependencies = [ "blake3", "grovedb-costs", @@ -3195,7 +3196,7 @@ dependencies = [ [[package]] name = "grovedb-version" version = "5.0.1" -source = "git+https://github.com/dashpay/grovedb?rev=753a11f14c9a4bc72bf2d5302751dd43d174621e#753a11f14c9a4bc72bf2d5302751dd43d174621e" +source = "git+https://github.com/dashpay/grovedb?rev=6c882c3ee7d2c331f1feda2eb4223add9a6f0e45#6c882c3ee7d2c331f1feda2eb4223add9a6f0e45" dependencies = [ "thiserror 2.0.18", "versioned-feature-core 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -3204,7 +3205,7 @@ dependencies = [ [[package]] name = "grovedb-visualize" version = "5.0.1" -source = "git+https://github.com/dashpay/grovedb?rev=753a11f14c9a4bc72bf2d5302751dd43d174621e#753a11f14c9a4bc72bf2d5302751dd43d174621e" +source = "git+https://github.com/dashpay/grovedb?rev=6c882c3ee7d2c331f1feda2eb4223add9a6f0e45#6c882c3ee7d2c331f1feda2eb4223add9a6f0e45" dependencies = [ "hex", "itertools 0.14.0", @@ -3213,7 +3214,7 @@ dependencies = [ [[package]] name = "grovedbg-types" version = "5.0.1" -source = "git+https://github.com/dashpay/grovedb?rev=753a11f14c9a4bc72bf2d5302751dd43d174621e#753a11f14c9a4bc72bf2d5302751dd43d174621e" +source = "git+https://github.com/dashpay/grovedb?rev=6c882c3ee7d2c331f1feda2eb4223add9a6f0e45#6c882c3ee7d2c331f1feda2eb4223add9a6f0e45" dependencies = [ "serde", "serde_with 3.21.0", @@ -3629,7 +3630,7 @@ dependencies = [ "libc", "percent-encoding", "pin-project-lite", - "socket2 0.5.10", + "socket2 0.6.4", "system-configuration", "tokio", "tower-service", @@ -3880,7 +3881,7 @@ checksum = "3640c1c38b8e4e43584d8df18be5fc6b0aa314ce6ebf51b53313d4306cca8e46" dependencies = [ "hermit-abi", "libc", - "windows-sys 0.59.0", + "windows-sys 0.61.2", ] [[package]] @@ -4692,7 +4693,7 @@ version = "0.50.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7957b9740744892f114936ab4a57b3f487491bbeafaf8083688b16841a4240e5" dependencies = [ - "windows-sys 0.59.0", + "windows-sys 0.61.2", ] [[package]] @@ -5582,7 +5583,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "03da047801ff44bb6a4d407d4860c05fd70bb81714e6b2f3812603d5b145b042" dependencies = [ "heck 0.4.1", - "itertools 0.13.0", + "itertools 0.10.5", "log", "multimap", "petgraph", @@ -5603,7 +5604,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8a56d757972c98b346a9b766e3f02746cde6dd1cd1d1d563472929fdd74bec4d" dependencies = [ "anyhow", - "itertools 0.13.0", + "itertools 0.10.5", "proc-macro2", "quote", "syn 2.0.117", @@ -5616,7 +5617,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b570b25f7617e43d59005d0990ccb79e950a423952cea19671b7a876da390adf" dependencies = [ "anyhow", - "itertools 0.13.0", + "itertools 0.10.5", "proc-macro2", "quote", "syn 2.0.117", @@ -5752,7 +5753,7 @@ dependencies = [ "quinn-udp", "rustc-hash 2.1.2", "rustls", - "socket2 0.5.10", + "socket2 0.6.4", "thiserror 2.0.18", "tokio", "tracing", @@ -5790,7 +5791,7 @@ dependencies = [ "cfg_aliases", "libc", "once_cell", - "socket2 0.5.10", + "socket2 0.6.4", "tracing", "windows-sys 0.59.0", ] @@ -6613,7 +6614,7 @@ dependencies = [ "errno", "libc", "linux-raw-sys 0.12.1", - "windows-sys 0.59.0", + "windows-sys 0.61.2", ] [[package]] @@ -6672,7 +6673,7 @@ dependencies = [ "security-framework", "security-framework-sys", "webpki-root-certs", - "windows-sys 0.59.0", + "windows-sys 0.61.2", ] [[package]] @@ -7532,7 +7533,7 @@ dependencies = [ "getrandom 0.4.2", "once_cell", "rustix 1.1.4", - "windows-sys 0.59.0", + "windows-sys 0.61.2", ] [[package]] @@ -8981,7 +8982,7 @@ version = "0.1.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c2a7b1c03c876122aa43f3020e6c3c3ee5c05081c9a00739faf7503aeba10d22" dependencies = [ - "windows-sys 0.59.0", + "windows-sys 0.61.2", ] [[package]] diff --git a/packages/dash-platform-queries/src/documents/ranked_proof_helpers.rs b/packages/dash-platform-queries/src/documents/ranked_proof_helpers.rs index 785b2f018e8..7ab5980bb60 100644 --- a/packages/dash-platform-queries/src/documents/ranked_proof_helpers.rs +++ b/packages/dash-platform-queries/src/documents/ranked_proof_helpers.rs @@ -13,9 +13,9 @@ //! two copies of a grammar agreeing. //! //! Unlike the count helper there is no per-shape dispatch: the ranked -//! surface has exactly one proof primitive -//! (`prove_indexed_axis_top_k_paginated`), and all of a request's -//! variation is carried *inside* the query struct. +//! surface has exactly one proof primitive (grovedb's unified +//! `prove_query` over `PathQuery::new_axis_top_k`), and all of a +//! request's variation is carried *inside* the query struct. //! //! [`DocumentRankedEntries`]: drive_proof_verifier::DocumentRankedEntries diff --git a/packages/rs-dpp/Cargo.toml b/packages/rs-dpp/Cargo.toml index 0759b188069..e72bbd77413 100644 --- a/packages/rs-dpp/Cargo.toml +++ b/packages/rs-dpp/Cargo.toml @@ -71,7 +71,7 @@ strum = { version = "0.26", features = ["derive"] } json-schema-compatibility-validator = { path = '../rs-json-schema-compatibility-validator', optional = true } once_cell = "1.19.0" tracing = { version = "0.1.41" } -grovedb-commitment-tree = { git = "https://github.com/dashpay/grovedb", rev = "753a11f14c9a4bc72bf2d5302751dd43d174621e", optional = true } +grovedb-commitment-tree = { git = "https://github.com/dashpay/grovedb", rev = "6c882c3ee7d2c331f1feda2eb4223add9a6f0e45", optional = true } [dev-dependencies] tokio = { version = "1.40", features = ["full"] } diff --git a/packages/rs-drive-abci/Cargo.toml b/packages/rs-drive-abci/Cargo.toml index 6bba018371c..f3e3fccbc69 100644 --- a/packages/rs-drive-abci/Cargo.toml +++ b/packages/rs-drive-abci/Cargo.toml @@ -82,7 +82,7 @@ derive_more = { version = "1.0", features = ["from", "deref", "deref_mut"] } async-trait = "0.1.77" console-subscriber = { version = "0.4", optional = true } bls-signatures = { git = "https://github.com/dashpay/bls-signatures", rev = "0842b17583888e8f46c252a4ee84cdfd58e0546f", optional = true } -grovedb-commitment-tree = { git = "https://github.com/dashpay/grovedb", rev = "753a11f14c9a4bc72bf2d5302751dd43d174621e" } +grovedb-commitment-tree = { git = "https://github.com/dashpay/grovedb", rev = "6c882c3ee7d2c331f1feda2eb4223add9a6f0e45" } nonempty = "0.11" # Shielded-pool snapshot needs raw RocksDB SstFileWriter + ingest_external_file_cf # bindings, and blake3 for the snapshot-file checksum. @@ -108,7 +108,7 @@ dpp = { path = "../rs-dpp", default-features = false, features = [ drive = { path = "../rs-drive", features = ["fixtures-and-mocks"] } drive-proof-verifier = { path = "../rs-drive-proof-verifier" } strategy-tests = { path = "../strategy-tests" } -grovedb-commitment-tree = { git = "https://github.com/dashpay/grovedb", rev = "753a11f14c9a4bc72bf2d5302751dd43d174621e", features = ["client"] } +grovedb-commitment-tree = { git = "https://github.com/dashpay/grovedb", rev = "6c882c3ee7d2c331f1feda2eb4223add9a6f0e45", features = ["client"] } assert_matches = "1.5.0" drive-abci = { path = ".", features = ["testing-config", "mocks", "shielded_test_data"] } bls-signatures = { git = "https://github.com/dashpay/bls-signatures", rev = "0842b17583888e8f46c252a4ee84cdfd58e0546f" } @@ -122,8 +122,8 @@ integer-encoding = { version = "4.0.0" } # For dump_only_default_and_aux_cfs_under_shielded_subtree_prefix — same # subtree-prefix algorithm grovedb uses internally. -grovedb-path = { git = "https://github.com/dashpay/grovedb", rev = "753a11f14c9a4bc72bf2d5302751dd43d174621e" } -grovedb-storage = { git = "https://github.com/dashpay/grovedb", rev = "753a11f14c9a4bc72bf2d5302751dd43d174621e" } +grovedb-path = { git = "https://github.com/dashpay/grovedb", rev = "6c882c3ee7d2c331f1feda2eb4223add9a6f0e45" } +grovedb-storage = { git = "https://github.com/dashpay/grovedb", rev = "6c882c3ee7d2c331f1feda2eb4223add9a6f0e45" } [features] default = ["bls-signatures"] diff --git a/packages/rs-drive-abci/src/abci/handler/prepare_proposal.rs b/packages/rs-drive-abci/src/abci/handler/prepare_proposal.rs index 10a4bd95631..e7191125946 100644 --- a/packages/rs-drive-abci/src/abci/handler/prepare_proposal.rs +++ b/packages/rs-drive-abci/src/abci/handler/prepare_proposal.rs @@ -13,7 +13,6 @@ use crate::rpc::core::CoreRPCLike; use dpp::dashcore::hashes::Hash; use dpp::dashcore::Network; use dpp::version::TryIntoPlatformVersioned; -use drive::grovedb_storage::Error::RocksDBError; use tenderdash_abci::proto::abci as proto; use tenderdash_abci::proto::abci::tx_record::TxAction; use tenderdash_abci::proto::abci::{ExecTxResult, TxRecord}; @@ -142,7 +141,7 @@ where ); if let Some(tx) = transaction_guard.as_ref() { tx.rollback_to_savepoint() - .map_err(|e| drive::grovedb::error::Error::StorageError(RocksDBError(e)))?; + .map_err(|e| drive::grovedb::error::Error::StorageError(e))?; tx.set_savepoint(); } transaction_guard diff --git a/packages/rs-drive-abci/src/abci/handler/process_proposal.rs b/packages/rs-drive-abci/src/abci/handler/process_proposal.rs index a64aba5013b..ce898a7dc77 100644 --- a/packages/rs-drive-abci/src/abci/handler/process_proposal.rs +++ b/packages/rs-drive-abci/src/abci/handler/process_proposal.rs @@ -14,7 +14,6 @@ use crate::platform_types::state_transitions_processing_result::StateTransitionE use crate::rpc::core::CoreRPCLike; use dpp::dashcore::Network; use dpp::version::TryIntoPlatformVersioned; -use drive::grovedb_storage::Error::RocksDBError; use tenderdash_abci::proto::abci as proto; use tenderdash_abci::proto::abci::tx_record::TxAction; @@ -173,7 +172,7 @@ where ); if let Some(tx) = transaction_guard.as_ref() { tx.rollback_to_savepoint() - .map_err(|e| drive::grovedb::error::Error::StorageError(RocksDBError(e)))?; + .map_err(|e| drive::grovedb::error::Error::StorageError(e))?; tx.set_savepoint(); } transaction_guard diff --git a/packages/rs-drive-abci/src/execution/platform_events/state_transition_processing/process_raw_state_transitions/v0/mod.rs b/packages/rs-drive-abci/src/execution/platform_events/state_transition_processing/process_raw_state_transitions/v0/mod.rs index 4e19577b925..2a17f38dba9 100644 --- a/packages/rs-drive-abci/src/execution/platform_events/state_transition_processing/process_raw_state_transitions/v0/mod.rs +++ b/packages/rs-drive-abci/src/execution/platform_events/state_transition_processing/process_raw_state_transitions/v0/mod.rs @@ -17,7 +17,6 @@ use crate::platform_types::state_transitions_processing_result::{ use dpp::util::hash::hash_single; use dpp::version::PlatformVersion; use drive::grovedb::Transaction; -use drive::grovedb_storage::Error::RocksDBError; use std::time::Instant; use super::super::StateTransitionAwareError; @@ -224,7 +223,7 @@ where // failure means the proposal can no longer match the // block — fail it rather than continue on leaked state. transaction.rollback_to_savepoint().map_err(|e| { - drive::grovedb::error::Error::StorageError(RocksDBError(e)) + drive::grovedb::error::Error::StorageError(e) })?; } StateTransitionExecutionResult::SuccessfulExecution { .. } diff --git a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/tests/document/ranked_group_drain.rs b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/tests/document/ranked_group_drain.rs index 10ada3042f7..8e97e3826b1 100644 --- a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/tests/document/ranked_group_drain.rs +++ b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/tests/document/ranked_group_drain.rs @@ -39,7 +39,10 @@ use dpp::state_transition::batch_transition::document_delete_transition::Documen use dpp::state_transition::batch_transition::BatchTransitionV1; use dpp::state_transition::StateTransition; use drive::drive::RootTree; -use drive::grovedb::Element; +use drive::grovedb::element::IndexAxis; +use drive::grovedb::operations::proof::indexed_axis::AxisEntries; +use drive::grovedb::query_result_type::QueryResultType; +use drive::grovedb::{Element, PathQuery, PathQueryRun}; /// The group that gets emptied. const G: &str = "beta"; @@ -75,19 +78,29 @@ fn ranked_count_groups( path: &[Vec], platform_version: &PlatformVersion, ) -> Vec<(u64, String)> { - let path_refs: Vec<&[u8]> = path.iter().map(|v| v.as_slice()).collect(); - platform + let path_query = PathQuery::new_axis_top_k(path.to_vec(), IndexAxis::Count, 100, 0, true); + let run = platform .drive .grove - .indexed_count_top_k( - path_refs.as_slice(), - 100, + .run_path_query( + &path_query, + true, + true, true, + QueryResultType::QueryPathKeyElementTrioResultType, None, &platform_version.drive.grove_version, ) .unwrap() - .expect("the ranked count read must succeed") + .expect("the ranked count read must succeed"); + let PathQueryRun::AxisEntries { + entries: AxisEntries::Count(entries), + .. + } = run + else { + panic!("expected count axis entries"); + }; + entries .into_iter() .map(|entry| entry.key_pair()) .map(|(count, key)| { diff --git a/packages/rs-drive-abci/src/query/document_query/v1/dispatch/mod.rs b/packages/rs-drive-abci/src/query/document_query/v1/dispatch/mod.rs index 4c2d0315f48..df6b78461cf 100644 --- a/packages/rs-drive-abci/src/query/document_query/v1/dispatch/mod.rs +++ b/packages/rs-drive-abci/src/query/document_query/v1/dispatch/mod.rs @@ -58,10 +58,11 @@ fn into_v1_ranked_entry(e: DriveRankedEntry) -> RankedEntry { /// proved**. /// /// **This is now a backstop rather than a live path.** The ranked -/// prover moved to `prove_indexed_axis_top_k_paginated`, which emits a -/// guaranteed-empty range against an empty axis secondary instead of -/// refusing, so proving a ranking over a contract with no documents -/// succeeds and the proved and unproven paths agree (pinned by +/// prover moved to the paginated axis traversal (today through +/// grovedb's unified `prove_query`), which emits a guaranteed-empty +/// range against an empty axis secondary instead of refusing, so +/// proving a ranking over a contract with no documents succeeds and +/// the proved and unproven paths agree (pinned by /// `ranked_tests::proving_an_empty_ranking_succeeds`). The mapping is /// kept because the failure it recognizes is a *class* — a merk-level /// "cannot prove an empty tree" surfacing from somewhere in the diff --git a/packages/rs-drive/Cargo.toml b/packages/rs-drive/Cargo.toml index 54012ec1f1f..1f505ea1aa6 100644 --- a/packages/rs-drive/Cargo.toml +++ b/packages/rs-drive/Cargo.toml @@ -52,12 +52,13 @@ enum-map = { version = "2.0.3", optional = true } intmap = { version = "3.0.1", features = ["serde"], optional = true } chrono = { version = "0.4.35", optional = true } itertools = { version = "0.13", optional = true } -grovedb = { git = "https://github.com/dashpay/grovedb", rev = "753a11f14c9a4bc72bf2d5302751dd43d174621e", optional = true, default-features = false } -grovedb-costs = { git = "https://github.com/dashpay/grovedb", rev = "753a11f14c9a4bc72bf2d5302751dd43d174621e", optional = true } -grovedb-path = { git = "https://github.com/dashpay/grovedb", rev = "753a11f14c9a4bc72bf2d5302751dd43d174621e" } -grovedb-storage = { git = "https://github.com/dashpay/grovedb", rev = "753a11f14c9a4bc72bf2d5302751dd43d174621e", optional = true } -grovedb-version = { git = "https://github.com/dashpay/grovedb", rev = "753a11f14c9a4bc72bf2d5302751dd43d174621e" } -grovedb-epoch-based-storage-flags = { git = "https://github.com/dashpay/grovedb", rev = "753a11f14c9a4bc72bf2d5302751dd43d174621e" } +grovedb = { git = "https://github.com/dashpay/grovedb", rev = "6c882c3ee7d2c331f1feda2eb4223add9a6f0e45", optional = true, default-features = false } +grovedb-costs = { git = "https://github.com/dashpay/grovedb", rev = "6c882c3ee7d2c331f1feda2eb4223add9a6f0e45", optional = true } +grovedb-path = { git = "https://github.com/dashpay/grovedb", rev = "6c882c3ee7d2c331f1feda2eb4223add9a6f0e45" } +grovedb-query = { git = "https://github.com/dashpay/grovedb", rev = "6c882c3ee7d2c331f1feda2eb4223add9a6f0e45" } +grovedb-storage = { git = "https://github.com/dashpay/grovedb", rev = "6c882c3ee7d2c331f1feda2eb4223add9a6f0e45", optional = true } +grovedb-version = { git = "https://github.com/dashpay/grovedb", rev = "6c882c3ee7d2c331f1feda2eb4223add9a6f0e45" } +grovedb-epoch-based-storage-flags = { git = "https://github.com/dashpay/grovedb", rev = "6c882c3ee7d2c331f1feda2eb4223add9a6f0e45" } [dev-dependencies] criterion = "0.5" diff --git a/packages/rs-drive/src/drive/contract/insert/insert_contract/v0/tests/ranked_index_e2e_tests.rs b/packages/rs-drive/src/drive/contract/insert/insert_contract/v0/tests/ranked_index_e2e_tests.rs index 9262a07f598..d59306b7e26 100644 --- a/packages/rs-drive/src/drive/contract/insert/insert_contract/v0/tests/ranked_index_e2e_tests.rs +++ b/packages/rs-drive/src/drive/contract/insert/insert_contract/v0/tests/ranked_index_e2e_tests.rs @@ -72,7 +72,10 @@ use dpp::prelude::DataContract; use dpp::tests::json_document::json_document_to_contract; use dpp::version::PlatformVersion; use grovedb::element::indexed::AVG_FIXED_POINT_SCALE; -use grovedb::Element; +use grovedb::element::IndexAxis; +use grovedb::query_result_type::QueryResultType; +use grovedb::{AxisKeys, Element, PathQuery, PathQueryRun}; +use grovedb_query::AxisQuery; /// The one index property every doctype in the fixture ranks by. const GROUP_PROPERTY: &str = "restaurantId"; @@ -271,49 +274,57 @@ fn group_keys(entries: &[(T, Vec)]) -> Vec { .collect() } -fn avg_top_k(drive: &Drive, path: &[Vec], k: u16, descending: bool) -> Vec<(i128, Vec)> { - let path_refs: Vec<&[u8]> = path.iter().map(|v| v.as_slice()).collect(); - drive +/// Run a keys-only top-k axis read through the unified PathQuery +/// surface — the same route the ranked no-proof executor takes. +fn run_top_k_keys( + drive: &Drive, + path: &[Vec], + axis: IndexAxis, + k: u16, + descending: bool, +) -> AxisKeys { + let path_query = PathQuery::new_axis( + path.to_vec(), + AxisQuery::top_k(axis, k, 0, descending).keys_only(), + ); + match drive .grove - .indexed_avg_top_k_keys( - path_refs.as_slice(), - k, - descending, + .run_path_query( + &path_query, + true, + true, + true, + QueryResultType::QueryPathKeyElementTrioResultType, None, &platform_version().drive.grove_version, ) .unwrap() - .expect("indexed_avg_top_k_keys must succeed") + .expect("top-k axis read must succeed") + { + PathQueryRun::AxisKeys { keys, .. } => keys, + other => panic!("expected AxisKeys, got {other:?}"), + } +} + +fn avg_top_k(drive: &Drive, path: &[Vec], k: u16, descending: bool) -> Vec<(i128, Vec)> { + match run_top_k_keys(drive, path, IndexAxis::Avg, k, descending) { + AxisKeys::Avg(pairs) => pairs, + other => panic!("expected avg pairs, got {other:?}"), + } } fn count_top_k(drive: &Drive, path: &[Vec], k: u16, descending: bool) -> Vec<(u64, Vec)> { - let path_refs: Vec<&[u8]> = path.iter().map(|v| v.as_slice()).collect(); - drive - .grove - .indexed_count_top_k_keys( - path_refs.as_slice(), - k, - descending, - None, - &platform_version().drive.grove_version, - ) - .unwrap() - .expect("indexed_count_top_k_keys must succeed") + match run_top_k_keys(drive, path, IndexAxis::Count, k, descending) { + AxisKeys::Count(pairs) => pairs, + other => panic!("expected count pairs, got {other:?}"), + } } fn sum_top_k(drive: &Drive, path: &[Vec], k: u16, descending: bool) -> Vec<(i64, Vec)> { - let path_refs: Vec<&[u8]> = path.iter().map(|v| v.as_slice()).collect(); - drive - .grove - .indexed_sum_top_k_keys( - path_refs.as_slice(), - k, - descending, - None, - &platform_version().drive.grove_version, - ) - .unwrap() - .expect("indexed_sum_top_k_keys must succeed") + match run_top_k_keys(drive, path, IndexAxis::Sum, k, descending) { + AxisKeys::Sum(pairs) => pairs, + other => panic!("expected sum pairs, got {other:?}"), + } } // --------------------------------------------------------------------------- diff --git a/packages/rs-drive/src/query/drive_document_having_query/execute_range.rs b/packages/rs-drive/src/query/drive_document_having_query/execute_range.rs index 6707461d8d5..fa02f06804a 100644 --- a/packages/rs-drive/src/query/drive_document_having_query/execute_range.rs +++ b/packages/rs-drive/src/query/drive_document_having_query/execute_range.rs @@ -12,13 +12,15 @@ //! `pub mod execute_range;` declaration. use super::super::drive_document_ranked_query::{RankedAxis, RankedEntry, RankedEntryValue}; -use super::{AxisRangeBounds, DriveDocumentHavingQuery}; +use super::DriveDocumentHavingQuery; use crate::drive::Drive; use crate::error::drive::DriveError; use crate::error::Error; use dpp::version::PlatformVersion; -use grovedb::TransactionArg; +use grovedb::query_result_type::QueryResultType; +use grovedb::{AxisKeys, PathQuery, PathQueryRun, TransactionArg}; use grovedb_costs::CostContext; +use grovedb_query::AxisQuery; impl DriveDocumentHavingQuery<'_> { /// Read the matching groups directly from the axis secondary: every @@ -41,68 +43,73 @@ impl DriveDocumentHavingQuery<'_> { ) -> Result, Error> { let grove_version = &platform_version.drive.grove_version; let path = self.indexed_property_name_tree_path()?; - let path_refs: Vec<&[u8]> = path.iter().map(|segment| segment.as_slice()).collect(); + + // The same bounded axis PathQuery the prove path uses, with the + // keys-only projection: the matching pairs are read straight off + // the pinned secondary view, no primary values resolved. + let (lo, hi) = self.bounds.i128_bounds(); + let path_query = PathQuery::new_axis( + path, + AxisQuery::bounded( + self.bounds.axis().into(), + lo, + hi, + self.limit, + self.descending, + ) + .keys_only(), + ); // Costs are destructured away rather than `.unwrap()`-ed, same // as the ranked executors: `CostContext::unwrap` is infallible // but reads like a panicking unwrap at the call site. - let entries = match self.bounds { - AxisRangeBounds::Count { lo, hi } => { - let CostContext { value, cost: _ } = drive.grove.indexed_count_range_keys( - path_refs.as_slice(), - lo, - hi, - self.descending, - self.limit, - transaction, - grove_version, - ); - value - .map_err(|e| Error::GroveDB(Box::new(e)))? - .into_iter() - .map(|(count, key)| RankedEntry { - key, - value: RankedEntryValue::Count(count), - }) - .collect::>() - } - AxisRangeBounds::Sum { lo, hi } => { - let CostContext { value, cost: _ } = drive.grove.indexed_sum_range_keys( - path_refs.as_slice(), - lo, - hi, - self.descending, - self.limit, - transaction, - grove_version, - ); - value - .map_err(|e| Error::GroveDB(Box::new(e)))? - .into_iter() - .map(|(sum, key)| RankedEntry { - key, - value: RankedEntryValue::Sum(sum), - }) - .collect::>() - } - AxisRangeBounds::Avg { lo, hi } => { - let CostContext { value, cost: _ } = drive.grove.indexed_avg_range_keys( - path_refs.as_slice(), - lo, - hi, - self.descending, - self.limit, - transaction, - grove_version, - ); - value - .map_err(|e| Error::GroveDB(Box::new(e)))? - .into_iter() - .map(|(avg, key)| RankedEntry { - key, - value: RankedEntryValue::AvgFixedPoint(avg), - }) - .collect::>() + let CostContext { value, cost: _ } = drive.grove.run_path_query( + &path_query, + true, + true, + true, + QueryResultType::QueryPathKeyElementTrioResultType, + transaction, + grove_version, + ); + // `skipped` is the paginated traversal's field and is `None` + // for bounded ones — nothing to check here. + let PathQueryRun::AxisKeys { keys, skipped: _ } = + value.map_err(|e| Error::GroveDB(Box::new(e)))? + else { + return Err(Error::Drive(DriveError::CorruptedDriveState(format!( + "having {:?} range read ran to a non-axis-keys result shape", + self.bounds.axis() + )))); + }; + + let entries = match (self.bounds.axis(), keys) { + (RankedAxis::Count, AxisKeys::Count(pairs)) => pairs + .into_iter() + .map(|(count, key)| RankedEntry { + key, + value: RankedEntryValue::Count(count), + }) + .collect::>(), + (RankedAxis::Sum, AxisKeys::Sum(pairs)) => pairs + .into_iter() + .map(|(sum, key)| RankedEntry { + key, + value: RankedEntryValue::Sum(sum), + }) + .collect::>(), + (RankedAxis::Avg, AxisKeys::Avg(pairs)) => pairs + .into_iter() + .map(|(avg, key)| RankedEntry { + key, + value: RankedEntryValue::AvgFixedPoint(avg), + }) + .collect::>(), + (axis, other) => { + return Err(Error::Drive(DriveError::CorruptedDriveState(format!( + "having {axis:?} range read returned {} pairs of a different axis shape", + other.len() + )))); } }; @@ -120,57 +127,52 @@ impl DriveDocumentHavingQuery<'_> { Ok(entries) } - /// Generate the grovedb indexed-axis range proof for this query. + /// Generate the bounded-axis proof for this query, through the + /// unified `PathQuery` surface (grovedb's only public proof surface + /// for indexed-axis reads): the query is + /// [`PathQuery::new_axis_bounded`] and the envelope is a GroveDBProof + /// V1 carrying an axis descent into the queried secondary. /// /// The envelope commits the in-range secondary entries, the - /// primary's root hash, the sibling axes' root hashes, and a - /// per-ancestor attestation chain up to the grovedb root — so the - /// client reconstructs the platform root hash from it. The Merk - /// query (the encoded bounds and walk direction) and the limit are - /// echoed and re-checked by grovedb's verifier against the client's - /// own reconstruction via [`AxisRangeBounds::merk_query`] — which is - /// why the bounds are validated rather than clamped upstream, and - /// why completeness needs no extra machinery: a Merk range proof - /// over a sorted keyspace commits its boundaries, so an in-range - /// group the server omitted fails reconstruction. + /// primary's root hash, the sibling axes' root hashes, and the + /// ordinary layer chain up to the grovedb root — so the client + /// reconstructs the platform root hash from it. Nothing is echoed: + /// the verifier takes the client's own reconstruction of the same + /// `PathQuery` as input, and grovedb lowers its bounds into the + /// secondary's keyspace through one function shared by both proof + /// sides — which is why the bounds are validated rather than clamped + /// upstream, and why completeness needs no extra machinery: a Merk + /// range proof over a sorted keyspace commits its boundaries, so an + /// in-range group the server omitted fails reconstruction. /// /// Verified by /// [`DriveDocumentHavingQuery::verify_having_range_proof`](crate::query::DriveDocumentHavingQuery::verify_having_range_proof). pub fn execute_range_with_proof( &self, drive: &Drive, - transaction: TransactionArg, + _transaction: TransactionArg, platform_version: &PlatformVersion, ) -> Result, Error> { let grove_version = &platform_version.drive.grove_version; let path = self.indexed_property_name_tree_path()?; - let path_refs: Vec<&[u8]> = path.iter().map(|segment| segment.as_slice()).collect(); - let secondary_query = self.bounds.merk_query(self.descending); + let (lo, hi) = self.bounds.i128_bounds(); + let path_query = PathQuery::new_axis_bounded( + path, + self.bounds.axis().into(), + lo, + hi, + self.limit, + self.descending, + ); + // The unified prover proves committed state — it takes no + // transaction. The parameter is kept for signature stability with + // the no-proof executor; the query dispatch passes `None` on this + // surface anyway (queries answer from committed state). + // // Same destructure-don't-unwrap rationale as the no-proof arm. - let CostContext { value, cost: _ } = match self.bounds.axis() { - RankedAxis::Count => drive.grove.prove_indexed_count_query( - path_refs.as_slice(), - secondary_query, - Some(self.limit), - transaction, - grove_version, - ), - RankedAxis::Sum => drive.grove.prove_indexed_sum_query( - path_refs.as_slice(), - secondary_query, - Some(self.limit), - transaction, - grove_version, - ), - RankedAxis::Avg => drive.grove.prove_indexed_avg_query( - path_refs.as_slice(), - secondary_query, - Some(self.limit), - transaction, - grove_version, - ), - }; + let CostContext { value, cost: _ } = + drive.grove.prove_query(&path_query, None, grove_version); value.map_err(|e| Error::GroveDB(Box::new(e))) } } diff --git a/packages/rs-drive/src/query/drive_document_having_query/mod.rs b/packages/rs-drive/src/query/drive_document_having_query/mod.rs index f0418fc798a..dcf17d0b883 100644 --- a/packages/rs-drive/src/query/drive_document_having_query/mod.rs +++ b/packages/rs-drive/src/query/drive_document_having_query/mod.rs @@ -37,13 +37,15 @@ //! rank `offset`); having-range addresses them by **value bound** //! (`aggregate ∈ [lo, hi]`). Three consequences: //! -//! 1. **The bound is part of the proof contract.** The grovedb envelope -//! for a range read echoes the Merk query itself, and the verifier -//! re-builds that query from the request's bounds -//! ([`AxisRangeBounds::merk_query`]) — so prover and verifier must -//! share one bounds-to-query translation, exactly as they share the -//! grove path. Completeness comes from the Merk range proof: the -//! boundary commitments show no in-range group was omitted. +//! 1. **The bound is part of the proof contract.** Both proof sides +//! build the same [`grovedb::PathQuery::new_axis_bounded`] from the +//! request's bounds ([`AxisRangeBounds::i128_bounds`]), and grovedb +//! lowers those bounds into the secondary's keyspace through one +//! shared function on both the prover and the verifier — so the two +//! sides cannot drift on which range a proof is about, exactly as +//! they share the grove path. Completeness comes from the Merk range +//! proof: the boundary commitments show no in-range group was +//! omitted. //! 2. **No `OFFSET`, no `start_at` — and no full pagination.** The //! range primitives take a limit but no skip, and a request carrying //! either knob is rejected loudly. A page cut at `limit` can only be @@ -85,8 +87,6 @@ use crate::error::query::QuerySyntaxError; use crate::error::Error; #[cfg(any(feature = "server", feature = "verify"))] use grovedb::element::indexed::{encode_avg_sort_key, encode_count_sort_key, encode_sum_sort_key}; -#[cfg(any(feature = "server", feature = "verify"))] -use grovedb::Query; #[cfg(any(feature = "server", feature = "verify"))] pub mod mode_detection; @@ -196,23 +196,26 @@ impl AxisRangeBounds { } } - /// The Merk query over the axis secondary that reads exactly these - /// bounds, walking in the requested direction. + /// The inclusive bounds widened to `i128` — the domain + /// [`grovedb::PathQuery::new_axis_bounded`] takes for every axis. + /// + /// The prover/verifier-agreement artifact of the having surface is + /// grovedb's own bounded-axis lowering: both proof sides lower the + /// same `PathQuery` bounds into the secondary's keyspace through one + /// shared function inside grovedb, producing exactly the byte range + /// [`Self::secondary_key_bounds`] documents — inclusive at + /// `encode(lo)`, exclusive at `encode(hi + 1)`, open-ended at the + /// axis maximum. Platform no longer builds the Merk query itself, so + /// the two sides cannot drift on which range a proof is about. /// - /// This is the **prover/verifier-agreement artifact** of the having - /// surface: grovedb's range-proof envelope is generated against this - /// query and verified against the verifier's own reconstruction of - /// it, so both sides must build it from the same bounds through this - /// one function — a divergence surfaces as a failed verification, - /// not a wrong answer. - pub fn merk_query(&self, descending: bool) -> Query { - let (lower, upper) = self.secondary_key_bounds(); - let mut query = Query::new_with_direction(!descending); - match upper { - Some(upper) => query.insert_range(lower..upper), - None => query.insert_range_from(lower..), + /// Widening is lossless: `u64` and `i64` both embed in `i128`, and + /// grovedb clamps back to each axis's own domain when lowering. + pub fn i128_bounds(&self) -> (i128, i128) { + match *self { + AxisRangeBounds::Count { lo, hi } => (lo as i128, hi as i128), + AxisRangeBounds::Sum { lo, hi } => (lo as i128, hi as i128), + AxisRangeBounds::Avg { lo, hi } => (lo, hi), } - query } } @@ -253,8 +256,9 @@ pub struct DocumentHavingMode { /// A resolved having-range query. Shared by the prover and the verifier — /// both build the grove path through /// [`DriveDocumentHavingQuery::indexed_property_name_tree_path`] and the -/// secondary query through [`AxisRangeBounds::merk_query`], so the two -/// cannot drift on which subtree or which range the proof is about. +/// same bounded axis `PathQuery` through +/// [`AxisRangeBounds::i128_bounds`], so the two cannot drift on which +/// subtree or which range the proof is about. #[derive(Debug, Clone)] #[cfg(any(feature = "server", feature = "verify"))] pub struct DriveDocumentHavingQuery<'a> { diff --git a/packages/rs-drive/src/query/drive_document_having_query/tests.rs b/packages/rs-drive/src/query/drive_document_having_query/tests.rs index 496a199d79a..702fb5d7277 100644 --- a/packages/rs-drive/src/query/drive_document_having_query/tests.rs +++ b/packages/rs-drive/src/query/drive_document_having_query/tests.rs @@ -557,10 +557,27 @@ mod bounds { } #[test] - fn merk_query_direction_follows_descending() { - let bounds = AxisRangeBounds::Count { lo: 101, hi: 200 }; - assert!(bounds.merk_query(false).left_to_right); - assert!(!bounds.merk_query(true).left_to_right); + fn i128_bounds_widen_every_axis_losslessly() { + assert_eq!( + AxisRangeBounds::Count { + lo: 101, + hi: u64::MAX + } + .i128_bounds(), + (101, u64::MAX as i128) + ); + assert_eq!( + AxisRangeBounds::Sum { + lo: i64::MIN, + hi: -5 + } + .i128_bounds(), + (i64::MIN as i128, -5) + ); + assert_eq!( + AxisRangeBounds::Avg { lo: -5, hi: 5 }.i128_bounds(), + (-5, 5) + ); } } @@ -1049,24 +1066,19 @@ mod execution { let (drive, contract) = setup_restaurants(); // Empty secondary (no documents at all): the unproven read - // returns the empty list, but grovedb's range prover — unlike - // the ranked surface's paginated prover — has no absence-proof - // shape for a completely empty tree and refuses. drive-abci - // maps this exact failure class onto an `InvalidArgument` - // telling the caller to retry unproved - // (`empty_ranking_proof_rejection`); at the drive level it - // surfaces as the grovedb error asserted here. If a future - // grovedb pin makes empty range proofs work, this arm should - // flip to a round-trip assertion. + // returns the empty list, and the unified bounded-axis prover + // proves it — an empty secondary is carried as empty proof + // bytes that the verifier resolves to a NULL_HASH secondary + // root, so the parent binding only passes when the element + // genuinely commits an empty secondary. (The old standalone + // range prover refused this state outright with "Cannot create + // proof for empty tree", which is why drive-abci still keeps + // `empty_ranking_proof_rejection` as a backstop for that error + // class.) let case = HavingCase::count(HavingOperator::GreaterThan, Value::U64(100), 10); let entries = entries_of(run(&drive, &contract, &case, false).expect("read succeeds")); assert!(entries.is_empty()); - let error = run(&drive, &contract, &case, true) - .expect_err("proving against an empty secondary is refused by grovedb"); - assert!( - format!("{error}").contains("Cannot create proof for empty tree"), - "the failure must be the recognized empty-tree class, got: {error}" - ); + assert_proof_round_trips(&drive, &contract, &case, &entries); // Populated secondary, bound above every count: a genuine // absence proof, which works — the tree has content to anchor @@ -1095,6 +1107,14 @@ mod execution { /// verify under both — correctly, because the range boundaries /// prove both claims — so the distinguishing group is the point of /// the fixture. + /// + /// The unified verifier is query-as-input rather than echo-checked: + /// the invariant it holds is "a proof can never make the client + /// believe a wrong answer to the client's own query", not "a proof + /// only verifies under the exact request it was built for". A + /// tampered query whose answer the proof also correctly attests + /// (the limit case at the end) therefore verifies — to that + /// query's own correct answer. #[test] fn a_proof_does_not_verify_under_different_bounds() { let (drive, contract) = setup_restaurants(); @@ -1139,18 +1159,27 @@ mod execution { "a proof of `> 2` must not verify as `> 1`" ); - // Nor under a different direction or limit. + // Nor under a different direction. tampered_query = client_side_query(&contract, &over_two); tampered_query.descending = true; assert!(tampered_query .verify_having_range_proof(&proof, platform_version()) .is_err()); + // A different limit is NOT an echo check under the unified + // query-as-input verifier: the same bytes verify under any limit + // they can correctly answer. Here exactly one group matches + // `> 2`, so limit 5 and limit 10 have the same answer and the + // proof verifies to it — the sound outcome, since the entries + // ARE the right answer to the limit-5 question. What can never + // happen is an over-long answer: the verifier's own shape check + // caps entries at the query's limit. tampered_query = client_side_query(&contract, &over_two); tampered_query.limit = 5; - assert!(tampered_query + let (_, entries) = tampered_query .verify_having_range_proof(&proof, platform_version()) - .is_err()); + .expect("a proof whose answer also answers the smaller limit verifies under it"); + assert_eq!(keys_of(&entries), vec!["beta"]); } /// A `having` on an axis no index declares is refused with the diff --git a/packages/rs-drive/src/query/drive_document_ranked_query/execute_top_k.rs b/packages/rs-drive/src/query/drive_document_ranked_query/execute_top_k.rs index 9cda62c9234..e24b07b3aa8 100644 --- a/packages/rs-drive/src/query/drive_document_ranked_query/execute_top_k.rs +++ b/packages/rs-drive/src/query/drive_document_ranked_query/execute_top_k.rs @@ -15,8 +15,10 @@ use crate::drive::Drive; use crate::error::drive::DriveError; use crate::error::Error; use dpp::version::PlatformVersion; -use grovedb::{IndexedTopKKeysPage, TransactionArg}; +use grovedb::query_result_type::QueryResultType; +use grovedb::{AxisKeys, PathQuery, PathQueryRun, TransactionArg}; use grovedb_costs::CostContext; +use grovedb_query::AxisQuery; impl DriveDocumentRankedQuery<'_> { /// Read one page of the ranking directly from the axis secondary: @@ -73,8 +75,20 @@ impl DriveDocumentRankedQuery<'_> { ) -> Result { let grove_version = &platform_version.drive.grove_version; let path = self.indexed_property_name_tree_path()?; - let path_refs: Vec<&[u8]> = path.iter().map(|segment| segment.as_slice()).collect(); - let offset = self.offset as u64; + + // The same axis PathQuery the prove path uses, with the + // keys-only projection: the ranking pairs are read straight off + // the pinned secondary view, no primary values resolved. + let path_query = PathQuery::new_axis( + path, + AxisQuery::top_k( + self.axis.into(), + self.k, + self.offset as u64, + self.descending, + ) + .keys_only(), + ); // The cost is dropped rather than `.unwrap()`-ed: // `CostContext::unwrap` is infallible (it drops the cost field) @@ -84,73 +98,57 @@ impl DriveDocumentRankedQuery<'_> { // above it accumulates or charges the cost, and no credit is // debited for a read. grovedb computes the `OperationCost` // because its API always does, and it ends here. - let (entries, skipped) = match self.axis { - RankedAxis::Count => { - let CostContext { value, cost: _ } = - drive.grove.indexed_count_top_k_paginated_keys( - path_refs.as_slice(), - self.k, - offset, - self.descending, - transaction, - grove_version, - ); - let IndexedTopKKeysPage { entries, skipped } = - value.map_err(|e| Error::GroveDB(Box::new(e)))?; - ( - entries - .into_iter() - .map(|(count, key)| RankedEntry { - key, - value: RankedEntryValue::Count(count), - }) - .collect::>(), - skipped, - ) - } - RankedAxis::Sum => { - let CostContext { value, cost: _ } = drive.grove.indexed_sum_top_k_paginated_keys( - path_refs.as_slice(), - self.k, - offset, - self.descending, - transaction, - grove_version, - ); - let IndexedTopKKeysPage { entries, skipped } = - value.map_err(|e| Error::GroveDB(Box::new(e)))?; - ( - entries - .into_iter() - .map(|(sum, key)| RankedEntry { - key, - value: RankedEntryValue::Sum(sum), - }) - .collect::>(), - skipped, - ) - } - RankedAxis::Avg => { - let CostContext { value, cost: _ } = drive.grove.indexed_avg_top_k_paginated_keys( - path_refs.as_slice(), - self.k, - offset, - self.descending, - transaction, - grove_version, - ); - let IndexedTopKKeysPage { entries, skipped } = - value.map_err(|e| Error::GroveDB(Box::new(e)))?; - ( - entries - .into_iter() - .map(|(avg, key)| RankedEntry { - key, - value: RankedEntryValue::AvgFixedPoint(avg), - }) - .collect::>(), - skipped, - ) + let CostContext { value, cost: _ } = drive.grove.run_path_query( + &path_query, + true, + true, + true, + QueryResultType::QueryPathKeyElementTrioResultType, + transaction, + grove_version, + ); + let PathQueryRun::AxisKeys { keys, skipped } = + value.map_err(|e| Error::GroveDB(Box::new(e)))? + else { + return Err(Error::Drive(DriveError::CorruptedDriveState(format!( + "ranked {:?} read ran to a non-axis-keys result shape", + self.axis + )))); + }; + let skipped = skipped.ok_or_else(|| { + Error::Drive(DriveError::CorruptedDriveState(format!( + "ranked {:?} read carried no skip count for a paginated walk", + self.axis + ))) + })?; + + let entries = match (self.axis, keys) { + (RankedAxis::Count, AxisKeys::Count(pairs)) => pairs + .into_iter() + .map(|(count, key)| RankedEntry { + key, + value: RankedEntryValue::Count(count), + }) + .collect::>(), + (RankedAxis::Sum, AxisKeys::Sum(pairs)) => pairs + .into_iter() + .map(|(sum, key)| RankedEntry { + key, + value: RankedEntryValue::Sum(sum), + }) + .collect::>(), + (RankedAxis::Avg, AxisKeys::Avg(pairs)) => pairs + .into_iter() + .map(|(avg, key)| RankedEntry { + key, + value: RankedEntryValue::AvgFixedPoint(avg), + }) + .collect::>(), + (axis, other) => { + return Err(Error::Drive(DriveError::CorruptedDriveState(format!( + "ranked {axis:?} read returned {} pairs of a different axis shape", + other.len() + )))); } }; @@ -170,21 +168,25 @@ impl DriveDocumentRankedQuery<'_> { Ok(RankedPage { skipped, entries }) } - /// Generate the grovedb indexed-axis paginated top-k proof for this - /// query. + /// Generate the axis-ordered top-k proof for this query, through the + /// unified `PathQuery` surface (grovedb's only public proof surface + /// for indexed-axis reads): the query is + /// [`PathQuery::new_axis_top_k`] and the envelope is a GroveDBProof + /// V1 carrying an axis descent into the queried secondary. /// /// The envelope commits the walked secondary entries, the number of /// entries skipped to reach them, the primary's root hash, the - /// sibling axes' root hashes, and a per-ancestor attestation chain - /// up to the grovedb root — so the client reconstructs the platform - /// root hash from it. It also echoes `(axis, k, offset, - /// descending)`, which - /// [`grovedb::GroveDb::verify_indexed_axis_top_k_paginated`] - /// re-checks against what the client asked for; that is why `k` is + /// sibling axes' root hashes, and the ordinary layer chain up to the + /// grovedb root — so the client reconstructs the platform root hash + /// from it. `(axis, k, offset, descending)` are **not echoed** in the + /// envelope: the verifier takes the client's own reconstruction of + /// the same `PathQuery` as input, so a proof generated for a + /// different ranking — or a different page — fails verification + /// rather than being silently reinterpreted. That is why `k` is /// validated rather than clamped upstream (a clamped `k` would - /// produce a proof the client's own reconstruction rejects). + /// produce a proof the client's own query rejects). /// - /// The paginated primitive is used unconditionally, with + /// The paginated traversal is used unconditionally, with /// `offset = 0` for offset-free requests, so there is exactly one /// proof shape on this surface: a client never has to guess which of /// two envelope formats a server produced. @@ -204,23 +206,27 @@ impl DriveDocumentRankedQuery<'_> { pub fn execute_top_k_with_proof( &self, drive: &Drive, - transaction: TransactionArg, + _transaction: TransactionArg, platform_version: &PlatformVersion, ) -> Result, Error> { let grove_version = &platform_version.drive.grove_version; let path = self.indexed_property_name_tree_path()?; - let path_refs: Vec<&[u8]> = path.iter().map(|segment| segment.as_slice()).collect(); - - // Same destructure-don't-unwrap rationale as the no-proof arm. - let CostContext { value, cost: _ } = drive.grove.prove_indexed_axis_top_k_paginated( - path_refs.as_slice(), + let path_query = PathQuery::new_axis_top_k( + path, self.axis.into(), self.k, self.offset as u64, self.descending, - transaction, - grove_version, ); + + // The unified prover proves committed state — it takes no + // transaction. The parameter is kept for signature stability with + // the no-proof executor; the query dispatch passes `None` on this + // surface anyway (queries answer from committed state). + // + // Same destructure-don't-unwrap rationale as the no-proof arm. + let CostContext { value, cost: _ } = + drive.grove.prove_query(&path_query, None, grove_version); value.map_err(|e| Error::GroveDB(Box::new(e))) } } diff --git a/packages/rs-drive/src/query/drive_document_ranked_query/mod.rs b/packages/rs-drive/src/query/drive_document_ranked_query/mod.rs index a72ccd7b7f4..68a52700540 100644 --- a/packages/rs-drive/src/query/drive_document_ranked_query/mod.rs +++ b/packages/rs-drive/src/query/drive_document_ranked_query/mod.rs @@ -117,10 +117,10 @@ mod tests; /// is rejected with /// [`crate::error::query::QuerySyntaxError::InvalidLimit`] rather than /// silently truncated. Truncation would be especially treacherous here -/// because `k` is echoed inside the proof envelope and re-checked by -/// [`grovedb::GroveDb::verify_indexed_axis_top_k_paginated`] — a -/// server-side clamp would produce a proof the client's own -/// reconstruction rejects. +/// because the proof is verified against the client's own +/// reconstruction of the same axis `PathQuery` (with the client's `k`) +/// by [`grovedb::GroveDb::verify_path_query`] — a server-side clamp +/// would produce a proof the client's own query rejects. /// /// There is deliberately **no companion ceiling on `OFFSET`**; see the /// module docs and [`DriveDocumentRankedQuery::offset`]. diff --git a/packages/rs-drive/src/verify/document_having/mod.rs b/packages/rs-drive/src/verify/document_having/mod.rs index a3ddcec97e1..06d35824f66 100644 --- a/packages/rs-drive/src/verify/document_having/mod.rs +++ b/packages/rs-drive/src/verify/document_having/mod.rs @@ -10,9 +10,9 @@ //! //! Only one verifier exists here, for the same reason as on the ranked //! surface: every having-range request — any of the three axes, either -//! direction, any contiguous bound — resolves to one -//! `prove_indexed_axis_query` envelope that differs only in the Merk -//! query (the encoded bounds + direction) and limit it echoes. +//! direction, any contiguous bound — resolves to one bounded-axis +//! `PathQuery` proved through grovedb's unified `prove_query`, differing +//! only in the axis, bounds, direction and limit the query carries. /// Indexed-axis range proof verification — returns the groups the proof /// commits to as falling inside the bound, in axis order. diff --git a/packages/rs-drive/src/verify/document_having/verify_having_range_proof/mod.rs b/packages/rs-drive/src/verify/document_having/verify_having_range_proof/mod.rs index 893a2766bbb..9f202485af0 100644 --- a/packages/rs-drive/src/verify/document_having/verify_having_range_proof/mod.rs +++ b/packages/rs-drive/src/verify/document_having/verify_having_range_proof/mod.rs @@ -14,8 +14,8 @@ impl DriveDocumentHavingQuery<'_> { /// [`execute_range_with_proof`](Self::execute_range_with_proof). /// Both sides derive the proved subtree from /// [`indexed_property_name_tree_path`](Self::indexed_property_name_tree_path) - /// and the secondary query from - /// [`AxisRangeBounds::merk_query`](crate::query::drive_document_having_query::AxisRangeBounds::merk_query), + /// and the same bounded axis `PathQuery` from + /// [`AxisRangeBounds::i128_bounds`](crate::query::drive_document_having_query::AxisRangeBounds::i128_bounds), /// so the verifier cannot drift from the prover on *which* bound over /// *which* tree it is checking. /// diff --git a/packages/rs-drive/src/verify/document_having/verify_having_range_proof/v0/mod.rs b/packages/rs-drive/src/verify/document_having/verify_having_range_proof/v0/mod.rs index 9caf4f9df85..2cf0a0ebdf2 100644 --- a/packages/rs-drive/src/verify/document_having/verify_having_range_proof/v0/mod.rs +++ b/packages/rs-drive/src/verify/document_having/verify_having_range_proof/v0/mod.rs @@ -3,31 +3,32 @@ use crate::error::Error; use crate::query::{DriveDocumentHavingQuery, RankedAxis, RankedEntry, RankedEntryValue}; use crate::verify::RootHash; use dpp::version::PlatformVersion; -use grovedb::operations::proof::indexed_axis::AxisEntries; -use grovedb::GroveDb; +use grovedb::operations::proof::{indexed_axis::AxisEntries, VerifiedPathQuery}; +use grovedb::{GroveDb, PathQuery}; impl DriveDocumentHavingQuery<'_> { /// v0 of [`Self::verify_having_range_proof`]. /// - /// Rebuilds the proved subtree path with - /// [`Self::indexed_property_name_tree_path`] and the secondary query - /// with - /// [`AxisRangeBounds::merk_query`](crate::query::drive_document_having_query::AxisRangeBounds::merk_query), - /// then hands the proof to the matching - /// `GroveDb::verify_indexed_*_query` — an associated function, no - /// database handle, so this compiles and runs in a verifier-only - /// build. + /// Rebuilds the same [`PathQuery::new_axis_bounded`] the prover used + /// — the path via [`Self::indexed_property_name_tree_path`], the + /// bounds via + /// [`AxisRangeBounds::i128_bounds`](crate::query::drive_document_having_query::AxisRangeBounds::i128_bounds) + /// — then hands the proof to [`GroveDb::verify_path_query`] — an + /// associated function, no database handle, so this compiles and + /// runs in a verifier-only build. /// /// Three things are checked before the entries are returned: /// - /// 1. **The envelope matches this query.** grovedb re-checks the - /// proof against the reconstructed Merk query (the encoded bounds - /// and walk direction) and the expected limit, so a proof - /// generated for a different bound — or a different direction, or - /// a different limit — is rejected rather than silently - /// reinterpreted. Completeness rides on the same check: a Merk - /// range proof commits its boundaries, so an in-range group the - /// prover omitted fails reconstruction. + /// 1. **The proof answers this query.** The unified verifier is + /// query-as-input: nothing is echoed in the envelope; grovedb + /// lowers the query's bounds into the secondary's keyspace + /// through the same function the prover used and verifies the + /// proof against that reconstruction, so a proof generated for a + /// different bound — or a different direction, or a different + /// limit — is rejected rather than silently reinterpreted. + /// Completeness rides on the same check: a Merk range proof + /// commits its boundaries, so an in-range group the prover + /// omitted fails reconstruction. /// 2. **The result's axis shape matches the requested axis** — the /// same belt-and-braces check the ranked verifier does. /// 3. **At most `limit` entries.** Fewer is normal — fewer groups @@ -44,35 +45,35 @@ impl DriveDocumentHavingQuery<'_> { platform_version: &PlatformVersion, ) -> Result<(RootHash, Vec), Error> { let path = self.indexed_property_name_tree_path()?; - let path_refs: Vec<&[u8]> = path.iter().map(|segment| segment.as_slice()).collect(); - let secondary_query = self.bounds.merk_query(self.descending); + let (lo, hi) = self.bounds.i128_bounds(); + let path_query = PathQuery::new_axis_bounded( + path, + self.bounds.axis().into(), + lo, + hi, + self.limit, + self.descending, + ); - let result = match self.bounds.axis() { - RankedAxis::Count => GroveDb::verify_indexed_count_query( - proof, - path_refs.as_slice(), - secondary_query, - Some(self.limit), - &platform_version.drive.grove_version, - ), - RankedAxis::Sum => GroveDb::verify_indexed_sum_query( - proof, - path_refs.as_slice(), - secondary_query, - Some(self.limit), - &platform_version.drive.grove_version, - ), - RankedAxis::Avg => GroveDb::verify_indexed_avg_query( - proof, - path_refs.as_slice(), - secondary_query, - Some(self.limit), - &platform_version.drive.grove_version, - ), - } - .map_err(|e| Error::GroveDB(Box::new(e)))?; + let verified = + GroveDb::verify_path_query(proof, &path_query, &platform_version.drive.grove_version) + .map_err(|e| Error::GroveDB(Box::new(e)))?; + + // `skipped` is the paginated traversal's field and is `None` for + // bounded ones — nothing to check here. + let VerifiedPathQuery::AxisEntries { + root_hash, + entries, + skipped: _, + } = verified + else { + return Err(Error::Drive(DriveError::CorruptedDriveState(format!( + "having range proof for the {:?} axis verified to a non-axis result shape", + self.bounds.axis() + )))); + }; - let entries = match (self.bounds.axis(), result.entries) { + let entries = match (self.bounds.axis(), entries) { (RankedAxis::Count, AxisEntries::Count(entries)) => entries .into_iter() .map(|entry| entry.key_pair()) @@ -115,6 +116,6 @@ impl DriveDocumentHavingQuery<'_> { )))); } - Ok((result.root_hash, entries)) + Ok((root_hash, entries)) } } diff --git a/packages/rs-drive/src/verify/document_ranked/mod.rs b/packages/rs-drive/src/verify/document_ranked/mod.rs index 0a5a0e0b8a7..d99a6b887f1 100644 --- a/packages/rs-drive/src/verify/document_ranked/mod.rs +++ b/packages/rs-drive/src/verify/document_ranked/mod.rs @@ -12,8 +12,9 @@ //! single proof shape. Where the count surface has five verifiers because //! five different grovedb primitives can answer a count, every ranked //! request — either direction, at any offset, on any of the three axes — -//! resolves to one `prove_indexed_axis_top_k_paginated` envelope that -//! differs only in the `(axis, k, descending, offset)` tuple it echoes. +//! resolves to one top-k axis `PathQuery` proved through grovedb's +//! unified `prove_query`, differing only in the `(axis, k, descending, +//! offset)` tuple the query carries. /// Indexed-axis top-k proof verification — returns the ranked groups the /// proof commits to, in ranking order. diff --git a/packages/rs-drive/src/verify/document_ranked/verify_ranked_top_k_proof/v0/mod.rs b/packages/rs-drive/src/verify/document_ranked/verify_ranked_top_k_proof/v0/mod.rs index 82f5b0a2320..6e540052520 100644 --- a/packages/rs-drive/src/verify/document_ranked/verify_ranked_top_k_proof/v0/mod.rs +++ b/packages/rs-drive/src/verify/document_ranked/verify_ranked_top_k_proof/v0/mod.rs @@ -5,31 +5,33 @@ use crate::query::{ }; use crate::verify::RootHash; use dpp::version::PlatformVersion; -use grovedb::operations::proof::indexed_axis::AxisEntries; -use grovedb::GroveDb; +use grovedb::operations::proof::{indexed_axis::AxisEntries, VerifiedPathQuery}; +use grovedb::{GroveDb, PathQuery}; impl DriveDocumentRankedQuery<'_> { /// v0 of [`Self::verify_ranked_top_k_proof`]. /// - /// Rebuilds the proved subtree path with - /// [`Self::indexed_property_name_tree_path`] and hands the proof to - /// [`GroveDb::verify_indexed_axis_top_k_paginated`], which is an - /// associated function — no database handle is involved, so this - /// compiles and runs in a verifier-only build. + /// Rebuilds the same [`PathQuery::new_axis_top_k`] the prover used — + /// path via [`Self::indexed_property_name_tree_path`], the axis / + /// `k` / offset / direction from this query — and hands the proof to + /// [`GroveDb::verify_path_query`], which is an associated function — + /// no database handle is involved, so this compiles and runs in a + /// verifier-only build. /// /// Three things are checked before the page is returned: /// - /// 1. **The envelope's `(axis, k, offset, descending)` match this - /// query.** grovedb does this itself: the values are echoed in - /// the proof and compared against the arguments, so a proof - /// generated for a different ranking — or a different page of the - /// same ranking — is rejected rather than silently reinterpreted. + /// 1. **The proof answers this query.** The unified verifier is + /// query-as-input: nothing is echoed in the envelope; the proof is + /// verified against the verifier's own reconstruction of the + /// `PathQuery`, so a proof generated for a different ranking — or + /// a different page of the same ranking — fails verification + /// rather than being silently reinterpreted. /// 2. **The result's axis shape matches the requested axis** — a /// `Count` request must not come back holding `Sum` entries. This - /// is belt-and-braces on top of (1) (the tag check already rules - /// it out) and exists so a future decoder change that decouples - /// the tag from the decoded variant surfaces as an error here - /// instead of a mis-typed number reaching the caller. + /// is belt-and-braces on top of (1) (the query's axis already + /// rules it out) and exists so a future decoder change that + /// decouples the query from the decoded variant surfaces as an + /// error here instead of a mis-typed number reaching the caller. /// 3. **At most `k` entries.** Fewer is normal — the index may hold /// fewer groups than were asked for — but more would mean the /// proof committed a longer walk than the request authorized. @@ -52,20 +54,41 @@ impl DriveDocumentRankedQuery<'_> { platform_version: &PlatformVersion, ) -> Result<(RootHash, RankedPage), Error> { let path = self.indexed_property_name_tree_path()?; - let path_refs: Vec<&[u8]> = path.iter().map(|segment| segment.as_slice()).collect(); - - let result = GroveDb::verify_indexed_axis_top_k_paginated( - proof, - path_refs.as_slice(), + let path_query = PathQuery::new_axis_top_k( + path, self.axis.into(), self.k, self.offset as u64, self.descending, - &platform_version.drive.grove_version, - ) - .map_err(|e| Error::GroveDB(Box::new(e)))?; + ); + + let verified = + GroveDb::verify_path_query(proof, &path_query, &platform_version.drive.grove_version) + .map_err(|e| Error::GroveDB(Box::new(e)))?; + + let VerifiedPathQuery::AxisEntries { + root_hash, + entries, + skipped, + } = verified + else { + return Err(Error::Drive(DriveError::CorruptedDriveState(format!( + "ranked top-k proof for the {:?} axis verified to a non-axis result shape", + self.axis + )))); + }; + + // A paginated (top-k) traversal always attests its skip count; + // `None` is the bounded traversal's shape and cannot answer this + // query. + let skipped = skipped.ok_or_else(|| { + Error::Drive(DriveError::CorruptedDriveState(format!( + "ranked top-k proof for the {:?} axis carried no attested skip count", + self.axis + ))) + })?; - let entries = match (self.axis, result.entries) { + let entries = match (self.axis, entries) { (RankedAxis::Count, AxisEntries::Count(entries)) => entries .into_iter() .map(|entry| entry.key_pair()) @@ -108,12 +131,6 @@ impl DriveDocumentRankedQuery<'_> { )))); } - Ok(( - result.root_hash, - RankedPage { - skipped: result.skipped, - entries, - }, - )) + Ok((root_hash, RankedPage { skipped, entries })) } } diff --git a/packages/rs-platform-version/Cargo.toml b/packages/rs-platform-version/Cargo.toml index 4ee353c872e..74faf5deaf6 100644 --- a/packages/rs-platform-version/Cargo.toml +++ b/packages/rs-platform-version/Cargo.toml @@ -11,7 +11,7 @@ license = "MIT" thiserror = { version = "2.0.12" } bincode = { version = "=2.0.1" } versioned-feature-core = { git = "https://github.com/dashpay/versioned-feature-core", version = "1.0.0" } -grovedb-version = { git = "https://github.com/dashpay/grovedb", rev = "753a11f14c9a4bc72bf2d5302751dd43d174621e" } +grovedb-version = { git = "https://github.com/dashpay/grovedb", rev = "6c882c3ee7d2c331f1feda2eb4223add9a6f0e45" } [features] mock-versions = [] diff --git a/packages/rs-platform-version/src/version/drive_versions/drive_verify_method_versions/mod.rs b/packages/rs-platform-version/src/version/drive_versions/drive_verify_method_versions/mod.rs index 84af8082e48..58280be26b8 100644 --- a/packages/rs-platform-version/src/version/drive_versions/drive_verify_method_versions/mod.rs +++ b/packages/rs-platform-version/src/version/drive_versions/drive_verify_method_versions/mod.rs @@ -76,8 +76,8 @@ pub struct DriveVerifyDocumentSumMethodVersions { /// Versions for the indexed-axis prove-path verifiers: the ranked /// (top-k) verifier and the boolean-`HAVING` range verifier. Both are /// implemented on the respective drive query types and delegate to -/// grovedb's indexed-axis proof verification -/// (`verify_indexed_axis_top_k_paginated` / `verify_indexed_axis_query`). +/// grovedb's unified `verify_path_query` over the query's axis +/// `PathQuery` (`new_axis_top_k` / `new_axis_bounded`). #[derive(Clone, Debug, Default)] pub struct DriveVerifyDocumentRankedMethodVersions { pub verify_ranked_top_k_proof: FeatureVersion, diff --git a/packages/rs-platform-wallet/Cargo.toml b/packages/rs-platform-wallet/Cargo.toml index 755f7bb110b..a46939a40ca 100644 --- a/packages/rs-platform-wallet/Cargo.toml +++ b/packages/rs-platform-wallet/Cargo.toml @@ -69,7 +69,7 @@ zeroize = "1" log = "0.4" # Shielded pool (optional, behind `shielded` feature) -grovedb-commitment-tree = { git = "https://github.com/dashpay/grovedb", rev = "753a11f14c9a4bc72bf2d5302751dd43d174621e", optional = true } +grovedb-commitment-tree = { git = "https://github.com/dashpay/grovedb", rev = "6c882c3ee7d2c331f1feda2eb4223add9a6f0e45", optional = true } # Direct `rusqlite` access so `FileBackedShieldedStore::open_path` can set # WAL + synchronous=NORMAL pragmas before handing the connection to # `ClientPersistentCommitmentTree`. Version locked to match the rev grovedb diff --git a/packages/rs-sdk/Cargo.toml b/packages/rs-sdk/Cargo.toml index ee1bfca14ae..95a53f942cf 100644 --- a/packages/rs-sdk/Cargo.toml +++ b/packages/rs-sdk/Cargo.toml @@ -18,7 +18,7 @@ drive = { path = "../rs-drive", default-features = false, features = [ ] } drive-proof-verifier = { path = "../rs-drive-proof-verifier", default-features = false } -grovedb-commitment-tree = { git = "https://github.com/dashpay/grovedb", rev = "753a11f14c9a4bc72bf2d5302751dd43d174621e", features = [ +grovedb-commitment-tree = { git = "https://github.com/dashpay/grovedb", rev = "6c882c3ee7d2c331f1feda2eb4223add9a6f0e45", features = [ "client", "sqlite", ], optional = true }