drive/verify/chained_document/verify_chained_documents_proof/mod.rs
1mod v0;
2
3use crate::error::drive::DriveError;
4use crate::error::Error;
5use crate::query::{ChainedDocumentsResult, DriveDocumentQuery};
6use crate::verify::RootHash;
7use dpp::version::PlatformVersion;
8
9impl DriveDocumentQuery<'_> {
10 /// Verifies a chained query's single merged proof — this query as the
11 /// inner half plus the single by-id join its
12 /// [`sub_queries`](DriveDocumentQuery::sub_queries) carry — and
13 /// returns `(root_hash, result)`.
14 ///
15 /// The verifier trusts nothing about the join, and needs nothing
16 /// beyond the proof itself: a BOOTSTRAP subset pass runs the inner
17 /// query alone against the merged proof and extracts candidate
18 /// join values from its proven positions; the outer by-ids
19 /// component is derived from those (exactly as the prover derived
20 /// it from its materialization), the merged query is rebuilt, and
21 /// the AUTHORITATIVE full pass verifies the whole composition —
22 /// grovedb enforces the inner page's per-instance limit and
23 /// range completeness — with the proven outer documents required
24 /// to match the proven inner join values. Under a `refersTo:
25 /// permanentDocument` join property a missing referenced document
26 /// is an invalid proof (such a target cannot dangle); under a
27 /// `refersTo: deletableDocument` one it is a proven absence, left
28 /// out of the outer half, which grovedb's coverage of every derived
29 /// `$id` keeps a prover from faking. An extra outer document is
30 /// always an invalid proof; a proof covering only the inner half (an
31 /// old node serving the plain query) fails the full pass whenever
32 /// the inner page is non-empty.
33 ///
34 /// One proof means one root by construction; the caller combines
35 /// the returned root hash with the surrounding tenderdash
36 /// signature — see `rs-drive-proof-verifier` for the canonical
37 /// composition.
38 ///
39 /// # Parameters
40 ///
41 /// * `proof`: The merged proof, as `query_chained_documents_with_proof` produced it.
42 /// * `platform_version`: The platform version.
43 ///
44 /// # Returns
45 ///
46 /// * `Ok((RootHash, ChainedDocumentsResult))` with the proof's root hash, the proven inner
47 /// projections, the proven outer documents and the join values proven to have none.
48 /// * `Err(Error)` when the method version is unknown, the query is not a valid chained
49 /// query, or the proof is invalid: it fails verification, lacks a referenced document
50 /// that cannot be deleted, or carries an outer document no join value asked for.
51 pub fn verify_chained_documents_proof(
52 &self,
53 proof: &[u8],
54 platform_version: &PlatformVersion,
55 ) -> Result<(RootHash, ChainedDocumentsResult), Error> {
56 match platform_version
57 .drive
58 .methods
59 .verify
60 .chained_document
61 .verify_chained_documents_proof
62 {
63 0 => self.verify_chained_documents_proof_v0(proof, platform_version),
64 version => Err(Error::Drive(DriveError::UnknownVersionMismatch {
65 method: "DriveDocumentQuery::verify_chained_documents_proof".to_string(),
66 known_versions: vec![0],
67 received: version,
68 })),
69 }
70 }
71}
72
73#[cfg(test)]
74mod tests {
75 use super::*;
76 use crate::error::drive::DriveError;
77 use crate::query::DriveDocumentQuery;
78 use dpp::data_contract::accessors::v0::DataContractV0Getters;
79 use dpp::data_contracts::SystemDataContract;
80 use dpp::system_data_contracts::load_system_data_contract;
81
82 #[test]
83 fn test_verify_chained_documents_proof_unknown_version() {
84 let platform_version = dpp::version::PlatformVersion::latest();
85 let contract = load_system_data_contract(SystemDataContract::DPNS, platform_version)
86 .expect("expected to load DPNS contract");
87 let document_type = contract
88 .document_type_for_name("domain")
89 .expect("expected domain document type");
90
91 let mut platform_version = platform_version.clone();
92 platform_version
93 .drive
94 .methods
95 .verify
96 .chained_document
97 .verify_chained_documents_proof = 255;
98
99 let query = DriveDocumentQuery {
100 contract: &contract,
101 document_type,
102 internal_clauses: Default::default(),
103 offset: None,
104 limit: Some(1),
105 order_by: Default::default(),
106 start_at: None,
107 start_at_included: false,
108 block_time_ms: None,
109 resolved_time_ranges: vec![],
110 sub_queries: vec![],
111 }
112 .with_by_id_join("records", document_type);
113
114 let result = query.verify_chained_documents_proof(&[], &platform_version);
115 assert!(matches!(
116 result,
117 Err(Error::Drive(DriveError::UnknownVersionMismatch { method, .. }))
118 if method == "DriveDocumentQuery::verify_chained_documents_proof"
119 ));
120 }
121}