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::Index,
8    journal::contiguous::{Contiguous, MutableContiguous},
9    kv::{self, Batchable},
10    mmr::Location,
11    qmdb::{
12        any::{
13            operation::update::Unordered as UnorderedUpdate,
14            unordered::{Operation, Update},
15            ValueEncoding,
16        },
17        current::{
18            db::{Merkleized, State, Unmerkleized},
19            proof::OperationProof,
20        },
21        store, DurabilityState, Durable, Error, NonDurable,
22    },
23    translator::Translator,
24};
25use commonware_codec::Codec;
26use commonware_cryptography::{DigestOf, Hasher};
27use commonware_runtime::{Clock, Metrics, Storage};
28use commonware_utils::Array;
29
30/// Proof information for verifying a key has a particular value in the database.
31pub type KeyValueProof<D, const N: usize> = OperationProof<D, N>;
32
33/// The generic Db type for unordered Current QMDB variants.
34pub type Db<E, C, K, V, H, T, const N: usize, S = Merkleized<DigestOf<H>>, D = Durable> =
35    super::super::db::Db<E, C, Index<T, Location>, H, Update<K, V>, N, S, D>;
36
37// Functionality shared across all DB states, such as most non-mutating operations.
38impl<
39        E: Storage + Clock + Metrics,
40        C: Contiguous<Item = Operation<K, V>>,
41        K: Array,
42        V: ValueEncoding,
43        H: Hasher,
44        T: Translator,
45        const N: usize,
46        S: State<DigestOf<H>>,
47        D: DurabilityState,
48    > Db<E, C, K, V, H, T, N, S, D>
49where
50    Operation<K, V>: Codec,
51    V::Value: Send + Sync,
52{
53    /// Get the value of `key` in the db, or None if it has no value.
54    pub async fn get(&self, key: &K) -> Result<Option<V::Value>, Error> {
55        self.any.get(key).await
56    }
57
58    /// Return true if the proof authenticates that `key` currently has value `value` in the db with
59    /// the provided `root`.
60    pub fn verify_key_value_proof(
61        hasher: &mut H,
62        key: K,
63        value: V::Value,
64        proof: &KeyValueProof<H::Digest, N>,
65        root: &H::Digest,
66    ) -> bool {
67        let op = Operation::Update(UnorderedUpdate(key, value));
68
69        proof.verify(hasher, Self::grafting_height(), op, root)
70    }
71}
72
73// Functionality for any Merkleized state (both Durable and NonDurable).
74impl<
75        E: Storage + Clock + Metrics,
76        C: MutableContiguous<Item = Operation<K, V>>,
77        K: Array,
78        V: ValueEncoding,
79        H: Hasher,
80        T: Translator,
81        const N: usize,
82        D: store::State,
83    > Db<E, C, K, V, H, T, N, Merkleized<DigestOf<H>>, D>
84where
85    Operation<K, V>: Codec,
86    V::Value: Send + Sync,
87{
88    /// Generate and return a proof of the current value of `key`, along with the other
89    /// [KeyValueProof] required to verify the proof. Returns KeyNotFound error if the key is not
90    /// currently assigned any value.
91    ///
92    /// # Errors
93    ///
94    /// Returns [Error::KeyNotFound] if the key is not currently assigned any value.
95    pub async fn key_value_proof(
96        &self,
97        hasher: &mut H,
98        key: K,
99    ) -> Result<KeyValueProof<H::Digest, N>, Error> {
100        let op_loc = self.any.get_with_loc(&key).await?;
101        let Some((_, loc)) = op_loc else {
102            return Err(Error::KeyNotFound);
103        };
104        let height = Self::grafting_height();
105        let mmr = &self.any.log.mmr;
106
107        OperationProof::<H::Digest, N>::new(hasher, &self.status, height, mmr, loc).await
108    }
109}
110
111// Functionality for the Mutable state.
112impl<
113        E: Storage + Clock + Metrics,
114        C: MutableContiguous<Item = Operation<K, V>>,
115        K: Array,
116        V: ValueEncoding,
117        H: Hasher,
118        T: Translator,
119        const N: usize,
120    > Db<E, C, K, V, H, T, N, Unmerkleized, NonDurable>
121where
122    Operation<K, V>: Codec,
123    V::Value: Send + Sync,
124{
125    /// Updates `key` to have value `value`. The operation is reflected in the snapshot, but will be
126    /// subject to rollback until the next successful `commit`.
127    pub async fn update(&mut self, key: K, value: V::Value) -> Result<(), Error> {
128        if let Some(old_loc) = self.any.update_key(key, value).await? {
129            self.status.set_bit(*old_loc, false);
130        }
131        self.status.push(true);
132
133        Ok(())
134    }
135
136    /// Creates a new key-value pair in the db. The operation is reflected in the snapshot, but will
137    /// be subject to rollback until the next successful `commit`. Returns true if the key was
138    /// created, false if it already existed.
139    pub async fn create(&mut self, key: K, value: V::Value) -> Result<bool, Error> {
140        if !self.any.create(key, value).await? {
141            return Ok(false);
142        }
143        self.status.push(true);
144
145        Ok(true)
146    }
147
148    /// Delete `key` and its value from the db. Deleting a key that already has no value is a no-op.
149    /// The operation is reflected in the snapshot, but will be subject to rollback until the next
150    /// successful `commit`. Returns true if the key was deleted, false if it was already inactive.
151    pub async fn delete(&mut self, key: K) -> Result<bool, Error> {
152        let Some(loc) = self.any.delete_key(key).await? else {
153            return Ok(false);
154        };
155
156        self.status.push(false);
157        self.status.set_bit(*loc, false);
158
159        Ok(true)
160    }
161}
162
163// Store implementation for all states
164impl<
165        E: Storage + Clock + Metrics,
166        C: Contiguous<Item = Operation<K, V>>,
167        K: Array,
168        V: ValueEncoding,
169        H: Hasher,
170        T: Translator,
171        const N: usize,
172        S: State<DigestOf<H>>,
173        D: DurabilityState,
174    > kv::Gettable for Db<E, C, K, V, H, T, N, S, D>
175where
176    Operation<K, V>: Codec,
177    V::Value: Send + Sync,
178{
179    type Key = K;
180    type Value = V::Value;
181    type Error = Error;
182
183    async fn get(&self, key: &Self::Key) -> Result<Option<Self::Value>, Self::Error> {
184        self.get(key).await
185    }
186}
187
188// StoreMut for (Unmerkleized, NonDurable) (aka mutable) state
189impl<
190        E: Storage + Clock + Metrics,
191        C: MutableContiguous<Item = Operation<K, V>>,
192        K: Array,
193        V: ValueEncoding,
194        H: Hasher,
195        T: Translator,
196        const N: usize,
197    > kv::Updatable for Db<E, C, K, V, H, T, N, Unmerkleized, NonDurable>
198where
199    Operation<K, V>: Codec,
200    V::Value: Send + Sync,
201{
202    async fn update(&mut self, key: Self::Key, value: Self::Value) -> Result<(), Self::Error> {
203        self.update(key, value).await
204    }
205}
206
207// StoreDeletable for (Unmerkleized, NonDurable) (aka mutable) state
208impl<
209        E: Storage + Clock + Metrics,
210        C: MutableContiguous<Item = Operation<K, V>>,
211        K: Array,
212        V: ValueEncoding,
213        H: Hasher,
214        T: Translator,
215        const N: usize,
216    > kv::Deletable for Db<E, C, K, V, H, T, N, Unmerkleized, NonDurable>
217where
218    Operation<K, V>: Codec,
219    V::Value: Send + Sync,
220{
221    async fn delete(&mut self, key: Self::Key) -> Result<bool, Self::Error> {
222        self.delete(key).await
223    }
224}
225
226// Batchable for (Unmerkleized, NonDurable) (aka mutable) state
227impl<E, C, K, V, T, H, const N: usize> Batchable
228    for Db<E, C, K, V, H, T, N, Unmerkleized, NonDurable>
229where
230    E: Storage + Clock + Metrics,
231    C: MutableContiguous<Item = Operation<K, V>>,
232    K: Array,
233    V: ValueEncoding,
234    T: Translator,
235    H: Hasher,
236    Operation<K, V>: Codec,
237    V::Value: Send + Sync,
238{
239    async fn write_batch<'a, Iter>(&'a mut self, iter: Iter) -> Result<(), Error>
240    where
241        Iter: Iterator<Item = (K, Option<V::Value>)> + Send + 'a,
242    {
243        let status = &mut self.status;
244        self.any
245            .write_batch_with_callback(iter, move |append: bool, loc: Option<Location>| {
246                status.push(append);
247                if let Some(loc) = loc {
248                    status.set_bit(*loc, false);
249                }
250            })
251            .await
252    }
253}