pub struct DriveDocumentCountQuery<'a> {
pub document_type: DocumentTypeRef<'a>,
pub contract_id: [u8; 32],
pub document_type_name: String,
pub index: &'a Index,
pub where_clauses: Vec<WhereClause>,
}Expand description
A query to count documents using CountTree elements in the index path.
This struct encapsulates all the information needed to perform a count query on a document type’s countable index.
Fields§
§document_type: DocumentTypeRef<'a>The document type to count
contract_id: [u8; 32]The contract id (32 bytes)
document_type_name: StringThe document type name
index: &'a IndexThe countable index to use
where_clauses: Vec<WhereClause>The equality where clauses that match index prefix properties
Implementations§
Source§impl DriveDocumentCountQuery<'_>
impl DriveDocumentCountQuery<'_>
Sourcepub fn is_range_operator(op: WhereOperator) -> bool
pub fn is_range_operator(op: WhereOperator) -> bool
Returns true if op is a range operator that can be served by a
range_countable index walking the property-name ProvableCountTree’s
children. The non-prefix portion of a range count query carries
exactly one range operator on the index’s last property.
Sourcepub fn has_unsupported_operator(where_clauses: &[WhereClause]) -> bool
pub fn has_unsupported_operator(where_clauses: &[WhereClause]) -> bool
Returns true if any where clause uses an operator the count fast path
cannot serve. Callers should treat this as a query-rejection signal.
Sourcepub fn detect_mode(
where_clauses: &[WhereClause],
mode: CountMode,
prove: bool,
) -> Result<DocumentCountMode, QuerySyntaxError>
pub fn detect_mode( where_clauses: &[WhereClause], mode: CountMode, prove: bool, ) -> Result<DocumentCountMode, QuerySyntaxError>
Classify a count query’s mode from its where clauses + request flags.
This is the protocol-version-agnostic shape detection that
decides which executor (one of the six
DocumentCountMode variants — Total / PerInValue /
RangeNoProof / RangeProof / RangeDistinctProof /
PointLookupProof) the request maps to. The returned
DocumentCountMode discriminates among the dispatcher’s
match arms; concrete pagination / index-picker inputs flow
through the call sites separately.
All validation that depends only on the where clauses + flags
(multiple range clauses, range mixed with In, distinct mode on
the prove path, distinct mode without a range clause, etc.) is
done here and surfaces as
QuerySyntaxError::InvalidWhereClauseComponents. Validation
that depends on the contract’s index set (no covering index)
stays at the call site since it requires the
&BTreeMap<String, Index>.
Source§impl DriveDocumentCountQuery<'_>
impl DriveDocumentCountQuery<'_>
Sourcepub fn find_countable_index_for_where_clauses<'b>(
indexes: &'b BTreeMap<String, Index>,
where_clauses: &[WhereClause],
) -> Option<&'b Index>
pub fn find_countable_index_for_where_clauses<'b>( indexes: &'b BTreeMap<String, Index>, where_clauses: &[WhereClause], ) -> Option<&'b Index>
Finds a countable: true index whose properties exactly match the
indexable (Equal/In) where-clause fields — every index property has a
corresponding clause AND every clause’s field appears in the index.
Exact coverage is the contract for both no-proof and prove count paths: a countable index counts exactly what it indexes, and queries against partially-covered indexes are rejected with a clear error directing the caller at the index-design fix. This avoids the product-of-uncovered-branching-factors walk that a prefix-match approach would silently fall through to, and keeps the storage’s “count maintained only at the terminal level” trade-off intact (no need to maintain counts at intermediate index levels just to serve partial-coverage queries cheaply).
Returns None if:
- Any where clause uses an operator other than
Equal/In. - The set of indexable where-clause fields doesn’t exactly equal the
set of properties of any single
countable: trueindex.
For the documents_countable: true case (total count with no where
clauses), the dispatcher reads the document-type primary-key tree’s
CountTree directly — that path doesn’t use this picker because no
index is involved.
Sourcepub fn find_range_countable_index_for_where_clauses<'b>(
indexes: &'b BTreeMap<String, Index>,
where_clauses: &[WhereClause],
) -> Option<&'b Index>
pub fn find_range_countable_index_for_where_clauses<'b>( indexes: &'b BTreeMap<String, Index>, where_clauses: &[WhereClause], ) -> Option<&'b Index>
Finds a range_countable index that can serve a range-count query.
Match criteria:
- All
Equal/Inwhere-clause fields form a prefix of the index properties. - There is exactly one range-operator where-clause, on a property that is the last property of the index (the IndexLevel terminator). This is the property whose values get walked.
- The index has
range_countable = trueandcountable.is_countable().
Returns None if no such index exists or if there’s more than one
range operator in the where clauses (which would require nested range
walks the current model doesn’t support). Pure point-lookup queries
(no range operator) should fall back to
Self::find_countable_index_for_where_clauses.
Source§impl DriveDocumentCountQuery<'_>
impl DriveDocumentCountQuery<'_>
Sourcepub fn aggregate_count_path_query(
&self,
platform_version: &PlatformVersion,
) -> Result<PathQuery, Error>
pub fn aggregate_count_path_query( &self, platform_version: &PlatformVersion, ) -> Result<PathQuery, Error>
Build the grovedb PathQuery for an AggregateCountOnRange
query against this count query’s range_countable index.
Shared between the server-side prove path
(Self::execute_aggregate_count_with_proof) and the client-
side verify path (the SDK’s FromProof<DocumentQuery> for
DocumentCount, via the shared verify_aggregate_count
helper). Both sides must produce the exact same PathQuery
for verification to recompute the same merk root.
Aggregate-count specifically restricts prefix props to Equal:
grovedb’s AggregateCountOnRange primitive wraps a single
inner range and emits one aggregate u64 — there’s no way for
it to cartesian-fork over multiple In values at the merk
layer. For per-distinct-value counts with In on prefix, use
Self::distinct_count_path_query instead.
Errors:
- No range where-clause / multiple range where-clauses →
InvalidWhereClauseComponents Inon a prefix property →InvalidWhereClauseComponents(aggregate primitive can’t fork)- Missing prefix clause →
InvalidWhereClauseComponents
Sourcepub fn carrier_aggregate_count_path_query(
&self,
limit: Option<u16>,
platform_version: &PlatformVersion,
) -> Result<PathQuery, Error>
pub fn carrier_aggregate_count_path_query( &self, limit: Option<u16>, platform_version: &PlatformVersion, ) -> Result<PathQuery, Error>
Build the grovedb PathQuery for a carrier
AggregateCountOnRange proof — one outer Key per In
value, each terminating in an ACOR boundary walk over the
per-branch range subtree. Returns one (in_key, u64) pair
per resolved In branch via
[grovedb::GroveDb::query_aggregate_count_per_key] (no-
proof) and
[grovedb::GroveDb::verify_aggregate_count_query_per_key]
(verify).
Required where-clause shape (validated upstream by
Self::detect_mode routing to
[DocumentCountMode::RangeAggregateCarrierProof]):
- Exactly one
Inclause on the In-property - Exactly one range clause on the terminator property of
a
range_countable: trueindex whose first property is the In-property - Any prefix properties between In and range must use
==(mirror ofSelf::aggregate_count_path_query’s non-In prefix rule)
Path-query structure:
- Outer path stops one level above the In-bearing property
subtree’s children (
@/doc_prefix/0x01/doctype/<In-prop>). - Outer Query:
Key(in_value_0),Key(in_value_1), … in lex-asc serialized order (grovedb’s multi-key walker invariant). subquery_path: the terminator property name (and any trailing==clause names between In and range, in index order).subquery:Query::new_aggregate_count_on_range(range_item).
Enabled by grovedb PR #663.
Before that PR, AggregateCountOnRange was required to be
the only item in its query and could not appear under a
subquery field — the dispatcher rejected this shape with
“range count queries with an in clause are not supported on
the aggregate prove path”.
Errors:
- No range where-clause / multiple range where-clauses →
InvalidWhereClauseComponents - No In where-clause →
InvalidWhereClauseComponents - In on a non-prefix property →
InvalidWhereClauseComponents - Prefix property between In and range uses non-Equal →
InvalidWhereClauseComponents
Sourcepub fn distinct_count_path_query(
&self,
limit: Option<u16>,
left_to_right: bool,
platform_version: &PlatformVersion,
) -> Result<PathQuery, Error>
pub fn distinct_count_path_query( &self, limit: Option<u16>, left_to_right: bool, platform_version: &PlatformVersion, ) -> Result<PathQuery, Error>
Build the grovedb PathQuery for a regular range query
against this count query’s range_countable index — the
distinct-counts variant. Used by:
- the server’s prove-distinct executor
(
Self::execute_distinct_count_with_proof) - the server’s no-proof range executor
(
Self::execute_range_count_no_proof) - the SDK’s per-key-count verifier
([
drive_proof_verifier::verify_distinct_count_proof])
In-on-prefix support via grovedb subqueries. Where
Self::aggregate_count_path_query rejects In on prefix
(the aggregate merk primitive can’t cartesian-fork), this
builder uses grovedb’s native subquery primitive:
- Flat shape (no In on prefix, only Equal): path includes the range terminator; outer Query has the range item.
- Compound shape (one In on prefix): path stops at the
In-bearing prop’s property-name subtree; outer Query has
one
Key(value)item per In value;set_subquery_pathcarries any post-In Equal-clause(name, value)pairs plus the terminator name;set_subqueryis the range item.
Both shapes return (path, branched-or-flat Query) and feed
the same grove_get_raw_path_query / get_proved_path_query
pipelines downstream. The compound shape replaces the
pre-existing cartesian-fork loop in
execute_range_count_no_proof.
limit IS load-bearing for prove-path verification: the
prover bounds the proof at limit matched keys, and the
verifier must build the exact same PathQuery (including
this cap) for the merk-root recomputation to match. The
dispatcher pre-validates limit ≤ max_query_limit on the
prove path, so unbounded queries can’t reach this builder
with Some(...) greater than the cap. The no-proof path
passes None (full walk) so cross-In-fork merging sees
every emitted element before the result-set-level limit is
applied in post-processing.
left_to_right controls grovedb’s iteration direction:
true (the default, used for ascending order_by_ascending)
walks the range from low key to high key; false reverses.
On the prove path this is load-bearing: the path query’s
Query.left_to_right is part of the serialized PathQuery
bytes, so the prover and verifier must agree on the value or
the merk-root recomputation fails. For compound queries the
flag is applied to BOTH the outer In-keys Query and the
inner range subquery, so descending iteration walks
(in_key_desc, key_desc) tuples (matching what
RangeCountOptions::order_by_ascending = false callers
expect).
Errors:
- No range where-clause / multiple range where-clauses
- Multiple In clauses on prefix props
- Non-Equal-non-In operator on a prefix prop
- Missing prefix clause
Sourcepub fn point_lookup_count_path_query(
&self,
platform_version: &PlatformVersion,
) -> Result<PathQuery, Error>
pub fn point_lookup_count_path_query( &self, platform_version: &PlatformVersion, ) -> Result<PathQuery, Error>
Build the grovedb PathQuery for a point-lookup count proof
against a countable: true index. Returns one element per
covered branch whose count_value is the per-branch document
count.
Shared between the server-side prove path
(Self::execute_point_lookup_count_with_proof) and the
client-side verify path
(Self::verify_point_lookup_count_proof). Both sides must
produce the exact same PathQuery for the merk-root
recomputation to match.
§Two terminator shapes depending on range_countable
The proof’s terminal element is at one of two layers, picked
from Index::range_countable:
- Normal
countable: true(NOTrange_countable): the terminator’s value tree is aNormalTree, and the doc-countCountTreesits inside it at the conventional[0]child. Proof targets[..., last_field, last_value, 0]. range_countable: true: the terminator’s value tree is itself aCountTree(continuation property-name subtrees sit beneath asElement::NonCountedso they don’t pollute the parent count — seeadd_indices_for_index_level_for_contract_operations_v0). The value tree’s owncount_value_or_default()already IS the per-branch doc count, so the proof targets the value tree directly at[..., last_field, last_value]and saves one merk-path layer per covered branch.
Concretely the optimization replaces a trailing Key([0])
with Key(last_value) against [..., last_field] (Equal-
only, no In) — or against the In-bearing prop’s property-name
subtree (In on terminator) — or replaces the trailing pair in
set_subquery_path (In on prefix + trailing Equals that reach
the terminator). The query shape stays in the same Query/
subquery topology so byte-equality across prover and verifier
is preserved by construction.
§Shape support
The builder requires the where clauses to fully cover the
index — every property in self.index.properties must have a
matching Equal or In clause. Partial-coverage shapes
(where some index properties have no matching clause) require
a recursive subquery enumeration that this builder does not
implement (and that the strict picker already rejects upstream).
In may appear at any position in the index. Equal
clauses before the In contribute to base_path; Equal clauses
after the In feed set_subquery_path on the outer Query so the
descent under each matched In value lands at the right
CountTree leaf. At most one In clause per query (multiple
would cartesian-fork beyond what a single set_subquery
expresses).
This is more permissive than the regular document query
path’s Index::matches rule (packages/rs-dpp/src/ data_contract/document_type/index/mod.rs:503), which restricts
In to the last or before-last index property because its
path-construction code positionally zips intermediate index
names with Equal-clause values (see
DriveDocumentQuery::get_non_primary_key_path_query). The
count path doesn’t have that constraint: it’s a pure CountTree
element lookup with no document-key terminator descent, no
order_by interpretation, and no limit/offset semantics, so
set_subquery_path with an arbitrary trailing tail just
works. Both no-proof (Self::execute_no_proof) and prove
(Self::execute_point_lookup_count_with_proof) executors
route through this single builder, so they accept the same
query shapes by construction.
Output shapes (countable / range_countable differ only in
whether the trailing Key([0]) is replaced by Key(last_value)):
- Equal-only, fully covered:
countable: path[..., last_field, last_value], singleKey([0]).range_countable: path[..., last_field], singleKey(last_value).
- Equal prefix +
In(any position) [+ trailing Equals]: compound query withbase_pathending at the In-bearing property’s property-name subtree (Equal clauses before the In are baked intobase_path); outer Query has oneKeyper In value (sorted lex-asc for prove/no-proof parity and pushed-limit safety — same convention asSelf::distinct_count_path_query).- In on terminator:
countable: subqueryKey([0])under each In value’s value tree (set_subquery_pathunset).range_countable: outerKeys already point at the CountTree value trees themselves; no subquery is set.
- In on a prefix + trailing Equals reaching the
terminator:
set_subquery_pathcarries the post-In Equal(name, value)pairs in index order:countable: full pairs, subqueryKey([0]).range_countable: last pair’svalueis hoisted out as the subquery’s singleKey(value);set_subquery_pathends at the terminator’s property-name segment.
- In on terminator:
§Errors
Rejects shapes the builder doesn’t support:
- Partial coverage (uncovered index property)
- More than one
Inclause - Any non-
Equal/ non-Inoperator (defense-in-depth; mode detection already filters these out)
Sourcepub fn primary_key_count_tree_path_query(
contract_id: [u8; 32],
document_type_name: &str,
) -> PathQuery
pub fn primary_key_count_tree_path_query( contract_id: [u8; 32], document_type_name: &str, ) -> PathQuery
Build the grovedb PathQuery for proving the document type’s
primary-key CountTree element at [contract_doc, contract_id, 1, doctype, 0]. Used for unfiltered total counts when the
document type has documents_countable: true — the
type-level CountTree’s count_value IS the total document
count, no index walk needed.
Shared between the server-side prove path
([Drive::execute_document_count_point_lookup_proof]’s
documents_countable fast path) and the client-side verify path
(Self::verify_primary_key_count_tree_proof). Both sides
produce the exact same PathQuery for merk-root recomputation.
Free function rather than a method on DriveDocumentCountQuery
because the documents_countable case isn’t tied to any index —
it operates at the doctype level directly.
Source§impl DriveDocumentCountQuery<'_>
impl DriveDocumentCountQuery<'_>
Sourcepub fn execute_no_proof(
&self,
drive: &Drive,
transaction: TransactionArg<'_, '_>,
platform_version: &PlatformVersion,
) -> Result<Vec<SplitCountEntry>, Error>
pub fn execute_no_proof( &self, drive: &Drive, transaction: TransactionArg<'_, '_>, platform_version: &PlatformVersion, ) -> Result<Vec<SplitCountEntry>, Error>
Executes the count query without generating a proof.
Returns the total count as a single SplitCountEntry with
empty key (the unified-count Total shape).
Implementation goes through the same
Self::point_lookup_count_path_query builder the prove
path uses, then runs grove.query to fetch the matched
CountTree elements and sums their count_value_or_default()
values. The builder handles all three structural cases
(Equal-only fully covered, In at any index position, In with
trailing Equals via set_subquery_path) — there’s no need
for a separate recursive walker on the no-proof side.
Sourcepub fn execute_point_lookup_count_with_proof(
&self,
drive: &Drive,
transaction: TransactionArg<'_, '_>,
platform_version: &PlatformVersion,
) -> Result<Vec<u8>, Error>
pub fn execute_point_lookup_count_with_proof( &self, drive: &Drive, transaction: TransactionArg<'_, '_>, platform_version: &PlatformVersion, ) -> Result<Vec<u8>, Error>
Generates a grovedb proof of the CountTree elements covering a
fully-covered Equal/In count query against a countable: true
index. Returns the raw proof bytes; the SDK-side
Self::verify_point_lookup_count_proof walks the proof and
extracts count_value_or_default() from each verified CountTree
element.
Builds the path query via
Self::point_lookup_count_path_query (shared with the
verifier AND with Self::execute_no_proof above, so all three
sites see byte-identical path queries). Errors surface from the
builder when the query shape isn’t supported — partial
coverage, more than one In, etc. — see that builder’s docstring
for the exhaustive contract.
Proof size is O(k × log n) where k is the number of covered
(Equal/In) branches and n is the tree depth: one merk path
proof per CountTree element, not per matching document.
Avoids the materialize-and-count alternative used by the
regular document-query path, which scales with the number
of matching docs and is capped at u16::MAX.
Source§impl DriveDocumentCountQuery<'_>
impl DriveDocumentCountQuery<'_>
Sourcepub fn execute_range_count_no_proof(
&self,
drive: &Drive,
options: &RangeCountOptions,
transaction: TransactionArg<'_, '_>,
platform_version: &PlatformVersion,
) -> Result<Vec<SplitCountEntry>, Error>
pub fn execute_range_count_no_proof( &self, drive: &Drive, options: &RangeCountOptions, transaction: TransactionArg<'_, '_>, platform_version: &PlatformVersion, ) -> Result<Vec<SplitCountEntry>, Error>
Executes a range-aware count query against a range_countable
index. Path layout is [contract_doc, doctype, prefix..., range_prop_name], whose children are the per-value
CountTree leaves keyed by the range property’s serialized
value.
The caller picks the index via
Self::find_range_countable_index_for_where_clauses; this
method assumes:
self.index.range_countable == true- All
Equal/Inwhere clauses cover the index prefix - Exactly one range-operator where clause hits the index’s last property
§Execution strategies by mode
- Flat summed (no
In,distinct = false): singlequery_aggregate_countcall against the merk-levelAggregateCountOnRangeprimitive. O(log n). - Compound summed (
Inon prefix,distinct = false): per-In-value fan-out — onequery_aggregate_countcall per matched In branch, summed in Rust. Bounded by the In array’s 100-element cap (enforced byWhereClause::in_values) times O(log n), so worst-case work is 100 × O(log n) regardless of how many documents the range actually matches. Closes the request-amplification surface a pre-fix walk-and-sum implementation had: that path materialized every matched(in_key, key)element even though the response was still a single aggregateu64. - Distinct mode (
distinct = true, with or withoutInon prefix): walks the unifiedSelf::distinct_count_path_queryand emits one entry per matched(in_key, key)pair. The path query carriesoptions.limit(clamped tomax_query_limitupstream by the dispatcher) andoptions.order_by_ascending, so per-query work is O(limit × log n). Cross-fork aggregation is intentionally NOT performed server-side; callers reduce bykeyclient-side if they want a flat histogram. See the book chapter (“No-Merge Compound Semantics”) for the rationale.
§Returned entry shape
When options.distinct = false, returns a single entry with
in_key = None, empty key, and count equal to the sum of
all matched per-value counts. When options.distinct = true,
returns one entry per emitted (in_key, key) pair, after
applying order_by_ascending and limit over the
lexicographic (in_key, key) tuple.
Sourcepub fn execute_aggregate_count_with_proof(
&self,
drive: &Drive,
transaction: TransactionArg<'_, '_>,
platform_version: &PlatformVersion,
) -> Result<Vec<u8>, Error>
pub fn execute_aggregate_count_with_proof( &self, drive: &Drive, transaction: TransactionArg<'_, '_>, platform_version: &PlatformVersion, ) -> Result<Vec<u8>, Error>
Generates a grovedb AggregateCountOnRange proof for a
range-count query against a range_countable index. The returned
proof bytes can be verified client-side via
GroveDb::verify_aggregate_count_query, which yields
(root_hash, count) — replacing the materialize-and-count proof
path that capped at u16::MAX documents.
Limitations vs. Self::execute_range_count_no_proof:
- Returns ONLY the total count (a single number, no
per-distinct-value entries) —
AggregateCountOnRangeis a single-aggregate primitive at the merk layer. - Requires the prefix to resolve to exactly one path.
Inon prefix properties is not supported because grovedb’s aggregate primitive only lifts a single inner range.
Sourcepub fn execute_distinct_count_with_proof(
&self,
drive: &Drive,
limit: u16,
left_to_right: bool,
transaction: TransactionArg<'_, '_>,
platform_version: &PlatformVersion,
) -> Result<Vec<u8>, Error>
pub fn execute_distinct_count_with_proof( &self, drive: &Drive, limit: u16, left_to_right: bool, transaction: TransactionArg<'_, '_>, platform_version: &PlatformVersion, ) -> Result<Vec<u8>, Error>
Generates a regular grovedb range proof against this count
query’s range_countable index — the distinct-counts-with-
proof companion to Self::execute_aggregate_count_with_proof.
No new prover code: the leaf is a ProvableCountTree and
merk’s existing prove_query already emits KVCount(key, value, count) per matched in-range key (via
to_kv_count_node). Each count is hash-bound to the merk
root via node_hash_with_count, so the per-key correctness
guarantee comes for free with the standard hash-chain check —
the SDK-side
[drive_proof_verifier::verify_distinct_count_proof] just
pulls the counts out of the proof’s op stream after the
integrity check passes.
Trade-off vs. the aggregate prove path:
- Returns per-distinct-value counts (one
(key, count)per matched lot value), not just a single sum. - Proof size is O(distinct values matched), not O(log n) — so
~1
KVCountop per matched key instead of subtree collapse viaHashWithCount. Still strictly smaller than materialize-and-count, which would emit each underlying doc.
Sourcepub fn execute_carrier_aggregate_count_with_proof(
&self,
drive: &Drive,
limit: Option<u16>,
transaction: TransactionArg<'_, '_>,
platform_version: &PlatformVersion,
) -> Result<Vec<u8>, Error>
pub fn execute_carrier_aggregate_count_with_proof( &self, drive: &Drive, limit: Option<u16>, transaction: TransactionArg<'_, '_>, platform_version: &PlatformVersion, ) -> Result<Vec<u8>, Error>
Generates a grovedb carrier AggregateCountOnRange proof
for In + range queries with group_by = [in_field]. The
proof commits one aggregate count per resolved In branch
via grovedb’s carrier-subquery composition
(PR #663).
Path query: see
Self::carrier_aggregate_count_path_query.
Trade-off vs. the alternative
Self::execute_distinct_count_with_proof
(GroupByCompound shape):
- This (carrier-ACOR): O(|In| · (log B + log C’)) proof
bytes. One commit per merk-tree boundary node per In
branch — preserves the per-branch aggregate granularity
that
group_by = [in_field, range_field]can’t express (the compound shape commits per-distinct-value-pair entries). - Alternative (distinct compound): O(|In| · R · log C’)
where R is distinct in-range values per branch. Carries
strictly more information (one
(in_key, range_key)pair per resolved doc) at substantially larger bytes.
Verified client-side via
[grovedb::GroveDb::verify_aggregate_count_query_per_key],
which returns (RootHash, Vec<(Vec<u8>, u64)>).
Source§impl DriveDocumentCountQuery<'_>
impl DriveDocumentCountQuery<'_>
Sourcepub fn verify_aggregate_count_proof(
&self,
proof: &[u8],
platform_version: &PlatformVersion,
) -> Result<(RootHash, u64), Error>
pub fn verify_aggregate_count_proof( &self, proof: &[u8], platform_version: &PlatformVersion, ) -> Result<(RootHash, u64), Error>
Verifies an AggregateCountOnRange proof and returns
(root_hash, count).
Counterpart to the prover-side
execute_aggregate_count_with_proof:
rebuilds the same PathQuery via
aggregate_count_path_query
and calls GroveDb::verify_aggregate_count_query. The
caller is responsible for combining the returned root_hash
with the surrounding tenderdash signature — see
rs-drive-proof-verifier’s verify_aggregate_count_proof
wrapper for the canonical composition.
§Arguments
proof— raw grovedb proof bytes.platform_version— selects the method version.
Source§impl DriveDocumentCountQuery<'_>
impl DriveDocumentCountQuery<'_>
Sourcepub fn verify_carrier_aggregate_count_proof(
&self,
proof: &[u8],
limit: Option<u16>,
platform_version: &PlatformVersion,
) -> Result<(RootHash, Vec<(Vec<u8>, u64)>), Error>
pub fn verify_carrier_aggregate_count_proof( &self, proof: &[u8], limit: Option<u16>, platform_version: &PlatformVersion, ) -> Result<(RootHash, Vec<(Vec<u8>, u64)>), Error>
Verifies a carrier AggregateCountOnRange proof and
returns (root_hash, per_key_counts) — one (in_key, u64)
pair per resolved In branch in serialized lex-asc order.
Counterpart to the prover-side
execute_carrier_aggregate_count_with_proof:
rebuilds the same PathQuery via
carrier_aggregate_count_path_query
and calls
[grovedb::GroveDb::verify_aggregate_count_query_per_key].
The caller is responsible for combining the returned
root_hash with the surrounding tenderdash signature — see
rs-drive-proof-verifier’s wrapper for the canonical
composition.
§Arguments
proof— raw grovedb proof bytes.platform_version— selects the method version.
The Vec<(Vec<u8>, u64)> payload mirrors grovedb’s per-key
carrier shape — see the v0 inner method for the rationale.
Source§impl DriveDocumentCountQuery<'_>
impl DriveDocumentCountQuery<'_>
Sourcepub fn verify_distinct_count_proof(
&self,
proof: &[u8],
limit: u16,
left_to_right: bool,
platform_version: &PlatformVersion,
) -> Result<(RootHash, Vec<SplitCountEntry>), Error>
pub fn verify_distinct_count_proof( &self, proof: &[u8], limit: u16, left_to_right: bool, platform_version: &PlatformVersion, ) -> Result<(RootHash, Vec<SplitCountEntry>), Error>
Verifies a regular grovedb range proof against a
ProvableCountTree and returns (root_hash, entries). Each
entry’s count is bound to the merk root via
node_hash_with_count(kv_hash, l_hash, r_hash, count), so
once this returns Ok every count is cryptographically
committed to the same root_hash the caller can pass to a
tenderdash signature check.
Counterpart to the prover-side
execute_distinct_count_with_proof:
rebuilds the same PathQuery via
distinct_count_path_query
and calls GroveDb::verify_query. Caller is responsible for
combining the returned root_hash with the surrounding
tenderdash signature — see rs-drive-proof-verifier’s
verify_distinct_count_proof wrapper for the canonical
composition.
Entries are emitted unmerged: for compound (In-on-prefix)
queries each entry retains its in_key (the In value for
that fork) alongside the terminator key. See
SplitCountEntry’s doc for the no-merge rationale.
§Arguments
proof— raw grovedb proof bytes.limit— the same limit the prover applied (also used to reconstruct the matching path query).left_to_right— same iteration direction the prover used.platform_version— selects the method version.
Source§impl DriveDocumentCountQuery<'_>
impl DriveDocumentCountQuery<'_>
Sourcepub fn verify_point_lookup_count_proof(
&self,
proof: &[u8],
platform_version: &PlatformVersion,
) -> Result<(RootHash, Vec<SplitCountEntry>), Error>
pub fn verify_point_lookup_count_proof( &self, proof: &[u8], platform_version: &PlatformVersion, ) -> Result<(RootHash, Vec<SplitCountEntry>), Error>
Verifies a grovedb proof of CountTree elements produced by the
point-lookup count proof path and returns (root_hash, entries).
Counterpart to the prover-side
execute_point_lookup_count_with_proof:
rebuilds the same PathQuery via
point_lookup_count_path_query
and calls GroveDb::verify_query. Each verified element’s
count_value is cryptographically bound to the merk root via
node_hash_with_count(kv_hash, l_hash, r_hash, count), so once
this returns Ok every count is committed to the same
root_hash the caller can pass to a tenderdash signature check.
Caller is responsible for combining the returned root_hash
with the surrounding tenderdash signature — see
rs-drive-proof-verifier’s verify_point_lookup_count_proof
wrapper for the canonical composition.
Entry shape:
- Equal-only, fully covered: a single entry with
in_key: None,key: vec![], andcountequal to the covered branch’s CountTreecount_value. Inat any index position (with any number of trailing Equals): one entry per In value, within_key: None,key: <serialized_in_value>, andcountequal to that In branch’s CountTreecount_value. When the In has trailing Equal clauses after it (e.g.a IN [..] AND b = y AND c = zon index[a, b, c]), those Equals are part of the descent so each branch’s count is “docs within_field == in_value AND <every trailing Equal>”; the entry’skeystill records just the In value because the trailing Equals are fixed across all entries. Matches the no-proofPerInValueshape (in_keyis reserved for the range-distinct compound case where In sits on a prefix of a range index).
Branches with no documents at the covered path don’t appear in the result (CountTree element is absent → no entry emitted).
Source§impl DriveDocumentCountQuery<'_>
impl DriveDocumentCountQuery<'_>
Sourcepub fn verify_primary_key_count_tree_proof(
proof: &[u8],
contract_id: [u8; 32],
document_type_name: &str,
platform_version: &PlatformVersion,
) -> Result<(RootHash, u64), Error>
pub fn verify_primary_key_count_tree_proof( proof: &[u8], contract_id: [u8; 32], document_type_name: &str, platform_version: &PlatformVersion, ) -> Result<(RootHash, u64), Error>
Verifies a grovedb proof of the document type’s primary-key
CountTree element and returns (root_hash, count). Used by
the SDK to verify the response from the prove path’s
documents_countable: true fast path — unfiltered total
counts on a doctype whose primary-key tree is itself a
CountTree.
Free-function on the type rather than &self because the
documents_countable case isn’t tied to any index — it
operates on the doctype primary-key tree directly. The
contract_id + document_type_name are all the verifier
needs to reconstruct the same PathQuery the prover used
via Self::primary_key_count_tree_path_query.
The verified count is cryptographically bound to the merk
root via node_hash_with_count(kv_hash, l_hash, r_hash, count) — same forge-resistance guarantee the other count-
proof verifiers rely on. Once this returns Ok, the count is
committed to the root_hash the caller passes to the
tenderdash signature check.
Returns count = 0 when the CountTree element is absent
(fresh doctype with no documents inserted). The
documents_countable storage layout creates the type-level
CountTree at contract apply time, so absence really does mean
“zero docs”; callers can rely on it.
Trait Implementations§
Source§impl<'a> Clone for DriveDocumentCountQuery<'a>
impl<'a> Clone for DriveDocumentCountQuery<'a>
Source§fn clone(&self) -> DriveDocumentCountQuery<'a>
fn clone(&self) -> DriveDocumentCountQuery<'a>
1.0.0 · Source§fn clone_from(&mut self, source: &Self)
fn clone_from(&mut self, source: &Self)
source. Read moreAuto Trait Implementations§
impl<'a> Freeze for DriveDocumentCountQuery<'a>
impl<'a> RefUnwindSafe for DriveDocumentCountQuery<'a>
impl<'a> Send for DriveDocumentCountQuery<'a>
impl<'a> Sync for DriveDocumentCountQuery<'a>
impl<'a> Unpin for DriveDocumentCountQuery<'a>
impl<'a> UnsafeUnpin for DriveDocumentCountQuery<'a>
impl<'a> UnwindSafe for DriveDocumentCountQuery<'a>
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
Source§impl<T> CloneToUninit for Twhere
T: Clone,
impl<T> CloneToUninit for Twhere
T: Clone,
§impl<T> Conv for T
impl<T> Conv for T
§impl<T> CostsExt for T
impl<T> CostsExt for T
§fn wrap_with_cost(self, cost: OperationCost) -> CostContext<Self>where
Self: Sized,
fn wrap_with_cost(self, cost: OperationCost) -> CostContext<Self>where
Self: Sized,
CostContext object with provided costs.§fn wrap_fn_cost(
self,
f: impl FnOnce(&Self) -> OperationCost,
) -> CostContext<Self>where
Self: Sized,
fn wrap_fn_cost(
self,
f: impl FnOnce(&Self) -> OperationCost,
) -> CostContext<Self>where
Self: Sized,
CostContext object with costs computed using the
value getting wrapped.§impl<T> FmtForward for T
impl<T> FmtForward for T
§fn fmt_binary(self) -> FmtBinary<Self>where
Self: Binary,
fn fmt_binary(self) -> FmtBinary<Self>where
Self: Binary,
self to use its Binary implementation when Debug-formatted.§fn fmt_display(self) -> FmtDisplay<Self>where
Self: Display,
fn fmt_display(self) -> FmtDisplay<Self>where
Self: Display,
self to use its Display implementation when
Debug-formatted.§fn fmt_lower_exp(self) -> FmtLowerExp<Self>where
Self: LowerExp,
fn fmt_lower_exp(self) -> FmtLowerExp<Self>where
Self: LowerExp,
self to use its LowerExp implementation when
Debug-formatted.§fn fmt_lower_hex(self) -> FmtLowerHex<Self>where
Self: LowerHex,
fn fmt_lower_hex(self) -> FmtLowerHex<Self>where
Self: LowerHex,
self to use its LowerHex implementation when
Debug-formatted.§fn fmt_octal(self) -> FmtOctal<Self>where
Self: Octal,
fn fmt_octal(self) -> FmtOctal<Self>where
Self: Octal,
self to use its Octal implementation when Debug-formatted.§fn fmt_pointer(self) -> FmtPointer<Self>where
Self: Pointer,
fn fmt_pointer(self) -> FmtPointer<Self>where
Self: Pointer,
self to use its Pointer implementation when
Debug-formatted.§fn fmt_upper_exp(self) -> FmtUpperExp<Self>where
Self: UpperExp,
fn fmt_upper_exp(self) -> FmtUpperExp<Self>where
Self: UpperExp,
self to use its UpperExp implementation when
Debug-formatted.§fn fmt_upper_hex(self) -> FmtUpperHex<Self>where
Self: UpperHex,
fn fmt_upper_hex(self) -> FmtUpperHex<Self>where
Self: UpperHex,
self to use its UpperHex implementation when
Debug-formatted.§fn fmt_list(self) -> FmtList<Self>where
&'a Self: for<'a> IntoIterator,
fn fmt_list(self) -> FmtList<Self>where
&'a Self: for<'a> IntoIterator,
§impl<T> Instrument for T
impl<T> Instrument for T
§fn instrument(self, span: Span) -> Instrumented<Self>
fn instrument(self, span: Span) -> Instrumented<Self>
§fn in_current_span(self) -> Instrumented<Self>
fn in_current_span(self) -> Instrumented<Self>
Source§impl<T> IntoEither for T
impl<T> IntoEither for T
Source§fn into_either(self, into_left: bool) -> Either<Self, Self>
fn into_either(self, into_left: bool) -> Either<Self, Self>
self into a Left variant of Either<Self, Self>
if into_left is true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read moreSource§fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
self into a Left variant of Either<Self, Self>
if into_left(&self) returns true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read more§impl<T, U> IntoOnNetwork<U> for Twhere
U: FromOnNetwork<T>,
impl<T, U> IntoOnNetwork<U> for Twhere
U: FromOnNetwork<T>,
§fn into_on_network(self, network: Network) -> U
fn into_on_network(self, network: Network) -> U
Calls U::from_on_network(self).
Source§impl<T, U> IntoPlatformVersioned<U> for Twhere
U: FromPlatformVersioned<T>,
impl<T, U> IntoPlatformVersioned<U> for Twhere
U: FromPlatformVersioned<T>,
Source§fn into_platform_versioned(self, platform_version: &PlatformVersion) -> U
fn into_platform_versioned(self, platform_version: &PlatformVersion) -> U
§impl<T> Pipe for Twhere
T: ?Sized,
impl<T> Pipe for Twhere
T: ?Sized,
§fn pipe<R>(self, func: impl FnOnce(Self) -> R) -> Rwhere
Self: Sized,
fn pipe<R>(self, func: impl FnOnce(Self) -> R) -> Rwhere
Self: Sized,
§fn pipe_ref<'a, R>(&'a self, func: impl FnOnce(&'a Self) -> R) -> Rwhere
R: 'a,
fn pipe_ref<'a, R>(&'a self, func: impl FnOnce(&'a Self) -> R) -> Rwhere
R: 'a,
self and passes that borrow into the pipe function. Read more§fn pipe_ref_mut<'a, R>(&'a mut self, func: impl FnOnce(&'a mut Self) -> R) -> Rwhere
R: 'a,
fn pipe_ref_mut<'a, R>(&'a mut self, func: impl FnOnce(&'a mut Self) -> R) -> Rwhere
R: 'a,
self and passes that borrow into the pipe function. Read more§fn pipe_borrow<'a, B, R>(&'a self, func: impl FnOnce(&'a B) -> R) -> R
fn pipe_borrow<'a, B, R>(&'a self, func: impl FnOnce(&'a B) -> R) -> R
§fn pipe_borrow_mut<'a, B, R>(
&'a mut self,
func: impl FnOnce(&'a mut B) -> R,
) -> R
fn pipe_borrow_mut<'a, B, R>( &'a mut self, func: impl FnOnce(&'a mut B) -> R, ) -> R
§fn pipe_as_ref<'a, U, R>(&'a self, func: impl FnOnce(&'a U) -> R) -> R
fn pipe_as_ref<'a, U, R>(&'a self, func: impl FnOnce(&'a U) -> R) -> R
self, then passes self.as_ref() into the pipe function.§fn pipe_as_mut<'a, U, R>(&'a mut self, func: impl FnOnce(&'a mut U) -> R) -> R
fn pipe_as_mut<'a, U, R>(&'a mut self, func: impl FnOnce(&'a mut U) -> R) -> R
self, then passes self.as_mut() into the pipe
function.§fn pipe_deref<'a, T, R>(&'a self, func: impl FnOnce(&'a T) -> R) -> R
fn pipe_deref<'a, T, R>(&'a self, func: impl FnOnce(&'a T) -> R) -> R
self, then passes self.deref() into the pipe function.§impl<T> Pointable for T
impl<T> Pointable for T
§impl<T> Tap for T
impl<T> Tap for T
§fn tap_borrow<B>(self, func: impl FnOnce(&B)) -> Self
fn tap_borrow<B>(self, func: impl FnOnce(&B)) -> Self
Borrow<B> of a value. Read more§fn tap_borrow_mut<B>(self, func: impl FnOnce(&mut B)) -> Self
fn tap_borrow_mut<B>(self, func: impl FnOnce(&mut B)) -> Self
BorrowMut<B> of a value. Read more§fn tap_ref<R>(self, func: impl FnOnce(&R)) -> Self
fn tap_ref<R>(self, func: impl FnOnce(&R)) -> Self
AsRef<R> view of a value. Read more§fn tap_ref_mut<R>(self, func: impl FnOnce(&mut R)) -> Self
fn tap_ref_mut<R>(self, func: impl FnOnce(&mut R)) -> Self
AsMut<R> view of a value. Read more§fn tap_deref<T>(self, func: impl FnOnce(&T)) -> Self
fn tap_deref<T>(self, func: impl FnOnce(&T)) -> Self
Deref::Target of a value. Read more§fn tap_deref_mut<T>(self, func: impl FnOnce(&mut T)) -> Self
fn tap_deref_mut<T>(self, func: impl FnOnce(&mut T)) -> Self
Deref::Target of a value. Read more§fn tap_dbg(self, func: impl FnOnce(&Self)) -> Self
fn tap_dbg(self, func: impl FnOnce(&Self)) -> Self
.tap() only in debug builds, and is erased in release builds.§fn tap_mut_dbg(self, func: impl FnOnce(&mut Self)) -> Self
fn tap_mut_dbg(self, func: impl FnOnce(&mut Self)) -> Self
.tap_mut() only in debug builds, and is erased in release
builds.§fn tap_borrow_dbg<B>(self, func: impl FnOnce(&B)) -> Self
fn tap_borrow_dbg<B>(self, func: impl FnOnce(&B)) -> Self
.tap_borrow() only in debug builds, and is erased in release
builds.§fn tap_borrow_mut_dbg<B>(self, func: impl FnOnce(&mut B)) -> Self
fn tap_borrow_mut_dbg<B>(self, func: impl FnOnce(&mut B)) -> Self
.tap_borrow_mut() only in debug builds, and is erased in release
builds.§fn tap_ref_dbg<R>(self, func: impl FnOnce(&R)) -> Self
fn tap_ref_dbg<R>(self, func: impl FnOnce(&R)) -> Self
.tap_ref() only in debug builds, and is erased in release
builds.§fn tap_ref_mut_dbg<R>(self, func: impl FnOnce(&mut R)) -> Self
fn tap_ref_mut_dbg<R>(self, func: impl FnOnce(&mut R)) -> Self
.tap_ref_mut() only in debug builds, and is erased in release
builds.§fn tap_deref_dbg<T>(self, func: impl FnOnce(&T)) -> Self
fn tap_deref_dbg<T>(self, func: impl FnOnce(&T)) -> Self
.tap_deref() only in debug builds, and is erased in release
builds.