Skip to main content

commonware_storage/qmdb/current/unordered/
db.rs

1//! Shared implementation for unordered Current QMDB variants.
2//!
3//! This module contains impl blocks that are generic over `ValueEncoding`, allowing them to be
4//! used by both fixed and variable unordered QMDB implementations.
5
6use crate::{
7    index::Unordered as UnorderedIndex,
8    journal::contiguous::{Contiguous, Mutable},
9    merkle::{self, hasher::Standard as StandardHasher, Location},
10    qmdb::{
11        any::{
12            operation::update::Unordered as UnorderedUpdate,
13            unordered::{Operation, Update},
14            ValueEncoding,
15        },
16        current::proof::OperationProof,
17        Error,
18    },
19    Context,
20};
21use commonware_codec::Codec;
22use commonware_cryptography::Hasher;
23use commonware_parallel::Strategy;
24use commonware_utils::Array;
25
26/// Proof information for verifying a key has a particular value in the database.
27pub type KeyValueProof<F, D, const N: usize> = OperationProof<F, D, N>;
28
29/// The generic Db type for unordered Current QMDB variants.
30///
31/// This type is generic over the index type `I`, allowing it to be used with both regular
32/// and partitioned indices.
33pub type Db<F, E, C, K, V, I, H, const N: usize, S> =
34    crate::qmdb::current::db::Db<F, E, C, I, H, Update<K, V>, N, S>;
35
36// Shared read-only functionality.
37impl<
38        F: merkle::Graftable,
39        E: Context,
40        C: Contiguous<Item = Operation<F, K, V>>,
41        K: Array,
42        V: ValueEncoding,
43        I: UnorderedIndex<Value = Location<F>>,
44        H: Hasher,
45        const N: usize,
46        S: Strategy,
47    > Db<F, E, C, K, V, I, H, N, S>
48where
49    Operation<F, K, V>: Codec,
50{
51    /// Get the value of `key` in the db, or None if it has no value.
52    pub async fn get(&self, key: &K) -> Result<Option<V::Value>, Error<F>> {
53        self.any.get(key).await
54    }
55
56    /// Return true if the proof authenticates that `key` currently has value `value` in the db with
57    /// the provided `root`.
58    pub fn verify_key_value_proof(
59        hasher: &StandardHasher<H>,
60        key: K,
61        value: V::Value,
62        proof: &KeyValueProof<F, H::Digest, N>,
63        root: &H::Digest,
64    ) -> bool {
65        let op = Operation::Update(UnorderedUpdate(key, value));
66
67        proof.verify(hasher, op, root)
68    }
69}
70
71impl<
72        F: merkle::Graftable,
73        E: Context,
74        C: Mutable<Item = Operation<F, K, V>>,
75        K: Array,
76        V: ValueEncoding,
77        I: UnorderedIndex<Value = Location<F>>,
78        H: Hasher,
79        const N: usize,
80        S: Strategy,
81    > Db<F, E, C, K, V, I, H, N, S>
82where
83    Operation<F, K, V>: Codec,
84{
85    /// Generate and return a proof of the current value of `key`, along with the other
86    /// [KeyValueProof] required to verify the proof. Returns KeyNotFound error if the key is not
87    /// currently assigned any value.
88    ///
89    /// # Errors
90    ///
91    /// Returns [Error::KeyNotFound] if the key is not currently assigned any value.
92    pub async fn key_value_proof(
93        &self,
94        hasher: &StandardHasher<H>,
95        key: K,
96    ) -> Result<KeyValueProof<F, H::Digest, N>, Error<F>> {
97        let op_loc = self.any.get_with_loc(&key).await?;
98        let Some((_, loc)) = op_loc else {
99            return Err(Error::<F>::KeyNotFound);
100        };
101        self.operation_proof(hasher, loc).await
102    }
103}