Skip to main content

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}