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