Skip to main content

commonware_storage/qmdb/current/ordered/
variable.rs

1//! An _ordered_ variant of a [crate::qmdb::current] authenticated database for variable-size values
2//!
3//! This variant maintains the lexicographic-next active key for each active key, enabling exclusion
4//! proofs (proving a key is currently inactive). Use [crate::qmdb::current::unordered::variable] if
5//! exclusion proofs are not needed.
6//!
7//! See [Db] for the main database type and [super::ExclusionProof] for proving key inactivity.
8
9pub use super::db::KeyValueProof;
10use crate::{
11    index::ordered::Index,
12    journal::contiguous::variable::Journal,
13    merkle::{Graftable, Location},
14    qmdb::{
15        any::{ordered::variable::Operation, value::VariableEncoding, VariableValue},
16        current::VariableConfig as Config,
17        operation::Key,
18        Error,
19    },
20    translator::Translator,
21    Context,
22};
23use commonware_codec::{Codec, Read};
24use commonware_cryptography::Hasher;
25use commonware_parallel::Strategy;
26
27pub type Db<F, E, K, V, H, T, const N: usize, S> = super::db::Db<
28    F,
29    E,
30    Journal<E, Operation<F, K, V>>,
31    K,
32    VariableEncoding<V>,
33    Index<T, Location<F>>,
34    H,
35    N,
36    S,
37>;
38
39impl<
40        F: Graftable,
41        E: Context,
42        K: Key,
43        V: VariableValue,
44        H: Hasher,
45        T: Translator,
46        const N: usize,
47        S: Strategy,
48    > Db<F, E, K, V, H, T, N, S>
49where
50    Operation<F, K, V>: Codec,
51{
52    /// Initializes a [Db] from the given `config`.
53    /// The configured [`Strategy`] is used to parallelize merkleization.
54    pub async fn init(
55        context: E,
56        config: Config<T, <Operation<F, K, V> as Read>::Cfg, S>,
57    ) -> Result<Self, Error<F>> {
58        crate::qmdb::current::init(context, config).await
59    }
60}
61
62pub mod partitioned {
63    //! A variant of [super] that uses a partitioned index for the snapshot.
64
65    use super::*;
66    use crate::index::partitioned::ordered::Index;
67
68    /// A partitioned variant of [super::Db].
69    ///
70    /// The const generic `P` specifies the number of prefix bytes used for partitioning:
71    /// - `P = 1`: 256 partitions
72    /// - `P = 2`: 65,536 partitions
73    /// - `P = 3`: ~16 million partitions
74    pub type Db<F, E, K, V, H, T, const P: usize, const N: usize, S> =
75        crate::qmdb::current::ordered::db::Db<
76            F,
77            E,
78            Journal<E, Operation<F, K, V>>,
79            K,
80            VariableEncoding<V>,
81            Index<T, Location<F>, P>,
82            H,
83            N,
84            S,
85        >;
86
87    impl<
88            F: Graftable,
89            E: Context,
90            K: Key,
91            V: VariableValue,
92            H: Hasher,
93            T: Translator,
94            const P: usize,
95            const N: usize,
96            S: Strategy,
97        > Db<F, E, K, V, H, T, P, N, S>
98    where
99        Operation<F, K, V>: Codec,
100    {
101        /// Initializes a [Db] from the given `config`.
102        /// The configured [`Strategy`] is used to parallelize merkleization.
103        pub async fn init(
104            context: E,
105            config: Config<T, <Operation<F, K, V> as Read>::Cfg, S>,
106        ) -> Result<Self, Error<F>> {
107            crate::qmdb::current::init(context, config).await
108        }
109    }
110}
111
112#[cfg(test)]
113mod test {
114    use crate::{
115        mmr,
116        qmdb::current::{ordered::tests as shared, tests::variable_config},
117        translator::OneCap,
118    };
119    use commonware_cryptography::{sha256::Digest, Sha256};
120    use commonware_macros::test_traced;
121    use commonware_runtime::deterministic;
122
123    /// A type alias for the concrete [Db] type used in these unit tests.
124    type CurrentTest = super::Db<
125        mmr::Family,
126        deterministic::Context,
127        Digest,
128        Digest,
129        Sha256,
130        OneCap,
131        32,
132        commonware_parallel::Sequential,
133    >;
134
135    #[allow(dead_code)]
136    fn _assert_stream_range_is_send(db: &CurrentTest, start: Digest) {
137        fn require_send<F: core::future::Future + Send>(_: F) {}
138        require_send(async move {
139            let stream = db.stream_range(start).await.unwrap();
140            futures::pin_mut!(stream);
141            let _ = futures::StreamExt::next(&mut stream).await;
142        });
143    }
144
145    /// Return a [Db] database initialized with a variable config.
146    async fn open_db(context: deterministic::Context, partition_prefix: String) -> CurrentTest {
147        let cfg = variable_config::<OneCap>(&partition_prefix, &context);
148        CurrentTest::init(context, cfg).await.unwrap()
149    }
150
151    #[test_traced("DEBUG")]
152    pub fn test_current_db_verify_proof_over_bits_in_uncommitted_chunk() {
153        shared::test_verify_proof_over_bits_in_uncommitted_chunk(open_db);
154    }
155
156    #[test_traced("DEBUG")]
157    pub fn test_current_db_range_proofs() {
158        shared::test_range_proofs(open_db);
159    }
160
161    #[test_traced("DEBUG")]
162    pub fn test_current_db_key_value_proof() {
163        shared::test_key_value_proof(open_db);
164    }
165
166    #[test_traced("WARN")]
167    pub fn test_current_db_proving_repeated_updates() {
168        shared::test_proving_repeated_updates(open_db);
169    }
170
171    #[test_traced("DEBUG")]
172    pub fn test_current_db_exclusion_proofs() {
173        shared::test_exclusion_proofs(open_db);
174    }
175}