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, ROOT_BAGGING,
16    },
17};
18use commonware_cryptography::Hasher;
19use commonware_parallel::Strategy;
20use commonware_runtime::{Clock, Metrics, Storage};
21
22/// Keyless operation for fixed-size values.
23pub type Operation<F, V> = BaseOperation<F, FixedEncoding<V>>;
24
25/// A keyless authenticated database for fixed-size data.
26pub type Db<F, E, V, H, S> =
27    super::Keyless<F, E, FixedEncoding<V>, fixed::Journal<E, Operation<F, V>>, H, S>;
28
29/// A compact keyless authenticated db for fixed-size data.
30pub type CompactDb<F, E, V, H, S> = super::CompactDb<F, E, FixedEncoding<V>, H, (), S>;
31
32type Journal<F, E, V, H, S> =
33    authenticated::Journal<F, E, fixed::Journal<E, Operation<F, V>>, H, S>;
34
35/// Configuration for a fixed-size [keyless](super) authenticated db.
36pub type Config<S> = super::Config<JournalConfig, S>;
37
38/// Configuration for a fixed-size [keyless](super) compact db.
39pub type CompactConfig<S> = super::CompactConfig<(), S>;
40
41impl<F: Family, E: Storage + Clock + Metrics, V: FixedValue, H: Hasher, S: Strategy>
42    Db<F, E, V, H, S>
43{
44    /// Returns a [Db] initialized from `cfg`. Any uncommitted operations will be
45    /// discarded and the state of the db will be as of the last committed operation.
46    pub async fn init(context: E, cfg: Config<S>) -> Result<Self, Error<F>> {
47        let journal: Journal<F, E, V, H, S> = Journal::new(
48            context.child("journal"),
49            cfg.merkle,
50            cfg.log,
51            Operation::<F, V>::is_commit,
52            ROOT_BAGGING,
53        )
54        .await?;
55        Self::init_from_journal(journal, context).await
56    }
57}
58
59impl<F: Family, E: Storage + Clock + Metrics, V: FixedValue, H: Hasher, S: Strategy>
60    CompactDb<F, E, V, H, S>
61{
62    /// Returns a [CompactDb] initialized from `cfg`.
63    pub async fn init(context: E, cfg: CompactConfig<S>) -> Result<Self, Error<F>> {
64        let merkle = crate::merkle::compact::Merkle::init(context, cfg.merkle).await?;
65        Self::init_from_merkle(merkle, ()).await
66    }
67}
68
69#[cfg(test)]
70mod test {
71    use super::*;
72    use crate::{
73        merkle::{mmb, mmr},
74        qmdb::keyless::tests,
75    };
76    use commonware_cryptography::Sha256;
77    use commonware_macros::test_traced;
78    use commonware_parallel::{Rayon, Sequential, Strategy};
79    use commonware_runtime::{
80        buffer::paged::CacheRef, deterministic, BufferPooler, Runner as _, Supervisor as _,
81    };
82    use commonware_utils::{NZUsize, NZU16, NZU64};
83    use std::num::{NonZeroU16, NonZeroUsize};
84
85    const PAGE_SIZE: NonZeroU16 = NZU16!(101);
86    const PAGE_CACHE_SIZE: NonZeroUsize = NZUsize!(11);
87
88    fn db_config<S: Strategy>(suffix: &str, pooler: &impl BufferPooler, strategy: S) -> Config<S> {
89        let page_cache = CacheRef::from_pooler(pooler, PAGE_SIZE, PAGE_CACHE_SIZE);
90        Config {
91            merkle: crate::merkle::full::Config {
92                journal_partition: format!("fixed-journal-{suffix}"),
93                metadata_partition: format!("fixed-metadata-{suffix}"),
94                items_per_blob: NZU64!(11),
95                write_buffer: NZUsize!(1024),
96                strategy,
97                page_cache: page_cache.clone(),
98            },
99            log: JournalConfig {
100                partition: format!("fixed-log-journal-{suffix}"),
101                items_per_blob: NZU64!(7),
102                page_cache,
103                write_buffer: NZUsize!(1024),
104            },
105        }
106    }
107
108    type TestDb<F> =
109        Db<F, deterministic::Context, commonware_utils::sequence::U64, Sha256, Sequential>;
110    type TestRayonDb<F> =
111        Db<F, deterministic::Context, commonware_utils::sequence::U64, Sha256, Rayon>;
112    type TestCompactDb<F> =
113        CompactDb<F, deterministic::Context, commonware_utils::sequence::U64, Sha256, Sequential>;
114
115    async fn open_db<F: Family>(context: deterministic::Context) -> TestDb<F> {
116        open_db_with_suffix("partition", context).await
117    }
118
119    async fn open_db_with_suffix<F: Family>(
120        suffix: &str,
121        context: deterministic::Context,
122    ) -> TestDb<F> {
123        let cfg = db_config(suffix, &context, Sequential);
124        TestDb::init(context, cfg).await.unwrap()
125    }
126
127    async fn open_rayon_db<F: Family>(context: deterministic::Context) -> TestRayonDb<F> {
128        let cfg = db_config("rayon", &context, Rayon::new(NZUsize!(2)).unwrap());
129        TestRayonDb::init(context, cfg).await.unwrap()
130    }
131
132    async fn open_compact<F: crate::merkle::Family>(
133        context: deterministic::Context,
134    ) -> TestCompactDb<F> {
135        let cfg = CompactConfig {
136            merkle: crate::merkle::compact::Config {
137                partition: "compact-keyless-fixed".into(),
138                strategy: Sequential,
139            },
140            commit_codec_config: (),
141        };
142        TestCompactDb::init(context, cfg).await.unwrap()
143    }
144
145    fn reopen<F: Family>() -> tests::Reopen<TestDb<F>> {
146        Box::new(|ctx| Box::pin(open_db(ctx)))
147    }
148
149    #[test_traced("INFO")]
150    fn test_keyless_fixed_metrics() {
151        deterministic::Runner::default().start(|ctx| async move {
152            let mut db = open_db::<mmr::Family>(ctx.child("db")).await;
153            let value = commonware_utils::sequence::U64::new(7);
154            let floor = db.inactivity_floor_loc();
155            let batch = db
156                .new_batch()
157                .append(value.clone())
158                .merkleize(&db, None, floor);
159            let range = db.apply_batch(batch).await.unwrap();
160            assert_eq!(db.get(range.start).await.unwrap(), Some(value.clone()));
161            assert_eq!(
162                db.get_many(&[range.start]).await.unwrap(),
163                vec![Some(value)]
164            );
165            db.commit().await.unwrap();
166            db.sync().await.unwrap();
167            db.prune(crate::merkle::Location::new(0)).await.unwrap();
168
169            let metrics = ctx.encode();
170            for expected in [
171                "db_size 3",
172                "db_pruning_boundary 0",
173                "db_retained 3",
174                "db_inactivity_floor 0",
175                "db_last_commit 2",
176                "db_get_calls_total 1",
177                "db_get_many_calls_total 1",
178                "db_locations_requested_total 2",
179                "db_apply_batch_calls_total 1",
180                "db_operations_applied_total 2",
181                "db_commit_calls_total 1",
182                "db_sync_calls_total 1",
183                "db_prune_calls_total 1",
184                "db_get_duration_count 1",
185                "db_get_many_duration_count 1",
186                "db_apply_batch_duration_count 1",
187                "db_commit_duration_count 1",
188                "db_sync_duration_count 1",
189                "db_prune_duration_count 1",
190            ] {
191                assert!(metrics.contains(expected), "missing {expected}\n{metrics}");
192            }
193        });
194    }
195
196    #[test_traced("INFO")]
197    fn test_keyless_fixed_empty() {
198        deterministic::Runner::default().start(|ctx| async move {
199            let db = open_db::<mmr::Family>(ctx.child("db").with_attribute("index", 1)).await;
200            tests::test_keyless_db_empty(ctx, db, reopen::<mmr::Family>()).await;
201        });
202    }
203
204    #[test_traced("WARN")]
205    fn test_keyless_fixed_build_basic() {
206        deterministic::Runner::default().start(|ctx| async move {
207            let db = open_db::<mmr::Family>(ctx.child("db").with_attribute("index", 1)).await;
208            tests::test_keyless_db_build_basic(ctx, db, reopen::<mmr::Family>()).await;
209        });
210    }
211
212    #[test_traced("WARN")]
213    fn test_keyless_fixed_recovery() {
214        deterministic::Runner::default().start(|ctx| async move {
215            let db = open_db::<mmr::Family>(ctx.child("db").with_attribute("index", 1)).await;
216            tests::test_keyless_db_recovery(ctx, db, reopen::<mmr::Family>()).await;
217        });
218    }
219
220    #[test_traced("WARN")]
221    fn test_keyless_fixed_non_empty_recovery() {
222        deterministic::Runner::default().start(|ctx| async move {
223            let db = open_db::<mmr::Family>(ctx.child("db").with_attribute("index", 1)).await;
224            tests::test_keyless_db_non_empty_recovery(ctx, db, reopen::<mmr::Family>()).await;
225        });
226    }
227
228    #[test_traced("INFO")]
229    fn test_keyless_fixed_proof() {
230        deterministic::Runner::default().start(|ctx| async move {
231            let db = open_db::<mmr::Family>(ctx.child("storage")).await;
232            tests::test_keyless_db_proof(db).await;
233        });
234    }
235
236    #[test_traced("INFO")]
237    fn test_keyless_fixed_proof_comprehensive() {
238        deterministic::Runner::default().start(|ctx| async move {
239            let db = open_db::<mmr::Family>(ctx.child("storage")).await;
240            tests::test_keyless_db_proof_comprehensive(db).await;
241        });
242    }
243
244    #[test_traced("INFO")]
245    fn test_keyless_fixed_proof_with_pruning() {
246        deterministic::Runner::default().start(|ctx| async move {
247            let db = open_db::<mmr::Family>(ctx.child("db").with_attribute("index", 1)).await;
248            tests::test_keyless_db_proof_with_pruning(ctx, db, reopen::<mmr::Family>()).await;
249        });
250    }
251
252    #[test_traced("WARN")]
253    fn test_keyless_fixed_empty_db_recovery() {
254        deterministic::Runner::default().start(|ctx| async move {
255            let db = open_db::<mmr::Family>(ctx.child("db").with_attribute("index", 1)).await;
256            tests::test_keyless_db_empty_db_recovery(ctx, db, reopen::<mmr::Family>()).await;
257        });
258    }
259
260    #[test_traced("WARN")]
261    fn test_keyless_fixed_replay_with_trailing_appends() {
262        deterministic::Runner::default().start(|ctx| async move {
263            let db = open_db::<mmr::Family>(ctx.child("db").with_attribute("index", 1)).await;
264            tests::test_keyless_db_replay_with_trailing_appends(ctx, db, reopen::<mmr::Family>())
265                .await;
266        });
267    }
268
269    #[test_traced("INFO")]
270    fn test_keyless_fixed_get_out_of_bounds() {
271        deterministic::Runner::default().start(|ctx| async move {
272            let db = open_db::<mmr::Family>(ctx.child("storage")).await;
273            tests::test_keyless_db_get_out_of_bounds(db).await;
274        });
275    }
276
277    #[test_traced("INFO")]
278    fn test_keyless_fixed_metadata() {
279        deterministic::Runner::default().start(|ctx| async move {
280            let db = open_db::<mmr::Family>(ctx.child("db")).await;
281            tests::test_keyless_db_metadata(db).await;
282        });
283    }
284
285    #[test_traced("INFO")]
286    fn test_keyless_fixed_shared_helper_accepts_rayon_strategy() {
287        deterministic::Runner::default().start(|ctx| async move {
288            let db = open_rayon_db::<mmr::Family>(ctx.child("db").with_attribute("index", 1)).await;
289            tests::test_keyless_db_metadata(db).await;
290        });
291    }
292
293    async fn assert_compact_root_compatibility<F: crate::merkle::Family>(
294        ctx: deterministic::Context,
295    ) {
296        let mut db = open_db::<F>(ctx.child("db")).await;
297        let mut compact = open_compact::<F>(ctx.child("compact")).await;
298        assert_eq!(db.root(), compact.root());
299
300        let v1 = commonware_utils::sequence::U64::new(1);
301        let v2 = commonware_utils::sequence::U64::new(2);
302        let metadata = commonware_utils::sequence::U64::new(99);
303
304        let floor = db.inactivity_floor_loc();
305        let retained = db
306            .new_batch()
307            .append(v1.clone())
308            .append(v2.clone())
309            .merkleize(&db, Some(metadata.clone()), floor);
310        let compact_batch = compact.new_batch().append(v1).append(v2).merkleize(
311            &compact,
312            Some(metadata.clone()),
313            floor,
314        );
315
316        assert_eq!(retained.root(), compact_batch.root());
317
318        db.apply_batch(retained).await.unwrap();
319        compact.apply_batch(compact_batch).unwrap();
320        db.commit().await.unwrap();
321        compact.commit().await.unwrap();
322
323        assert_eq!(db.root(), compact.root());
324        assert_eq!(compact.get_metadata(), Some(metadata.clone()));
325
326        drop(compact);
327        let reopened = open_compact::<F>(ctx.child("reopen")).await;
328        assert_eq!(db.root(), reopened.root());
329        assert_eq!(reopened.get_metadata(), Some(metadata));
330
331        reopened.destroy().await.unwrap();
332        db.destroy().await.unwrap();
333    }
334
335    #[test_traced("INFO")]
336    fn test_keyless_fixed_compact_root_compatibility() {
337        deterministic::Runner::default().start(|ctx| async move {
338            assert_compact_root_compatibility::<mmr::Family>(ctx).await;
339        });
340    }
341
342    #[test_traced("INFO")]
343    fn test_keyless_fixed_compact_root_compatibility_mmb() {
344        deterministic::Runner::default().start(|ctx| async move {
345            assert_compact_root_compatibility::<mmb::Family>(ctx).await;
346        });
347    }
348
349    #[test_traced("INFO")]
350    fn test_keyless_fixed_pruning() {
351        deterministic::Runner::default().start(|ctx| async move {
352            let db = open_db::<mmr::Family>(ctx.child("db")).await;
353            tests::test_keyless_db_pruning(db).await;
354        });
355    }
356
357    #[test_traced("INFO")]
358    fn test_keyless_fixed_batch_get() {
359        deterministic::Runner::default().start(|ctx| async move {
360            let db = open_db::<mmr::Family>(ctx.child("db")).await;
361            tests::test_keyless_batch_get(db).await;
362        });
363    }
364
365    #[test_traced("INFO")]
366    fn test_keyless_fixed_batch_stacked_get() {
367        deterministic::Runner::default().start(|ctx| async move {
368            let db = open_db::<mmr::Family>(ctx.child("db")).await;
369            tests::test_keyless_batch_stacked_get(db).await;
370        });
371    }
372
373    #[test_traced("INFO")]
374    fn test_keyless_fixed_batch_speculative_root() {
375        deterministic::Runner::default().start(|ctx| async move {
376            let db = open_db::<mmr::Family>(ctx.child("db")).await;
377            tests::test_keyless_batch_speculative_root(db).await;
378        });
379    }
380
381    #[test_traced("INFO")]
382    fn test_keyless_fixed_merkleized_batch_get() {
383        deterministic::Runner::default().start(|ctx| async move {
384            let db = open_db::<mmr::Family>(ctx.child("db")).await;
385            tests::test_keyless_merkleized_batch_get(db).await;
386        });
387    }
388
389    #[test_traced("INFO")]
390    fn test_keyless_fixed_get_many() {
391        deterministic::Runner::default().start(|ctx| async move {
392            let db = open_db::<mmr::Family>(ctx.child("db")).await;
393            tests::test_keyless_get_many(db).await;
394        });
395    }
396
397    #[test_traced("INFO")]
398    fn test_keyless_fixed_batch_chained() {
399        deterministic::Runner::default().start(|ctx| async move {
400            let db = open_db::<mmr::Family>(ctx.child("db")).await;
401            tests::test_keyless_batch_chained(db).await;
402        });
403    }
404
405    #[test_traced("INFO")]
406    fn test_keyless_fixed_batch_chained_apply_sequential() {
407        deterministic::Runner::default().start(|ctx| async move {
408            let db = open_db::<mmr::Family>(ctx.child("db")).await;
409            tests::test_keyless_batch_chained_apply_sequential(db).await;
410        });
411    }
412
413    #[test_traced("INFO")]
414    fn test_keyless_fixed_batch_many_sequential() {
415        deterministic::Runner::default().start(|ctx| async move {
416            let db = open_db::<mmr::Family>(ctx.child("db")).await;
417            tests::test_keyless_batch_many_sequential(db).await;
418        });
419    }
420
421    #[test_traced("INFO")]
422    fn test_keyless_fixed_batch_empty() {
423        deterministic::Runner::default().start(|ctx| async move {
424            let db = open_db::<mmr::Family>(ctx.child("db")).await;
425            tests::test_keyless_batch_empty(db).await;
426        });
427    }
428
429    #[test_traced("INFO")]
430    fn test_keyless_fixed_batch_chained_merkleized_get() {
431        deterministic::Runner::default().start(|ctx| async move {
432            let db = open_db::<mmr::Family>(ctx.child("db")).await;
433            tests::test_keyless_batch_chained_merkleized_get(db).await;
434        });
435    }
436
437    #[test_traced("INFO")]
438    fn test_keyless_fixed_batch_large() {
439        deterministic::Runner::default().start(|ctx| async move {
440            let db = open_db::<mmr::Family>(ctx.child("db")).await;
441            tests::test_keyless_batch_large(db).await;
442        });
443    }
444
445    #[test_traced]
446    fn test_keyless_fixed_stale_batch() {
447        deterministic::Runner::default().start(|ctx| async move {
448            let db = open_db::<mmr::Family>(ctx.child("db")).await;
449            tests::test_keyless_stale_batch(db).await;
450        });
451    }
452
453    #[test_traced]
454    fn test_keyless_fixed_stale_batch_chained() {
455        deterministic::Runner::default().start(|ctx| async move {
456            let db = open_db::<mmr::Family>(ctx.child("db")).await;
457            tests::test_keyless_stale_batch_chained(db).await;
458        });
459    }
460
461    #[test_traced]
462    fn test_keyless_fixed_sequential_commit_parent_then_child() {
463        deterministic::Runner::default().start(|ctx| async move {
464            let db = open_db::<mmr::Family>(ctx.child("db")).await;
465            tests::test_keyless_sequential_commit_parent_then_child(db).await;
466        });
467    }
468
469    #[test_traced]
470    fn test_keyless_fixed_stale_batch_child_before_parent() {
471        deterministic::Runner::default().start(|ctx| async move {
472            let db = open_db::<mmr::Family>(ctx.child("db")).await;
473            tests::test_keyless_stale_batch_child_before_parent(db).await;
474        });
475    }
476
477    #[test_traced]
478    fn test_keyless_fixed_to_batch() {
479        deterministic::Runner::default().start(|ctx| async move {
480            let db = open_db::<mmr::Family>(ctx.child("db")).await;
481            tests::test_keyless_to_batch(db).await;
482        });
483    }
484
485    #[test_traced]
486    fn test_keyless_fixed_child_root_matches_pending_and_committed() {
487        deterministic::Runner::default().start(|ctx| async move {
488            let db = open_db::<mmr::Family>(ctx.child("db")).await;
489            tests::test_keyless_child_root_matches_pending_and_committed(db).await;
490        });
491    }
492
493    #[test_traced("INFO")]
494    fn test_keyless_fixed_rewind_recovery() {
495        deterministic::Runner::default().start(|ctx| async move {
496            let db = open_db::<mmr::Family>(ctx.child("db")).await;
497            tests::test_keyless_db_rewind_recovery(ctx, db, reopen::<mmr::Family>()).await;
498        });
499    }
500
501    #[test_traced("INFO")]
502    fn test_keyless_fixed_rewind_pruned_target_errors() {
503        deterministic::Runner::default().start(|ctx| async move {
504            let db = open_db::<mmr::Family>(ctx.child("db")).await;
505            tests::test_keyless_db_rewind_pruned_target_errors(db).await;
506        });
507    }
508
509    #[test_traced("INFO")]
510    fn test_keyless_fixed_floor_tracking() {
511        deterministic::Runner::default().start(|ctx| async move {
512            let db = open_db::<mmr::Family>(ctx.child("db").with_attribute("index", 1)).await;
513            tests::test_keyless_db_floor_tracking(ctx, db, reopen::<mmr::Family>()).await;
514        });
515    }
516
517    #[test_traced("INFO")]
518    fn test_keyless_fixed_floor_regression_rejected() {
519        deterministic::Runner::default().start(|ctx| async move {
520            let db = open_db::<mmr::Family>(ctx.child("db")).await;
521            tests::test_keyless_db_floor_regression_rejected(db).await;
522        });
523    }
524
525    #[test_traced("INFO")]
526    fn test_keyless_fixed_floor_beyond_commit_loc_rejected() {
527        deterministic::Runner::default().start(|ctx| async move {
528            let db = open_db::<mmr::Family>(ctx.child("db")).await;
529            tests::test_keyless_db_floor_beyond_commit_loc_rejected(db).await;
530        });
531    }
532
533    #[test_traced("INFO")]
534    fn test_keyless_fixed_rewind_restores_floor() {
535        deterministic::Runner::default().start(|ctx| async move {
536            let db = open_db::<mmr::Family>(ctx.child("db")).await;
537            tests::test_keyless_db_rewind_restores_floor(db).await;
538        });
539    }
540
541    #[test_traced("INFO")]
542    fn test_keyless_fixed_floor_changes_root() {
543        deterministic::Runner::default().start(|ctx| async move {
544            let db_a = open_db_with_suffix::<mmr::Family>("root-a", ctx.child("a")).await;
545            let db_b = open_db_with_suffix::<mmr::Family>("root-b", ctx.child("b")).await;
546            tests::test_keyless_db_floor_changes_root(db_a, db_b).await;
547        });
548    }
549
550    #[test_traced("INFO")]
551    fn test_keyless_fixed_floor_at_commit_loc_accepted() {
552        deterministic::Runner::default().start(|ctx| async move {
553            let db = open_db::<mmr::Family>(ctx.child("db")).await;
554            tests::test_keyless_db_floor_at_commit_loc_accepted(db).await;
555        });
556    }
557
558    #[test_traced("INFO")]
559    fn test_keyless_fixed_rewind_after_reopen_with_floor() {
560        deterministic::Runner::default().start(|ctx| async move {
561            let db = open_db::<mmr::Family>(ctx.child("db").with_attribute("index", 1)).await;
562            tests::test_keyless_db_rewind_after_reopen_with_floor(ctx, db, reopen::<mmr::Family>())
563                .await;
564        });
565    }
566
567    #[test_traced("INFO")]
568    fn test_keyless_fixed_ancestor_floor_regression_rejected() {
569        deterministic::Runner::default().start(|ctx| async move {
570            let db = open_db::<mmr::Family>(ctx.child("db")).await;
571            tests::test_keyless_db_ancestor_floor_regression_rejected(db).await;
572        });
573    }
574
575    #[test_traced("INFO")]
576    fn test_keyless_fixed_ancestor_floor_beyond_commit_loc_rejected() {
577        deterministic::Runner::default().start(|ctx| async move {
578            let db = open_db::<mmr::Family>(ctx.child("db")).await;
579            tests::test_keyless_db_ancestor_floor_beyond_commit_loc_rejected(db).await;
580        });
581    }
582
583    #[test_traced("INFO")]
584    fn test_keyless_fixed_chained_apply_with_valid_floors_succeeds() {
585        deterministic::Runner::default().start(|ctx| async move {
586            let db = open_db::<mmr::Family>(ctx.child("db")).await;
587            tests::test_keyless_db_chained_apply_with_valid_floors_succeeds(db).await;
588        });
589    }
590
591    #[test_traced("INFO")]
592    fn test_keyless_fixed_single_commit_live_set() {
593        deterministic::Runner::default().start(|ctx| async move {
594            let db = open_db::<mmr::Family>(ctx.child("db").with_attribute("index", 1)).await;
595            tests::test_keyless_db_single_commit_live_set(ctx, db, reopen::<mmr::Family>()).await;
596        });
597    }
598
599    // mmb::Family variants
600
601    #[test_traced("INFO")]
602    fn test_keyless_fixed_empty_mmb() {
603        deterministic::Runner::default().start(|ctx| async move {
604            let db = open_db::<mmb::Family>(ctx.child("db").with_attribute("index", 1)).await;
605            tests::test_keyless_db_empty(ctx, db, reopen::<mmb::Family>()).await;
606        });
607    }
608
609    #[test_traced("WARN")]
610    fn test_keyless_fixed_build_basic_mmb() {
611        deterministic::Runner::default().start(|ctx| async move {
612            let db = open_db::<mmb::Family>(ctx.child("db").with_attribute("index", 1)).await;
613            tests::test_keyless_db_build_basic(ctx, db, reopen::<mmb::Family>()).await;
614        });
615    }
616
617    #[test_traced("WARN")]
618    fn test_keyless_fixed_recovery_mmb() {
619        deterministic::Runner::default().start(|ctx| async move {
620            let db = open_db::<mmb::Family>(ctx.child("db").with_attribute("index", 1)).await;
621            tests::test_keyless_db_recovery(ctx, db, reopen::<mmb::Family>()).await;
622        });
623    }
624
625    #[test_traced("WARN")]
626    fn test_keyless_fixed_non_empty_recovery_mmb() {
627        deterministic::Runner::default().start(|ctx| async move {
628            let db = open_db::<mmb::Family>(ctx.child("db").with_attribute("index", 1)).await;
629            tests::test_keyless_db_non_empty_recovery(ctx, db, reopen::<mmb::Family>()).await;
630        });
631    }
632
633    #[test_traced("INFO")]
634    fn test_keyless_fixed_proof_mmb() {
635        deterministic::Runner::default().start(|ctx| async move {
636            let db = open_db::<mmb::Family>(ctx.child("storage")).await;
637            tests::test_keyless_db_proof(db).await;
638        });
639    }
640
641    #[test_traced("INFO")]
642    fn test_keyless_fixed_proof_comprehensive_mmb() {
643        deterministic::Runner::default().start(|ctx| async move {
644            let db = open_db::<mmb::Family>(ctx.child("storage")).await;
645            tests::test_keyless_db_proof_comprehensive(db).await;
646        });
647    }
648
649    #[test_traced("INFO")]
650    fn test_keyless_fixed_proof_with_pruning_mmb() {
651        deterministic::Runner::default().start(|ctx| async move {
652            let db = open_db::<mmb::Family>(ctx.child("db").with_attribute("index", 1)).await;
653            tests::test_keyless_db_proof_with_pruning(ctx, db, reopen::<mmb::Family>()).await;
654        });
655    }
656
657    #[test_traced("WARN")]
658    fn test_keyless_fixed_empty_db_recovery_mmb() {
659        deterministic::Runner::default().start(|ctx| async move {
660            let db = open_db::<mmb::Family>(ctx.child("db").with_attribute("index", 1)).await;
661            tests::test_keyless_db_empty_db_recovery(ctx, db, reopen::<mmb::Family>()).await;
662        });
663    }
664
665    #[test_traced("WARN")]
666    fn test_keyless_fixed_replay_with_trailing_appends_mmb() {
667        deterministic::Runner::default().start(|ctx| async move {
668            let db = open_db::<mmb::Family>(ctx.child("db").with_attribute("index", 1)).await;
669            tests::test_keyless_db_replay_with_trailing_appends(ctx, db, reopen::<mmb::Family>())
670                .await;
671        });
672    }
673
674    #[test_traced("INFO")]
675    fn test_keyless_fixed_get_out_of_bounds_mmb() {
676        deterministic::Runner::default().start(|ctx| async move {
677            let db = open_db::<mmb::Family>(ctx.child("storage")).await;
678            tests::test_keyless_db_get_out_of_bounds(db).await;
679        });
680    }
681
682    #[test_traced("INFO")]
683    fn test_keyless_fixed_metadata_mmb() {
684        deterministic::Runner::default().start(|ctx| async move {
685            let db = open_db::<mmb::Family>(ctx.child("db")).await;
686            tests::test_keyless_db_metadata(db).await;
687        });
688    }
689
690    #[test_traced("INFO")]
691    fn test_keyless_fixed_pruning_mmb() {
692        deterministic::Runner::default().start(|ctx| async move {
693            let db = open_db::<mmb::Family>(ctx.child("db")).await;
694            tests::test_keyless_db_pruning(db).await;
695        });
696    }
697
698    #[test_traced("INFO")]
699    fn test_keyless_fixed_batch_get_mmb() {
700        deterministic::Runner::default().start(|ctx| async move {
701            let db = open_db::<mmb::Family>(ctx.child("db")).await;
702            tests::test_keyless_batch_get(db).await;
703        });
704    }
705
706    #[test_traced("INFO")]
707    fn test_keyless_fixed_batch_stacked_get_mmb() {
708        deterministic::Runner::default().start(|ctx| async move {
709            let db = open_db::<mmb::Family>(ctx.child("db")).await;
710            tests::test_keyless_batch_stacked_get(db).await;
711        });
712    }
713
714    #[test_traced("INFO")]
715    fn test_keyless_fixed_batch_speculative_root_mmb() {
716        deterministic::Runner::default().start(|ctx| async move {
717            let db = open_db::<mmb::Family>(ctx.child("db")).await;
718            tests::test_keyless_batch_speculative_root(db).await;
719        });
720    }
721
722    #[test_traced("INFO")]
723    fn test_keyless_fixed_merkleized_batch_get_mmb() {
724        deterministic::Runner::default().start(|ctx| async move {
725            let db = open_db::<mmb::Family>(ctx.child("db")).await;
726            tests::test_keyless_merkleized_batch_get(db).await;
727        });
728    }
729
730    #[test_traced("INFO")]
731    fn test_keyless_fixed_batch_chained_mmb() {
732        deterministic::Runner::default().start(|ctx| async move {
733            let db = open_db::<mmb::Family>(ctx.child("db")).await;
734            tests::test_keyless_batch_chained(db).await;
735        });
736    }
737
738    #[test_traced("INFO")]
739    fn test_keyless_fixed_batch_chained_apply_sequential_mmb() {
740        deterministic::Runner::default().start(|ctx| async move {
741            let db = open_db::<mmb::Family>(ctx.child("db")).await;
742            tests::test_keyless_batch_chained_apply_sequential(db).await;
743        });
744    }
745
746    #[test_traced("INFO")]
747    fn test_keyless_fixed_batch_many_sequential_mmb() {
748        deterministic::Runner::default().start(|ctx| async move {
749            let db = open_db::<mmb::Family>(ctx.child("db")).await;
750            tests::test_keyless_batch_many_sequential(db).await;
751        });
752    }
753
754    #[test_traced("INFO")]
755    fn test_keyless_fixed_batch_empty_mmb() {
756        deterministic::Runner::default().start(|ctx| async move {
757            let db = open_db::<mmb::Family>(ctx.child("db")).await;
758            tests::test_keyless_batch_empty(db).await;
759        });
760    }
761
762    #[test_traced("INFO")]
763    fn test_keyless_fixed_batch_chained_merkleized_get_mmb() {
764        deterministic::Runner::default().start(|ctx| async move {
765            let db = open_db::<mmb::Family>(ctx.child("db")).await;
766            tests::test_keyless_batch_chained_merkleized_get(db).await;
767        });
768    }
769
770    #[test_traced("INFO")]
771    fn test_keyless_fixed_batch_large_mmb() {
772        deterministic::Runner::default().start(|ctx| async move {
773            let db = open_db::<mmb::Family>(ctx.child("db")).await;
774            tests::test_keyless_batch_large(db).await;
775        });
776    }
777
778    #[test_traced]
779    fn test_keyless_fixed_stale_batch_mmb() {
780        deterministic::Runner::default().start(|ctx| async move {
781            let db = open_db::<mmb::Family>(ctx.child("db")).await;
782            tests::test_keyless_stale_batch(db).await;
783        });
784    }
785
786    #[test_traced]
787    fn test_keyless_fixed_stale_batch_chained_mmb() {
788        deterministic::Runner::default().start(|ctx| async move {
789            let db = open_db::<mmb::Family>(ctx.child("db")).await;
790            tests::test_keyless_stale_batch_chained(db).await;
791        });
792    }
793
794    #[test_traced]
795    fn test_keyless_fixed_sequential_commit_parent_then_child_mmb() {
796        deterministic::Runner::default().start(|ctx| async move {
797            let db = open_db::<mmb::Family>(ctx.child("db")).await;
798            tests::test_keyless_sequential_commit_parent_then_child(db).await;
799        });
800    }
801
802    #[test_traced]
803    fn test_keyless_fixed_stale_batch_child_before_parent_mmb() {
804        deterministic::Runner::default().start(|ctx| async move {
805            let db = open_db::<mmb::Family>(ctx.child("db")).await;
806            tests::test_keyless_stale_batch_child_before_parent(db).await;
807        });
808    }
809
810    #[test_traced]
811    fn test_keyless_fixed_to_batch_mmb() {
812        deterministic::Runner::default().start(|ctx| async move {
813            let db = open_db::<mmb::Family>(ctx.child("db")).await;
814            tests::test_keyless_to_batch(db).await;
815        });
816    }
817
818    #[test_traced]
819    fn test_keyless_fixed_child_root_matches_pending_and_committed_mmb() {
820        deterministic::Runner::default().start(|ctx| async move {
821            let db = open_db::<mmb::Family>(ctx.child("db")).await;
822            tests::test_keyless_child_root_matches_pending_and_committed(db).await;
823        });
824    }
825
826    #[test_traced("INFO")]
827    fn test_keyless_fixed_rewind_recovery_mmb() {
828        deterministic::Runner::default().start(|ctx| async move {
829            let db = open_db::<mmb::Family>(ctx.child("db")).await;
830            tests::test_keyless_db_rewind_recovery(ctx, db, reopen::<mmb::Family>()).await;
831        });
832    }
833
834    #[test_traced("INFO")]
835    fn test_keyless_fixed_rewind_pruned_target_errors_mmb() {
836        deterministic::Runner::default().start(|ctx| async move {
837            let db = open_db::<mmb::Family>(ctx.child("db")).await;
838            tests::test_keyless_db_rewind_pruned_target_errors(db).await;
839        });
840    }
841
842    #[test_traced("INFO")]
843    fn test_keyless_fixed_floor_tracking_mmb() {
844        deterministic::Runner::default().start(|ctx| async move {
845            let db = open_db::<mmb::Family>(ctx.child("db").with_attribute("index", 1)).await;
846            tests::test_keyless_db_floor_tracking(ctx, db, reopen::<mmb::Family>()).await;
847        });
848    }
849
850    #[test_traced("INFO")]
851    fn test_keyless_fixed_floor_regression_rejected_mmb() {
852        deterministic::Runner::default().start(|ctx| async move {
853            let db = open_db::<mmb::Family>(ctx.child("db")).await;
854            tests::test_keyless_db_floor_regression_rejected(db).await;
855        });
856    }
857
858    #[test_traced("INFO")]
859    fn test_keyless_fixed_floor_beyond_commit_loc_rejected_mmb() {
860        deterministic::Runner::default().start(|ctx| async move {
861            let db = open_db::<mmb::Family>(ctx.child("db")).await;
862            tests::test_keyless_db_floor_beyond_commit_loc_rejected(db).await;
863        });
864    }
865
866    #[test_traced("INFO")]
867    fn test_keyless_fixed_rewind_restores_floor_mmb() {
868        deterministic::Runner::default().start(|ctx| async move {
869            let db = open_db::<mmb::Family>(ctx.child("db")).await;
870            tests::test_keyless_db_rewind_restores_floor(db).await;
871        });
872    }
873
874    #[test_traced("INFO")]
875    fn test_keyless_fixed_floor_changes_root_mmb() {
876        deterministic::Runner::default().start(|ctx| async move {
877            let db_a = open_db_with_suffix::<mmb::Family>("root-a", ctx.child("a")).await;
878            let db_b = open_db_with_suffix::<mmb::Family>("root-b", ctx.child("b")).await;
879            tests::test_keyless_db_floor_changes_root(db_a, db_b).await;
880        });
881    }
882
883    #[test_traced("INFO")]
884    fn test_keyless_fixed_floor_at_commit_loc_accepted_mmb() {
885        deterministic::Runner::default().start(|ctx| async move {
886            let db = open_db::<mmb::Family>(ctx.child("db")).await;
887            tests::test_keyless_db_floor_at_commit_loc_accepted(db).await;
888        });
889    }
890
891    #[test_traced("INFO")]
892    fn test_keyless_fixed_rewind_after_reopen_with_floor_mmb() {
893        deterministic::Runner::default().start(|ctx| async move {
894            let db = open_db::<mmb::Family>(ctx.child("db").with_attribute("index", 1)).await;
895            tests::test_keyless_db_rewind_after_reopen_with_floor(ctx, db, reopen::<mmb::Family>())
896                .await;
897        });
898    }
899
900    #[test_traced("INFO")]
901    fn test_keyless_fixed_ancestor_floor_regression_rejected_mmb() {
902        deterministic::Runner::default().start(|ctx| async move {
903            let db = open_db::<mmb::Family>(ctx.child("db")).await;
904            tests::test_keyless_db_ancestor_floor_regression_rejected(db).await;
905        });
906    }
907
908    #[test_traced("INFO")]
909    fn test_keyless_fixed_ancestor_floor_beyond_commit_loc_rejected_mmb() {
910        deterministic::Runner::default().start(|ctx| async move {
911            let db = open_db::<mmb::Family>(ctx.child("db")).await;
912            tests::test_keyless_db_ancestor_floor_beyond_commit_loc_rejected(db).await;
913        });
914    }
915
916    #[test_traced("INFO")]
917    fn test_keyless_fixed_chained_apply_with_valid_floors_succeeds_mmb() {
918        deterministic::Runner::default().start(|ctx| async move {
919            let db = open_db::<mmb::Family>(ctx.child("db")).await;
920            tests::test_keyless_db_chained_apply_with_valid_floors_succeeds(db).await;
921        });
922    }
923
924    #[test_traced("INFO")]
925    fn test_keyless_fixed_single_commit_live_set_mmb() {
926        deterministic::Runner::default().start(|ctx| async move {
927            let db = open_db::<mmb::Family>(ctx.child("db").with_attribute("index", 1)).await;
928            tests::test_keyless_db_single_commit_live_set(ctx, db, reopen::<mmb::Family>()).await;
929        });
930    }
931
932    /// Smoke test: verify the sync engine works end-to-end with a fixed-size keyless database.
933    /// The full sync test suite runs against the variable variant via the harness in
934    /// [`super::super::sync::tests`]; this test covers the fixed-size code path.
935    #[test_traced("WARN")]
936    fn test_keyless_fixed_sync() {
937        use crate::{
938            merkle::Location,
939            qmdb::sync::{self, engine::Config, Target},
940        };
941        use commonware_utils::{non_empty_range, sequence::U64};
942        use std::sync::Arc;
943
944        deterministic::Runner::default().start(|ctx| async move {
945            let target_config = db_config("sync-target", &ctx, Sequential);
946            let mut target_db: TestDb<mmr::Family> =
947                TestDb::init(ctx.child("target"), target_config)
948                    .await
949                    .unwrap();
950
951            let mut batch = target_db.new_batch();
952            for i in 0..20u64 {
953                batch = batch.append(U64::new(i * 10 + 1));
954            }
955            let floor = target_db.inactivity_floor_loc();
956            let merkleized = batch.merkleize(&target_db, None, floor);
957            target_db.apply_batch(merkleized).await.unwrap();
958
959            let target_root = target_db.root();
960            let bounds = target_db.bounds().await;
961            let lower_bound = bounds.start;
962            let upper_bound = bounds.end;
963
964            let client_config = db_config("sync-client", &ctx, Sequential);
965            let target_db = Arc::new(target_db);
966            let config = Config {
967                db_config: client_config,
968                fetch_batch_size: NZU64!(5),
969                target: Target {
970                    root: target_root,
971                    range: non_empty_range!(lower_bound, upper_bound),
972                },
973                context: ctx.child("client"),
974                resolver: target_db.clone(),
975                apply_batch_size: 1024,
976                max_outstanding_requests: 1,
977                update_rx: None,
978                finish_rx: None,
979                reached_target_tx: None,
980                max_retained_roots: 8,
981            };
982            let synced_db: TestDb<mmr::Family> = sync::sync(config).await.unwrap();
983
984            assert_eq!(synced_db.root(), target_root);
985            let bounds = synced_db.bounds().await;
986            assert_eq!(bounds.end, upper_bound);
987            assert_eq!(bounds.start, lower_bound);
988
989            for i in 0..20u64 {
990                let got = synced_db.get(Location::new(i + 1)).await.unwrap();
991                assert_eq!(got, Some(U64::new(i * 10 + 1)));
992            }
993
994            synced_db.destroy().await.unwrap();
995            let target_db =
996                Arc::try_unwrap(target_db).unwrap_or_else(|_| panic!("failed to unwrap Arc"));
997            target_db.destroy().await.unwrap();
998        });
999    }
1000}