drive/verify/mod.rs
1#![allow(clippy::result_large_err)] // Errors intentionally carry rich context in verify paths
2 // TODO: Revisit after shrinking top-level Error by boxing heavy variants
3use crate::error::Error;
4use dpp::version::PlatformVersion;
5use grovedb::{GroveDb, PathQuery};
6
7/// Chained document query (provable semi-join) verification methods on
8/// proofs — two grovedb proofs verified as one composed statement.
9pub mod chained_document;
10/// Composite document query (page plus derived sub-queries)
11/// verification methods on proofs — one merged proof verified as one
12/// composed statement.
13pub mod composite_document;
14///DataContract verification methods on proofs
15pub mod contract;
16/// Document verification methods on proofs
17pub mod document;
18/// Document-count verification methods on proofs (the
19/// `GetDocumentsCount` endpoint's prove-path verifiers).
20pub mod document_count;
21/// Having-range verification methods on proofs (the
22/// `GROUP BY … HAVING <aggregate> <op> <value> LIMIT n` surface's
23/// prove-path verifier).
24pub mod document_having;
25/// Document-ranked verification methods on proofs (the
26/// `GROUP BY … ORDER BY <aggregate> LIMIT n` surface's prove-path
27/// verifier).
28pub mod document_ranked;
29/// Document-sum verification methods on proofs (the
30/// `GetDocumentsSum` endpoint's prove-path verifiers).
31pub mod document_sum;
32/// Identity verification methods on proofs
33pub mod identity;
34/// Single Document verification methods on proofs
35pub mod single_document;
36
37/// System components (Epoch info etc...) verification methods on proofs
38pub mod system;
39
40/// Address funds proof verification module
41pub mod address_funds;
42/// Contract group proof verification
43pub mod contract_groups;
44/// Contract moderation proofs: one identity's status and pages of a contract's lists.
45pub mod contract_moderation;
46/// Group proof verification module
47pub mod group;
48/// The GroveDB proof envelope floor clients apply before a proof reaches Drive.
49pub mod grovedb_proof_envelope;
50/// Shielded pool proof verification module
51pub mod shielded;
52/// Verifies that a state transition contents exist in the proof
53pub mod state_transition;
54/// Token proof verification module
55pub mod tokens;
56/// Voting proof verification module
57pub mod voting;
58
59mod bounded_decode;
60
61/// Represents the root hash of the grovedb tree
62pub type RootHash = [u8; 32];
63
64/// A range total's verification from protocol version 14 on: `verified`, or,
65/// when grovedb refused the proof, the empty total `empty` makes of the root
66/// the proof reconstructs, if the proof shows the range holds nothing
67/// ([`verify_empty_range_tree`] over the path of `range_path`'s query, the
68/// query the prover proved); otherwise grovedb's refusal. The range-total
69/// verifiers at version 1 wrap their version 0, which refuses such a proof as
70/// released, in it.
71pub(crate) fn or_empty_range_total<V>(
72 verified: Result<V, Error>,
73 proof: &[u8],
74 range_path: impl FnOnce() -> Result<PathQuery, Error>,
75 empty: impl FnOnce(RootHash) -> V,
76 platform_version: &PlatformVersion,
77) -> Result<V, Error> {
78 match verified {
79 Ok(verified) => Ok(verified),
80 Err(error) => {
81 let path_query = range_path()?;
82 match verify_empty_range_tree(proof, &path_query.path, platform_version) {
83 Some(root_hash) => Ok(empty(root_hash)),
84 None => Err(error),
85 }
86 }
87 }
88}
89
90/// The root hash a range-total proof reconstructs when the range it totals
91/// holds nothing, or `None` when the proof does not show that: a key on
92/// `path` is missing (an equality value no document holds), or the path's
93/// last key holds an empty tree. grovedb proves a missing key absent and
94/// descends no further, and proves an empty tree of a kind the read does not
95/// aggregate (a provable sum tree under a count read, say) without a lower
96/// layer; its aggregate verifiers reject both as a missing layer. The same
97/// proof verifies as a plain query for the path's last key, which then holds
98/// no element, or the empty tree itself, its hash bound to the empty tree's:
99/// a tree holding entries comes with the lower layer the aggregate read
100/// proved, which a plain key query refuses, or is not empty. So `Some` proves
101/// the range holds nothing, and its total is zero.
102fn verify_empty_range_tree(
103 proof: &[u8],
104 path: &[Vec<u8>],
105 platform_version: &PlatformVersion,
106) -> Option<RootHash> {
107 let (key, parent) = path.split_last()?;
108 let query = PathQuery::new_single_key(parent.to_vec(), key.clone());
109 let (root_hash, elements) =
110 GroveDb::verify_query(proof, &query, &platform_version.drive.grove_version).ok()?;
111 match elements.as_slice() {
112 [] => Some(root_hash),
113 [(_, _, Some(element))] if element.is_any_tree() && !element.is_non_empty_tree() => {
114 Some(root_hash)
115 }
116 _ => None,
117 }
118}