Skip to main content

commonware_storage/qmdb/keyless/
fixed.rs

1//! A keyless authenticated database for fixed-size data.
2//!
3//! For variable-size values, use [super::variable].
4
5use crate::{
6    journal::{
7        authenticated,
8        contiguous::fixed::{self, Config as JournalConfig},
9    },
10    merkle::Family,
11    qmdb::{
12        any::value::{FixedEncoding, FixedValue},
13        keyless::operation::Operation as BaseOperation,
14        operation::Committable,
15        Error,
16    },
17};
18use commonware_cryptography::Hasher;
19use commonware_runtime::{Clock, Metrics, Storage};
20
21/// Keyless operation for fixed-size values.
22pub type Operation<V> = BaseOperation<FixedEncoding<V>>;
23
24/// A keyless authenticated database for fixed-size data.
25pub type Db<F, E, V, H> =
26    super::Keyless<F, E, FixedEncoding<V>, fixed::Journal<E, Operation<V>>, H>;
27
28type Journal<F, E, V, H> = authenticated::Journal<F, E, fixed::Journal<E, Operation<V>>, H>;
29
30/// Configuration for a fixed-size [keyless](super) authenticated db.
31pub type Config = super::Config<JournalConfig>;
32
33impl<F: Family, E: Storage + Clock + Metrics, V: FixedValue, H: Hasher> Db<F, E, V, H> {
34    /// Returns a [Db] initialized from `cfg`. Any uncommitted operations will be
35    /// discarded and the state of the db will be as of the last committed operation.
36    pub async fn init(context: E, cfg: Config) -> Result<Self, Error<F>> {
37        let journal: Journal<F, E, V, H> =
38            Journal::new(context, cfg.merkle, cfg.log, Operation::<V>::is_commit).await?;
39        Self::init_from_journal(journal).await
40    }
41}
42
43#[cfg(test)]
44mod test {
45    use super::*;
46    use crate::{
47        merkle::{mmb, mmr},
48        qmdb::keyless::tests,
49    };
50    use commonware_cryptography::Sha256;
51    use commonware_macros::test_traced;
52    use commonware_runtime::{
53        buffer::paged::CacheRef, deterministic, BufferPooler, Metrics, Runner as _,
54    };
55    use commonware_utils::{NZUsize, NZU16, NZU64};
56    use std::num::{NonZeroU16, NonZeroUsize};
57
58    const PAGE_SIZE: NonZeroU16 = NZU16!(101);
59    const PAGE_CACHE_SIZE: NonZeroUsize = NZUsize!(11);
60
61    fn db_config(suffix: &str, pooler: &impl BufferPooler) -> Config {
62        let page_cache = CacheRef::from_pooler(pooler, PAGE_SIZE, PAGE_CACHE_SIZE);
63        Config {
64            merkle: crate::merkle::journaled::Config {
65                journal_partition: format!("fixed-journal-{suffix}"),
66                metadata_partition: format!("fixed-metadata-{suffix}"),
67                items_per_blob: NZU64!(11),
68                write_buffer: NZUsize!(1024),
69                thread_pool: None,
70                page_cache: page_cache.clone(),
71            },
72            log: JournalConfig {
73                partition: format!("fixed-log-journal-{suffix}"),
74                items_per_blob: NZU64!(7),
75                page_cache,
76                write_buffer: NZUsize!(1024),
77            },
78        }
79    }
80
81    type TestDb<F> = Db<F, deterministic::Context, commonware_utils::sequence::U64, Sha256>;
82
83    async fn open_db<F: crate::merkle::Family>(context: deterministic::Context) -> TestDb<F> {
84        let cfg = db_config("partition", &context);
85        TestDb::init(context, cfg).await.unwrap()
86    }
87
88    fn reopen<F: crate::merkle::Family>() -> tests::Reopen<TestDb<F>> {
89        Box::new(|ctx| Box::pin(open_db(ctx)))
90    }
91
92    #[test_traced("INFO")]
93    fn test_keyless_fixed_empty() {
94        deterministic::Runner::default().start(|ctx| async move {
95            let db = open_db::<mmr::Family>(ctx.with_label("db1")).await;
96            tests::test_keyless_db_empty(ctx, db, reopen::<mmr::Family>()).await;
97        });
98    }
99
100    #[test_traced("WARN")]
101    fn test_keyless_fixed_build_basic() {
102        deterministic::Runner::default().start(|ctx| async move {
103            let db = open_db::<mmr::Family>(ctx.with_label("db1")).await;
104            tests::test_keyless_db_build_basic(ctx, db, reopen::<mmr::Family>()).await;
105        });
106    }
107
108    #[test_traced("WARN")]
109    fn test_keyless_fixed_recovery() {
110        deterministic::Runner::default().start(|ctx| async move {
111            let db = open_db::<mmr::Family>(ctx.with_label("db1")).await;
112            tests::test_keyless_db_recovery(ctx, db, reopen::<mmr::Family>()).await;
113        });
114    }
115
116    #[test_traced("WARN")]
117    fn test_keyless_fixed_non_empty_recovery() {
118        deterministic::Runner::default().start(|ctx| async move {
119            let db = open_db::<mmr::Family>(ctx.with_label("db1")).await;
120            tests::test_keyless_db_non_empty_recovery(ctx, db, reopen::<mmr::Family>()).await;
121        });
122    }
123
124    #[test_traced("INFO")]
125    fn test_keyless_fixed_proof() {
126        deterministic::Runner::default().start(|ctx| async move {
127            let db = open_db::<mmr::Family>(ctx.clone()).await;
128            tests::test_keyless_db_proof(db).await;
129        });
130    }
131
132    #[test_traced("INFO")]
133    fn test_keyless_fixed_proof_comprehensive() {
134        deterministic::Runner::default().start(|ctx| async move {
135            let db = open_db::<mmr::Family>(ctx.clone()).await;
136            tests::test_keyless_db_proof_comprehensive(db).await;
137        });
138    }
139
140    #[test_traced("INFO")]
141    fn test_keyless_fixed_proof_with_pruning() {
142        deterministic::Runner::default().start(|ctx| async move {
143            let db = open_db::<mmr::Family>(ctx.with_label("db1")).await;
144            tests::test_keyless_db_proof_with_pruning(ctx, db, reopen::<mmr::Family>()).await;
145        });
146    }
147
148    #[test_traced("WARN")]
149    fn test_keyless_fixed_empty_db_recovery() {
150        deterministic::Runner::default().start(|ctx| async move {
151            let db = open_db::<mmr::Family>(ctx.with_label("db1")).await;
152            tests::test_keyless_db_empty_db_recovery(ctx, db, reopen::<mmr::Family>()).await;
153        });
154    }
155
156    #[test_traced("WARN")]
157    fn test_keyless_fixed_replay_with_trailing_appends() {
158        deterministic::Runner::default().start(|ctx| async move {
159            let db = open_db::<mmr::Family>(ctx.with_label("db1")).await;
160            tests::test_keyless_db_replay_with_trailing_appends(ctx, db, reopen::<mmr::Family>())
161                .await;
162        });
163    }
164
165    #[test_traced("INFO")]
166    fn test_keyless_fixed_get_out_of_bounds() {
167        deterministic::Runner::default().start(|ctx| async move {
168            let db = open_db::<mmr::Family>(ctx.clone()).await;
169            tests::test_keyless_db_get_out_of_bounds(db).await;
170        });
171    }
172
173    #[test_traced("INFO")]
174    fn test_keyless_fixed_metadata() {
175        deterministic::Runner::default().start(|ctx| async move {
176            let db = open_db::<mmr::Family>(ctx.with_label("db")).await;
177            tests::test_keyless_db_metadata(db).await;
178        });
179    }
180
181    #[test_traced("INFO")]
182    fn test_keyless_fixed_pruning() {
183        deterministic::Runner::default().start(|ctx| async move {
184            let db = open_db::<mmr::Family>(ctx.with_label("db")).await;
185            tests::test_keyless_db_pruning(db).await;
186        });
187    }
188
189    #[test_traced("INFO")]
190    fn test_keyless_fixed_batch_get() {
191        deterministic::Runner::default().start(|ctx| async move {
192            let db = open_db::<mmr::Family>(ctx.with_label("db")).await;
193            tests::test_keyless_batch_get(db).await;
194        });
195    }
196
197    #[test_traced("INFO")]
198    fn test_keyless_fixed_batch_stacked_get() {
199        deterministic::Runner::default().start(|ctx| async move {
200            let db = open_db::<mmr::Family>(ctx.with_label("db")).await;
201            tests::test_keyless_batch_stacked_get(db).await;
202        });
203    }
204
205    #[test_traced("INFO")]
206    fn test_keyless_fixed_batch_speculative_root() {
207        deterministic::Runner::default().start(|ctx| async move {
208            let db = open_db::<mmr::Family>(ctx.with_label("db")).await;
209            tests::test_keyless_batch_speculative_root(db).await;
210        });
211    }
212
213    #[test_traced("INFO")]
214    fn test_keyless_fixed_merkleized_batch_get() {
215        deterministic::Runner::default().start(|ctx| async move {
216            let db = open_db::<mmr::Family>(ctx.with_label("db")).await;
217            tests::test_keyless_merkleized_batch_get(db).await;
218        });
219    }
220
221    #[test_traced("INFO")]
222    fn test_keyless_fixed_batch_chained() {
223        deterministic::Runner::default().start(|ctx| async move {
224            let db = open_db::<mmr::Family>(ctx.with_label("db")).await;
225            tests::test_keyless_batch_chained(db).await;
226        });
227    }
228
229    #[test_traced("INFO")]
230    fn test_keyless_fixed_batch_chained_apply_sequential() {
231        deterministic::Runner::default().start(|ctx| async move {
232            let db = open_db::<mmr::Family>(ctx.with_label("db")).await;
233            tests::test_keyless_batch_chained_apply_sequential(db).await;
234        });
235    }
236
237    #[test_traced("INFO")]
238    fn test_keyless_fixed_batch_many_sequential() {
239        deterministic::Runner::default().start(|ctx| async move {
240            let db = open_db::<mmr::Family>(ctx.with_label("db")).await;
241            tests::test_keyless_batch_many_sequential(db).await;
242        });
243    }
244
245    #[test_traced("INFO")]
246    fn test_keyless_fixed_batch_empty() {
247        deterministic::Runner::default().start(|ctx| async move {
248            let db = open_db::<mmr::Family>(ctx.with_label("db")).await;
249            tests::test_keyless_batch_empty(db).await;
250        });
251    }
252
253    #[test_traced("INFO")]
254    fn test_keyless_fixed_batch_chained_merkleized_get() {
255        deterministic::Runner::default().start(|ctx| async move {
256            let db = open_db::<mmr::Family>(ctx.with_label("db")).await;
257            tests::test_keyless_batch_chained_merkleized_get(db).await;
258        });
259    }
260
261    #[test_traced("INFO")]
262    fn test_keyless_fixed_batch_large() {
263        deterministic::Runner::default().start(|ctx| async move {
264            let db = open_db::<mmr::Family>(ctx.with_label("db")).await;
265            tests::test_keyless_batch_large(db).await;
266        });
267    }
268
269    #[test_traced]
270    fn test_keyless_fixed_stale_batch() {
271        deterministic::Runner::default().start(|ctx| async move {
272            let db = open_db::<mmr::Family>(ctx.with_label("db")).await;
273            tests::test_keyless_stale_batch(db).await;
274        });
275    }
276
277    #[test_traced]
278    fn test_keyless_fixed_stale_batch_chained() {
279        deterministic::Runner::default().start(|ctx| async move {
280            let db = open_db::<mmr::Family>(ctx.with_label("db")).await;
281            tests::test_keyless_stale_batch_chained(db).await;
282        });
283    }
284
285    #[test_traced]
286    fn test_keyless_fixed_sequential_commit_parent_then_child() {
287        deterministic::Runner::default().start(|ctx| async move {
288            let db = open_db::<mmr::Family>(ctx.with_label("db")).await;
289            tests::test_keyless_sequential_commit_parent_then_child(db).await;
290        });
291    }
292
293    #[test_traced]
294    fn test_keyless_fixed_stale_batch_child_before_parent() {
295        deterministic::Runner::default().start(|ctx| async move {
296            let db = open_db::<mmr::Family>(ctx.with_label("db")).await;
297            tests::test_keyless_stale_batch_child_before_parent(db).await;
298        });
299    }
300
301    #[test_traced]
302    fn test_keyless_fixed_to_batch() {
303        deterministic::Runner::default().start(|ctx| async move {
304            let db = open_db::<mmr::Family>(ctx.with_label("db")).await;
305            tests::test_keyless_to_batch(db).await;
306        });
307    }
308
309    #[test_traced]
310    fn test_keyless_fixed_child_root_matches_pending_and_committed() {
311        deterministic::Runner::default().start(|ctx| async move {
312            let db = open_db::<mmr::Family>(ctx.with_label("db")).await;
313            tests::test_keyless_child_root_matches_pending_and_committed(db).await;
314        });
315    }
316
317    #[test_traced("INFO")]
318    fn test_keyless_fixed_rewind_recovery() {
319        deterministic::Runner::default().start(|ctx| async move {
320            let db = open_db::<mmr::Family>(ctx.with_label("db")).await;
321            tests::test_keyless_db_rewind_recovery(ctx, db, reopen::<mmr::Family>()).await;
322        });
323    }
324
325    #[test_traced("INFO")]
326    fn test_keyless_fixed_rewind_pruned_target_errors() {
327        deterministic::Runner::default().start(|ctx| async move {
328            let db = open_db::<mmr::Family>(ctx.with_label("db")).await;
329            tests::test_keyless_db_rewind_pruned_target_errors(db).await;
330        });
331    }
332
333    // mmb::Family variants
334
335    #[test_traced("INFO")]
336    fn test_keyless_fixed_empty_mmb() {
337        deterministic::Runner::default().start(|ctx| async move {
338            let db = open_db::<mmb::Family>(ctx.with_label("db1")).await;
339            tests::test_keyless_db_empty(ctx, db, reopen::<mmb::Family>()).await;
340        });
341    }
342
343    #[test_traced("WARN")]
344    fn test_keyless_fixed_build_basic_mmb() {
345        deterministic::Runner::default().start(|ctx| async move {
346            let db = open_db::<mmb::Family>(ctx.with_label("db1")).await;
347            tests::test_keyless_db_build_basic(ctx, db, reopen::<mmb::Family>()).await;
348        });
349    }
350
351    #[test_traced("WARN")]
352    fn test_keyless_fixed_recovery_mmb() {
353        deterministic::Runner::default().start(|ctx| async move {
354            let db = open_db::<mmb::Family>(ctx.with_label("db1")).await;
355            tests::test_keyless_db_recovery(ctx, db, reopen::<mmb::Family>()).await;
356        });
357    }
358
359    #[test_traced("WARN")]
360    fn test_keyless_fixed_non_empty_recovery_mmb() {
361        deterministic::Runner::default().start(|ctx| async move {
362            let db = open_db::<mmb::Family>(ctx.with_label("db1")).await;
363            tests::test_keyless_db_non_empty_recovery(ctx, db, reopen::<mmb::Family>()).await;
364        });
365    }
366
367    #[test_traced("INFO")]
368    fn test_keyless_fixed_proof_mmb() {
369        deterministic::Runner::default().start(|ctx| async move {
370            let db = open_db::<mmb::Family>(ctx.clone()).await;
371            tests::test_keyless_db_proof(db).await;
372        });
373    }
374
375    #[test_traced("INFO")]
376    fn test_keyless_fixed_proof_comprehensive_mmb() {
377        deterministic::Runner::default().start(|ctx| async move {
378            let db = open_db::<mmb::Family>(ctx.clone()).await;
379            tests::test_keyless_db_proof_comprehensive(db).await;
380        });
381    }
382
383    #[test_traced("INFO")]
384    fn test_keyless_fixed_proof_with_pruning_mmb() {
385        deterministic::Runner::default().start(|ctx| async move {
386            let db = open_db::<mmb::Family>(ctx.with_label("db1")).await;
387            tests::test_keyless_db_proof_with_pruning(ctx, db, reopen::<mmb::Family>()).await;
388        });
389    }
390
391    #[test_traced("WARN")]
392    fn test_keyless_fixed_empty_db_recovery_mmb() {
393        deterministic::Runner::default().start(|ctx| async move {
394            let db = open_db::<mmb::Family>(ctx.with_label("db1")).await;
395            tests::test_keyless_db_empty_db_recovery(ctx, db, reopen::<mmb::Family>()).await;
396        });
397    }
398
399    #[test_traced("WARN")]
400    fn test_keyless_fixed_replay_with_trailing_appends_mmb() {
401        deterministic::Runner::default().start(|ctx| async move {
402            let db = open_db::<mmb::Family>(ctx.with_label("db1")).await;
403            tests::test_keyless_db_replay_with_trailing_appends(ctx, db, reopen::<mmb::Family>())
404                .await;
405        });
406    }
407
408    #[test_traced("INFO")]
409    fn test_keyless_fixed_get_out_of_bounds_mmb() {
410        deterministic::Runner::default().start(|ctx| async move {
411            let db = open_db::<mmb::Family>(ctx.clone()).await;
412            tests::test_keyless_db_get_out_of_bounds(db).await;
413        });
414    }
415
416    #[test_traced("INFO")]
417    fn test_keyless_fixed_metadata_mmb() {
418        deterministic::Runner::default().start(|ctx| async move {
419            let db = open_db::<mmb::Family>(ctx.with_label("db")).await;
420            tests::test_keyless_db_metadata(db).await;
421        });
422    }
423
424    #[test_traced("INFO")]
425    fn test_keyless_fixed_pruning_mmb() {
426        deterministic::Runner::default().start(|ctx| async move {
427            let db = open_db::<mmb::Family>(ctx.with_label("db")).await;
428            tests::test_keyless_db_pruning(db).await;
429        });
430    }
431
432    #[test_traced("INFO")]
433    fn test_keyless_fixed_batch_get_mmb() {
434        deterministic::Runner::default().start(|ctx| async move {
435            let db = open_db::<mmb::Family>(ctx.with_label("db")).await;
436            tests::test_keyless_batch_get(db).await;
437        });
438    }
439
440    #[test_traced("INFO")]
441    fn test_keyless_fixed_batch_stacked_get_mmb() {
442        deterministic::Runner::default().start(|ctx| async move {
443            let db = open_db::<mmb::Family>(ctx.with_label("db")).await;
444            tests::test_keyless_batch_stacked_get(db).await;
445        });
446    }
447
448    #[test_traced("INFO")]
449    fn test_keyless_fixed_batch_speculative_root_mmb() {
450        deterministic::Runner::default().start(|ctx| async move {
451            let db = open_db::<mmb::Family>(ctx.with_label("db")).await;
452            tests::test_keyless_batch_speculative_root(db).await;
453        });
454    }
455
456    #[test_traced("INFO")]
457    fn test_keyless_fixed_merkleized_batch_get_mmb() {
458        deterministic::Runner::default().start(|ctx| async move {
459            let db = open_db::<mmb::Family>(ctx.with_label("db")).await;
460            tests::test_keyless_merkleized_batch_get(db).await;
461        });
462    }
463
464    #[test_traced("INFO")]
465    fn test_keyless_fixed_batch_chained_mmb() {
466        deterministic::Runner::default().start(|ctx| async move {
467            let db = open_db::<mmb::Family>(ctx.with_label("db")).await;
468            tests::test_keyless_batch_chained(db).await;
469        });
470    }
471
472    #[test_traced("INFO")]
473    fn test_keyless_fixed_batch_chained_apply_sequential_mmb() {
474        deterministic::Runner::default().start(|ctx| async move {
475            let db = open_db::<mmb::Family>(ctx.with_label("db")).await;
476            tests::test_keyless_batch_chained_apply_sequential(db).await;
477        });
478    }
479
480    #[test_traced("INFO")]
481    fn test_keyless_fixed_batch_many_sequential_mmb() {
482        deterministic::Runner::default().start(|ctx| async move {
483            let db = open_db::<mmb::Family>(ctx.with_label("db")).await;
484            tests::test_keyless_batch_many_sequential(db).await;
485        });
486    }
487
488    #[test_traced("INFO")]
489    fn test_keyless_fixed_batch_empty_mmb() {
490        deterministic::Runner::default().start(|ctx| async move {
491            let db = open_db::<mmb::Family>(ctx.with_label("db")).await;
492            tests::test_keyless_batch_empty(db).await;
493        });
494    }
495
496    #[test_traced("INFO")]
497    fn test_keyless_fixed_batch_chained_merkleized_get_mmb() {
498        deterministic::Runner::default().start(|ctx| async move {
499            let db = open_db::<mmb::Family>(ctx.with_label("db")).await;
500            tests::test_keyless_batch_chained_merkleized_get(db).await;
501        });
502    }
503
504    #[test_traced("INFO")]
505    fn test_keyless_fixed_batch_large_mmb() {
506        deterministic::Runner::default().start(|ctx| async move {
507            let db = open_db::<mmb::Family>(ctx.with_label("db")).await;
508            tests::test_keyless_batch_large(db).await;
509        });
510    }
511
512    #[test_traced]
513    fn test_keyless_fixed_stale_batch_mmb() {
514        deterministic::Runner::default().start(|ctx| async move {
515            let db = open_db::<mmb::Family>(ctx.with_label("db")).await;
516            tests::test_keyless_stale_batch(db).await;
517        });
518    }
519
520    #[test_traced]
521    fn test_keyless_fixed_stale_batch_chained_mmb() {
522        deterministic::Runner::default().start(|ctx| async move {
523            let db = open_db::<mmb::Family>(ctx.with_label("db")).await;
524            tests::test_keyless_stale_batch_chained(db).await;
525        });
526    }
527
528    #[test_traced]
529    fn test_keyless_fixed_sequential_commit_parent_then_child_mmb() {
530        deterministic::Runner::default().start(|ctx| async move {
531            let db = open_db::<mmb::Family>(ctx.with_label("db")).await;
532            tests::test_keyless_sequential_commit_parent_then_child(db).await;
533        });
534    }
535
536    #[test_traced]
537    fn test_keyless_fixed_stale_batch_child_before_parent_mmb() {
538        deterministic::Runner::default().start(|ctx| async move {
539            let db = open_db::<mmb::Family>(ctx.with_label("db")).await;
540            tests::test_keyless_stale_batch_child_before_parent(db).await;
541        });
542    }
543
544    #[test_traced]
545    fn test_keyless_fixed_to_batch_mmb() {
546        deterministic::Runner::default().start(|ctx| async move {
547            let db = open_db::<mmb::Family>(ctx.with_label("db")).await;
548            tests::test_keyless_to_batch(db).await;
549        });
550    }
551
552    #[test_traced]
553    fn test_keyless_fixed_child_root_matches_pending_and_committed_mmb() {
554        deterministic::Runner::default().start(|ctx| async move {
555            let db = open_db::<mmb::Family>(ctx.with_label("db")).await;
556            tests::test_keyless_child_root_matches_pending_and_committed(db).await;
557        });
558    }
559
560    #[test_traced("INFO")]
561    fn test_keyless_fixed_rewind_recovery_mmb() {
562        deterministic::Runner::default().start(|ctx| async move {
563            let db = open_db::<mmb::Family>(ctx.with_label("db")).await;
564            tests::test_keyless_db_rewind_recovery(ctx, db, reopen::<mmb::Family>()).await;
565        });
566    }
567
568    #[test_traced("INFO")]
569    fn test_keyless_fixed_rewind_pruned_target_errors_mmb() {
570        deterministic::Runner::default().start(|ctx| async move {
571            let db = open_db::<mmb::Family>(ctx.with_label("db")).await;
572            tests::test_keyless_db_rewind_pruned_target_errors(db).await;
573        });
574    }
575}