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    Context,
12    index::ordered::Index,
13    journal::contiguous::variable::Journal,
14    merkle::{Graftable, Location},
15    qmdb::{
16        Error,
17        any::{VariableValue, ordered::variable::Operation, value::VariableEncoding},
18        current::VariableConfig as Config,
19        operation::Key,
20    },
21    translator::Translator,
22};
23use commonware_codec::Read;
24use commonware_cryptography::Hasher;
25use commonware_parallel::Strategy;
26use commonware_runtime::Spawner;
27
28pub type Db<F, E, K, V, H, T, const N: usize, S> = super::db::Db<
29    F,
30    E,
31    Journal<E, Operation<F, K, V>>,
32    K,
33    VariableEncoding<V>,
34    Index<T, Location<F>>,
35    H,
36    N,
37    S,
38>;
39
40impl<
41    F: Graftable,
42    E: Context + Spawner,
43    K: Key,
44    V: VariableValue,
45    H: Hasher,
46    T: Translator,
47    const N: usize,
48    S: Strategy,
49> Db<F, E, K, V, H, T, N, S>
50where
51    Operation<F, K, V>: Read,
52{
53    /// Initializes a [Db] from the given `config`.
54    /// The configured [`Strategy`] is used to parallelize merkleization.
55    pub async fn init(
56        context: E,
57        config: Config<T, <Operation<F, K, V> as Read>::Cfg, S>,
58    ) -> Result<Self, Error<F>> {
59        crate::qmdb::current::init(context, config).await
60    }
61}
62
63pub mod partitioned {
64    //! A variant of [super] that uses a partitioned index for the snapshot.
65
66    use super::*;
67    use crate::index::partitioned::ordered::Index;
68
69    /// A partitioned variant of [super::Db].
70    ///
71    /// The const generic `P` specifies the number of prefix bytes used for partitioning:
72    /// - `P = 1`: 256 partitions
73    /// - `P = 2`: 65,536 partitions
74    /// - `P = 3`: ~16 million partitions
75    pub type Db<F, E, K, V, H, T, const P: usize, const N: usize, S> =
76        crate::qmdb::current::ordered::db::Db<
77            F,
78            E,
79            Journal<E, Operation<F, K, V>>,
80            K,
81            VariableEncoding<V>,
82            Index<T, Location<F>, P>,
83            H,
84            N,
85            S,
86        >;
87
88    impl<
89        F: Graftable,
90        E: Context + Spawner,
91        K: Key,
92        V: VariableValue,
93        H: Hasher,
94        T: Translator,
95        const P: usize,
96        const N: usize,
97        S: Strategy,
98    > Db<F, E, K, V, H, T, P, N, S>
99    where
100        Operation<F, K, V>: Read,
101    {
102        /// Initializes a [Db] from the given `config`.
103        pub async fn init(
104            context: E,
105            config: Config<T, <Operation<F, K, V> as Read>::Cfg, S, core::num::NonZeroUsize>,
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, sha256::Digest};
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}