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    kv,
10    mmr::Location,
11    qmdb::{
12        any::{
13            operation::update::Unordered as UnorderedUpdate,
14            unordered::{Operation, Update},
15            ValueEncoding,
16        },
17        current::proof::OperationProof,
18        Error,
19    },
20};
21use commonware_codec::Codec;
22use commonware_cryptography::Hasher;
23use commonware_runtime::{Clock, Metrics, Storage};
24use commonware_utils::Array;
25
26/// Proof information for verifying a key has a particular value in the database.
27pub type KeyValueProof<D, const N: usize> = OperationProof<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<E, C, K, V, I, H, const N: usize> =
34    crate::qmdb::current::db::Db<E, C, I, H, Update<K, V>, N>;
35
36// Shared read-only functionality.
37impl<
38        E: Storage + Clock + Metrics,
39        C: Contiguous<Item = Operation<K, V>>,
40        K: Array,
41        V: ValueEncoding,
42        I: UnorderedIndex<Value = Location>,
43        H: Hasher,
44        const N: usize,
45    > Db<E, C, K, V, I, H, N>
46where
47    Operation<K, V>: Codec,
48    V::Value: Send + Sync,
49{
50    /// Get the value of `key` in the db, or None if it has no value.
51    pub async fn get(&self, key: &K) -> Result<Option<V::Value>, Error> {
52        self.any.get(key).await
53    }
54
55    /// Return true if the proof authenticates that `key` currently has value `value` in the db with
56    /// the provided `root`.
57    pub fn verify_key_value_proof(
58        hasher: &mut H,
59        key: K,
60        value: V::Value,
61        proof: &KeyValueProof<H::Digest, N>,
62        root: &H::Digest,
63    ) -> bool {
64        let op = Operation::Update(UnorderedUpdate(key, value));
65
66        proof.verify(hasher, op, root)
67    }
68}
69
70impl<
71        E: Storage + Clock + Metrics,
72        C: Mutable<Item = Operation<K, V>>,
73        K: Array,
74        V: ValueEncoding,
75        I: UnorderedIndex<Value = Location>,
76        H: Hasher,
77        const N: usize,
78    > Db<E, C, K, V, I, H, N>
79where
80    Operation<K, V>: Codec,
81    V::Value: Send + Sync,
82{
83    /// Generate and return a proof of the current value of `key`, along with the other
84    /// [KeyValueProof] required to verify the proof. Returns KeyNotFound error if the key is not
85    /// currently assigned any value.
86    ///
87    /// # Errors
88    ///
89    /// Returns [Error::KeyNotFound] if the key is not currently assigned any value.
90    pub async fn key_value_proof(
91        &self,
92        hasher: &mut H,
93        key: K,
94    ) -> Result<KeyValueProof<H::Digest, N>, Error> {
95        let op_loc = self.any.get_with_loc(&key).await?;
96        let Some((_, loc)) = op_loc else {
97            return Err(Error::KeyNotFound);
98        };
99        self.operation_proof(hasher, loc).await
100    }
101}
102
103// Store implementation
104impl<
105        E: Storage + Clock + Metrics,
106        C: Contiguous<Item = Operation<K, V>>,
107        K: Array,
108        V: ValueEncoding,
109        I: UnorderedIndex<Value = Location>,
110        H: Hasher,
111        const N: usize,
112    > kv::Gettable for Db<E, C, K, V, I, H, N>
113where
114    Operation<K, V>: Codec,
115    V::Value: Send + Sync,
116{
117    type Key = K;
118    type Value = V::Value;
119    type Error = Error;
120
121    async fn get(&self, key: &Self::Key) -> Result<Option<Self::Value>, Self::Error> {
122        self.get(key).await
123    }
124}