Skip to main content

commonware_storage/qmdb/keyless/
variable.rs

1//! A keyless authenticated database for variable-length data.
2//!
3//! For fixed-size values, use [super::fixed].
4
5use crate::{
6    journal::{
7        authenticated,
8        contiguous::variable::{self, Config as JournalConfig},
9    },
10    merkle::Family,
11    qmdb::{
12        any::value::{VariableEncoding, VariableValue},
13        keyless::operation::Operation as BaseOperation,
14        operation::Committable,
15        Error, ROOT_BAGGING,
16    },
17};
18use commonware_codec::Read;
19use commonware_cryptography::Hasher;
20use commonware_parallel::Strategy;
21use commonware_runtime::{Clock, Metrics, Storage};
22
23/// Keyless operation for variable-length values.
24pub type Operation<F, V> = BaseOperation<F, VariableEncoding<V>>;
25
26/// A keyless authenticated database for variable-length data.
27pub type Db<F, E, V, H, S> =
28    super::Keyless<F, E, VariableEncoding<V>, variable::Journal<E, Operation<F, V>>, H, S>;
29
30/// A compact keyless authenticated db for variable-length data.
31pub type CompactDb<F, E, V, H, C, S> = super::CompactDb<F, E, VariableEncoding<V>, H, C, S>;
32
33type Journal<F, E, V, H, S> =
34    authenticated::Journal<F, E, variable::Journal<E, Operation<F, V>>, H, S>;
35
36/// Configuration for a variable-size [keyless](super) authenticated db.
37pub type Config<C, S> = super::Config<JournalConfig<C>, S>;
38
39/// Configuration for a variable-size [keyless](super) compact db.
40pub type CompactConfig<C, S> = super::CompactConfig<C, S>;
41
42impl<F: Family, E: Storage + Clock + Metrics, V: VariableValue, H: Hasher, S: Strategy>
43    Db<F, E, V, H, S>
44{
45    /// Returns a [Db] initialized from `cfg`. Any uncommitted operations will be
46    /// discarded and the state of the db will be as of the last committed operation.
47    pub async fn init(
48        context: E,
49        cfg: Config<<Operation<F, V> as Read>::Cfg, S>,
50    ) -> Result<Self, Error<F>> {
51        let journal: Journal<F, E, V, H, S> = Journal::new(
52            context.child("journal"),
53            cfg.merkle,
54            cfg.log,
55            Operation::<F, V>::is_commit,
56            ROOT_BAGGING,
57        )
58        .await?;
59        Self::init_from_journal(journal, context).await
60    }
61}
62
63impl<
64        F: Family,
65        E: Storage + Clock + Metrics,
66        V: VariableValue,
67        H: Hasher,
68        C: Clone + Send + Sync + 'static,
69        S: Strategy,
70    > CompactDb<F, E, V, H, C, S>
71where
72    Operation<F, V>: Read<Cfg = C>,
73{
74    /// Returns a [CompactDb] initialized from `cfg`.
75    pub async fn init(context: E, cfg: CompactConfig<C, S>) -> Result<Self, Error<F>> {
76        let merkle = crate::merkle::compact::Merkle::init(context, cfg.merkle).await?;
77        Self::init_from_merkle(merkle, cfg.commit_codec_config).await
78    }
79}
80
81#[cfg(test)]
82mod test {
83    use super::*;
84    use crate::{
85        merkle::{mmb, mmr},
86        qmdb::keyless::tests,
87    };
88    use commonware_cryptography::Sha256;
89    use commonware_macros::test_traced;
90    use commonware_parallel::Sequential;
91    use commonware_runtime::{
92        buffer::paged::CacheRef, deterministic, BufferPooler, Runner as _, Supervisor as _,
93    };
94    use commonware_utils::{NZUsize, NZU16, NZU64};
95    use std::num::{NonZeroU16, NonZeroUsize};
96
97    // Use some weird sizes here to test boundary conditions.
98    const PAGE_SIZE: NonZeroU16 = NZU16!(101);
99    const PAGE_CACHE_SIZE: NonZeroUsize = NZUsize!(11);
100
101    fn db_config(
102        suffix: &str,
103        pooler: &impl BufferPooler,
104    ) -> Config<(commonware_codec::RangeCfg<usize>, ()), Sequential> {
105        let page_cache = CacheRef::from_pooler(pooler, PAGE_SIZE, PAGE_CACHE_SIZE);
106        Config {
107            merkle: crate::merkle::full::Config {
108                journal_partition: format!("journal-{suffix}"),
109                metadata_partition: format!("metadata-{suffix}"),
110                items_per_blob: NZU64!(11),
111                write_buffer: NZUsize!(1024),
112                strategy: Sequential,
113                page_cache: page_cache.clone(),
114            },
115            log: JournalConfig {
116                partition: format!("log-journal-{suffix}"),
117                items_per_section: NZU64!(7),
118                compression: None,
119                codec_config: ((0..=10000).into(), ()),
120                page_cache,
121                write_buffer: NZUsize!(1024),
122            },
123        }
124    }
125
126    type TestDb<F> = Db<F, deterministic::Context, Vec<u8>, Sha256, Sequential>;
127    type TestCompactDb<F> = CompactDb<
128        F,
129        deterministic::Context,
130        Vec<u8>,
131        Sha256,
132        (commonware_codec::RangeCfg<usize>, ()),
133        Sequential,
134    >;
135
136    /// Return a [Db] database initialized with a fixed config.
137    async fn open_db<F: Family>(context: deterministic::Context) -> TestDb<F> {
138        open_db_with_suffix("partition", context).await
139    }
140
141    async fn open_db_with_suffix<F: Family>(
142        suffix: &str,
143        context: deterministic::Context,
144    ) -> TestDb<F> {
145        let cfg = db_config(suffix, &context);
146        TestDb::init(context, cfg).await.unwrap()
147    }
148
149    async fn open_compact<F: crate::merkle::Family>(
150        context: deterministic::Context,
151    ) -> TestCompactDb<F> {
152        let cfg = CompactConfig {
153            merkle: crate::merkle::compact::Config {
154                partition: "compact-keyless-variable".into(),
155                strategy: Sequential,
156            },
157            commit_codec_config: ((0..=10000usize).into(), ()),
158        };
159        TestCompactDb::init(context, cfg).await.unwrap()
160    }
161
162    fn reopen<F: Family>() -> tests::Reopen<TestDb<F>> {
163        Box::new(|ctx| Box::pin(open_db(ctx)))
164    }
165
166    #[test_traced("INFO")]
167    fn test_keyless_db_empty() {
168        deterministic::Runner::default().start(|ctx| async move {
169            let db = open_db::<mmr::Family>(ctx.child("db").with_attribute("index", 1)).await;
170            tests::test_keyless_db_empty(ctx, db, reopen::<mmr::Family>()).await;
171        });
172    }
173
174    #[test_traced("WARN")]
175    fn test_keyless_db_build_basic() {
176        deterministic::Runner::default().start(|ctx| async move {
177            let db = open_db::<mmr::Family>(ctx.child("db").with_attribute("index", 1)).await;
178            tests::test_keyless_db_build_basic(ctx, db, reopen::<mmr::Family>()).await;
179        });
180    }
181
182    #[test_traced("WARN")]
183    fn test_keyless_db_recovery() {
184        deterministic::Runner::default().start(|ctx| async move {
185            let db = open_db::<mmr::Family>(ctx.child("db").with_attribute("index", 1)).await;
186            tests::test_keyless_db_recovery(ctx, db, reopen::<mmr::Family>()).await;
187        });
188    }
189
190    #[test_traced("WARN")]
191    fn test_keyless_db_non_empty_recovery() {
192        deterministic::Runner::default().start(|ctx| async move {
193            let db = open_db::<mmr::Family>(ctx.child("db").with_attribute("index", 1)).await;
194            tests::test_keyless_db_non_empty_recovery(ctx, db, reopen::<mmr::Family>()).await;
195        });
196    }
197
198    #[test_traced("INFO")]
199    fn test_keyless_db_proof() {
200        deterministic::Runner::default().start(|ctx| async move {
201            let db = open_db::<mmr::Family>(ctx.child("storage")).await;
202            tests::test_keyless_db_proof(db).await;
203        });
204    }
205
206    #[test_traced("INFO")]
207    fn test_keyless_db_proof_comprehensive() {
208        deterministic::Runner::default().start(|ctx| async move {
209            let db = open_db::<mmr::Family>(ctx.child("storage")).await;
210            tests::test_keyless_db_proof_comprehensive(db).await;
211        });
212    }
213
214    #[test_traced("INFO")]
215    fn test_keyless_db_proof_with_pruning() {
216        deterministic::Runner::default().start(|ctx| async move {
217            let db = open_db::<mmr::Family>(ctx.child("db").with_attribute("index", 1)).await;
218            tests::test_keyless_db_proof_with_pruning(ctx, db, reopen::<mmr::Family>()).await;
219        });
220    }
221
222    /// Regression: when pruning leaves `bounds.start` mid-blob ahead of the first retained commit,
223    /// `historical_proof` for sizes in that leading interval must report `HistoricalFloorPruned`
224    /// (the floor metadata is gone) rather than the misleading `UnexpectedData` (which sounds like
225    /// data corruption).
226    ///
227    /// Items_per_section=7 with batches of 3 appends + 1 commit places commits at locations 0, 4,
228    /// 8, 12, .... Pruning to loc=8 removes blob 0 (end=7 <=
229    /// 8) and retains blob 1 ([7, 14)). `bounds.start = 7` is a non-commit op (an Append), and the
230    /// previous commit at location 4 was pruned. `historical_proof(op_count=8, ...)` asks for the
231    /// state just before the first retained commit, which has no retained governing floor.
232    #[test_traced("INFO")]
233    fn test_keyless_historical_proof_floor_pruned() {
234        use crate::merkle::Location;
235        deterministic::Runner::default().start(|ctx| async move {
236            let mut db = open_db::<mmr::Family>(ctx.child("db")).await;
237
238            // Build commits at 0, 4, 8, 12, ... (3 appends + 1 commit per batch).
239            for batch_idx in 0u64..15 {
240                let mut batch = db.new_batch();
241                for j in 0..3 {
242                    batch =
243                        batch.append(<Vec<u8> as crate::qmdb::keyless::tests::TestValue>::make(
244                            batch_idx * 10 + j,
245                        ));
246                }
247                let new_commit_loc = Location::new(*db.last_commit_loc() + 1 + 3);
248                db.apply_batch(batch.merkleize(&db, None, new_commit_loc))
249                    .await
250                    .unwrap();
251            }
252
253            // Prune to loc=8: blob 0 ([0,7)) end=7 <= 8 -> pruned. bounds.start = 7, first retained
254            // commit is at 8.
255            db.prune(Location::new(8)).await.unwrap();
256            let bounds = db.bounds().await;
257            assert_eq!(*bounds.start, 7);
258
259            // op_count = first retained commit (= state just before that commit). Expected:
260            // HistoricalFloorPruned, NOT UnexpectedData.
261            let result = db
262                .historical_proof(Location::new(8), bounds.start, NZU64!(5))
263                .await;
264            assert!(
265                !matches!(result, Err(Error::UnexpectedData(_))),
266                "must not surface as UnexpectedData; got {result:?}",
267            );
268            assert!(
269                matches!(result, Err(Error::HistoricalFloorPruned(loc)) if loc == Location::new(8)),
270                "expected HistoricalFloorPruned(8), got {result:?}",
271            );
272
273            // Sanity: a commit-boundary size whose floor is retained still works. First retained
274            // commit at 8 declares some floor; op_count=9 is the post-commit size whose governing
275            // floor is the one declared at op 8.
276            db.historical_proof(Location::new(9), Location::new(8), NZU64!(1))
277                .await
278                .expect("commit-boundary historical_proof should succeed");
279
280            db.destroy().await.unwrap();
281        });
282    }
283
284    #[test_traced("WARN")]
285    fn test_keyless_db_empty_db_recovery() {
286        deterministic::Runner::default().start(|ctx| async move {
287            let db = open_db::<mmr::Family>(ctx.child("db").with_attribute("index", 1)).await;
288            tests::test_keyless_db_empty_db_recovery(ctx, db, reopen::<mmr::Family>()).await;
289        });
290    }
291
292    #[test_traced("WARN")]
293    fn test_keyless_db_replay_with_trailing_appends() {
294        deterministic::Runner::default().start(|ctx| async move {
295            let db = open_db::<mmr::Family>(ctx.child("db").with_attribute("index", 1)).await;
296            tests::test_keyless_db_replay_with_trailing_appends(ctx, db, reopen::<mmr::Family>())
297                .await;
298        });
299    }
300
301    #[test_traced("INFO")]
302    fn test_keyless_db_get_out_of_bounds() {
303        deterministic::Runner::default().start(|ctx| async move {
304            let db = open_db::<mmr::Family>(ctx.child("storage")).await;
305            tests::test_keyless_db_get_out_of_bounds(db).await;
306        });
307    }
308
309    #[test_traced("INFO")]
310    fn test_keyless_db_metadata() {
311        deterministic::Runner::default().start(|ctx| async move {
312            let db = open_db::<mmr::Family>(ctx.child("db")).await;
313            tests::test_keyless_db_metadata(db).await;
314        });
315    }
316
317    async fn assert_compact_root_compatibility<F: crate::merkle::Family>(
318        ctx: deterministic::Context,
319    ) {
320        let mut db = open_db::<F>(ctx.child("db")).await;
321        let mut compact = open_compact::<F>(ctx.child("compact")).await;
322        assert_eq!(db.root(), compact.root());
323
324        let v1 = b"hello".to_vec();
325        let v2 = b"world".to_vec();
326        let metadata = b"metadata".to_vec();
327
328        let floor = db.inactivity_floor_loc();
329        let retained = db
330            .new_batch()
331            .append(v1.clone())
332            .append(v2.clone())
333            .merkleize(&db, Some(metadata.clone()), floor);
334        let compact_batch = compact.new_batch().append(v1).append(v2).merkleize(
335            &compact,
336            Some(metadata.clone()),
337            floor,
338        );
339
340        assert_eq!(retained.root(), compact_batch.root());
341
342        db.apply_batch(retained).await.unwrap();
343        compact.apply_batch(compact_batch).unwrap();
344        db.commit().await.unwrap();
345        compact.commit().await.unwrap();
346
347        assert_eq!(db.root(), compact.root());
348        assert_eq!(compact.get_metadata(), Some(metadata.clone()));
349
350        drop(compact);
351        let reopened = open_compact::<F>(ctx.child("reopen")).await;
352        assert_eq!(db.root(), reopened.root());
353        assert_eq!(reopened.get_metadata(), Some(metadata));
354
355        reopened.destroy().await.unwrap();
356        db.destroy().await.unwrap();
357    }
358
359    #[test_traced("INFO")]
360    fn test_keyless_variable_compact_root_compatibility() {
361        deterministic::Runner::default().start(|ctx| async move {
362            assert_compact_root_compatibility::<mmr::Family>(ctx).await;
363        });
364    }
365
366    #[test_traced("INFO")]
367    fn test_keyless_variable_compact_root_compatibility_mmb() {
368        deterministic::Runner::default().start(|ctx| async move {
369            assert_compact_root_compatibility::<mmb::Family>(ctx).await;
370        });
371    }
372
373    #[test_traced("INFO")]
374    fn test_keyless_db_pruning() {
375        deterministic::Runner::default().start(|ctx| async move {
376            let db = open_db::<mmr::Family>(ctx.child("db")).await;
377            tests::test_keyless_db_pruning(db).await;
378        });
379    }
380
381    #[test_traced("INFO")]
382    fn test_keyless_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_batch_get(db).await;
386        });
387    }
388
389    #[test_traced("INFO")]
390    fn test_keyless_batch_stacked_get() {
391        deterministic::Runner::default().start(|ctx| async move {
392            let db = open_db::<mmr::Family>(ctx.child("db")).await;
393            tests::test_keyless_batch_stacked_get(db).await;
394        });
395    }
396
397    #[test_traced("INFO")]
398    fn test_keyless_batch_speculative_root() {
399        deterministic::Runner::default().start(|ctx| async move {
400            let db = open_db::<mmr::Family>(ctx.child("db")).await;
401            tests::test_keyless_batch_speculative_root(db).await;
402        });
403    }
404
405    #[test_traced("INFO")]
406    fn test_keyless_merkleized_batch_get() {
407        deterministic::Runner::default().start(|ctx| async move {
408            let db = open_db::<mmr::Family>(ctx.child("db")).await;
409            tests::test_keyless_merkleized_batch_get(db).await;
410        });
411    }
412
413    #[test_traced("INFO")]
414    fn test_keyless_get_many() {
415        deterministic::Runner::default().start(|ctx| async move {
416            let db = open_db::<mmr::Family>(ctx.child("db")).await;
417            tests::test_keyless_get_many(db).await;
418        });
419    }
420
421    #[test_traced("INFO")]
422    fn test_keyless_batch_chained() {
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(db).await;
426        });
427    }
428
429    #[test_traced("INFO")]
430    fn test_keyless_batch_chained_apply_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_chained_apply_sequential(db).await;
434        });
435    }
436
437    #[test_traced("INFO")]
438    fn test_keyless_batch_many_sequential() {
439        deterministic::Runner::default().start(|ctx| async move {
440            let db = open_db::<mmr::Family>(ctx.child("db")).await;
441            tests::test_keyless_batch_many_sequential(db).await;
442        });
443    }
444
445    #[test_traced("INFO")]
446    fn test_keyless_batch_empty() {
447        deterministic::Runner::default().start(|ctx| async move {
448            let db = open_db::<mmr::Family>(ctx.child("db")).await;
449            tests::test_keyless_batch_empty(db).await;
450        });
451    }
452
453    #[test_traced("INFO")]
454    fn test_keyless_batch_chained_merkleized_get() {
455        deterministic::Runner::default().start(|ctx| async move {
456            let db = open_db::<mmr::Family>(ctx.child("db")).await;
457            tests::test_keyless_batch_chained_merkleized_get(db).await;
458        });
459    }
460
461    #[test_traced("INFO")]
462    fn test_keyless_batch_large() {
463        deterministic::Runner::default().start(|ctx| async move {
464            let db = open_db::<mmr::Family>(ctx.child("db")).await;
465            tests::test_keyless_batch_large(db).await;
466        });
467    }
468
469    #[test_traced]
470    fn test_keyless_stale_batch() {
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(db).await;
474        });
475    }
476
477    #[test_traced]
478    fn test_stale_batch_chained() {
479        deterministic::Runner::default().start(|ctx| async move {
480            let db = open_db::<mmr::Family>(ctx.child("db")).await;
481            tests::test_keyless_stale_batch_chained(db).await;
482        });
483    }
484
485    #[test_traced]
486    fn test_sequential_commit_parent_then_child() {
487        deterministic::Runner::default().start(|ctx| async move {
488            let db = open_db::<mmr::Family>(ctx.child("db")).await;
489            tests::test_keyless_sequential_commit_parent_then_child(db).await;
490        });
491    }
492
493    #[test_traced]
494    fn test_stale_batch_child_applied_before_parent() {
495        deterministic::Runner::default().start(|ctx| async move {
496            let db = open_db::<mmr::Family>(ctx.child("db")).await;
497            tests::test_keyless_stale_batch_child_before_parent(db).await;
498        });
499    }
500
501    #[test_traced]
502    fn test_partial_ancestor_commit() {
503        deterministic::Runner::default().start(|ctx| async move {
504            let db = open_db::<mmr::Family>(ctx.child("db")).await;
505            tests::test_keyless_partial_ancestor_commit(db).await;
506        });
507    }
508
509    #[test_traced]
510    fn test_keyless_to_batch() {
511        deterministic::Runner::default().start(|ctx| async move {
512            let db = open_db::<mmr::Family>(ctx.child("db")).await;
513            tests::test_keyless_to_batch(db).await;
514        });
515    }
516
517    #[test_traced]
518    fn test_keyless_child_root_matches_pending_and_committed() {
519        deterministic::Runner::default().start(|ctx| async move {
520            let db = open_db::<mmr::Family>(ctx.child("db")).await;
521            tests::test_keyless_child_root_matches_pending_and_committed(db).await;
522        });
523    }
524
525    #[test_traced("INFO")]
526    fn test_keyless_rewind_recovery() {
527        deterministic::Runner::default().start(|ctx| async move {
528            let db = open_db::<mmr::Family>(ctx.child("db")).await;
529            tests::test_keyless_db_rewind_recovery(ctx, db, reopen::<mmr::Family>()).await;
530        });
531    }
532
533    #[test_traced("INFO")]
534    fn test_keyless_rewind_pruned_target_errors() {
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_pruned_target_errors(db).await;
538        });
539    }
540
541    // mmb::Family variants
542
543    #[test_traced("INFO")]
544    fn test_keyless_db_empty_mmb() {
545        deterministic::Runner::default().start(|ctx| async move {
546            let db = open_db::<mmb::Family>(ctx.child("db").with_attribute("index", 1)).await;
547            tests::test_keyless_db_empty(ctx, db, reopen::<mmb::Family>()).await;
548        });
549    }
550
551    #[test_traced("WARN")]
552    fn test_keyless_db_build_basic_mmb() {
553        deterministic::Runner::default().start(|ctx| async move {
554            let db = open_db::<mmb::Family>(ctx.child("db").with_attribute("index", 1)).await;
555            tests::test_keyless_db_build_basic(ctx, db, reopen::<mmb::Family>()).await;
556        });
557    }
558
559    #[test_traced("WARN")]
560    fn test_keyless_db_recovery_mmb() {
561        deterministic::Runner::default().start(|ctx| async move {
562            let db = open_db::<mmb::Family>(ctx.child("db").with_attribute("index", 1)).await;
563            tests::test_keyless_db_recovery(ctx, db, reopen::<mmb::Family>()).await;
564        });
565    }
566
567    #[test_traced("WARN")]
568    fn test_keyless_db_non_empty_recovery_mmb() {
569        deterministic::Runner::default().start(|ctx| async move {
570            let db = open_db::<mmb::Family>(ctx.child("db").with_attribute("index", 1)).await;
571            tests::test_keyless_db_non_empty_recovery(ctx, db, reopen::<mmb::Family>()).await;
572        });
573    }
574
575    #[test_traced("INFO")]
576    fn test_keyless_db_proof_mmb() {
577        deterministic::Runner::default().start(|ctx| async move {
578            let db = open_db::<mmb::Family>(ctx.child("storage")).await;
579            tests::test_keyless_db_proof(db).await;
580        });
581    }
582
583    #[test_traced("INFO")]
584    fn test_keyless_db_proof_comprehensive_mmb() {
585        deterministic::Runner::default().start(|ctx| async move {
586            let db = open_db::<mmb::Family>(ctx.child("storage")).await;
587            tests::test_keyless_db_proof_comprehensive(db).await;
588        });
589    }
590
591    #[test_traced("INFO")]
592    fn test_keyless_db_proof_with_pruning_mmb() {
593        deterministic::Runner::default().start(|ctx| async move {
594            let db = open_db::<mmb::Family>(ctx.child("db").with_attribute("index", 1)).await;
595            tests::test_keyless_db_proof_with_pruning(ctx, db, reopen::<mmb::Family>()).await;
596        });
597    }
598
599    #[test_traced("WARN")]
600    fn test_keyless_db_empty_db_recovery_mmb() {
601        deterministic::Runner::default().start(|ctx| async move {
602            let db = open_db::<mmb::Family>(ctx.child("db").with_attribute("index", 1)).await;
603            tests::test_keyless_db_empty_db_recovery(ctx, db, reopen::<mmb::Family>()).await;
604        });
605    }
606
607    #[test_traced("WARN")]
608    fn test_keyless_db_replay_with_trailing_appends_mmb() {
609        deterministic::Runner::default().start(|ctx| async move {
610            let db = open_db::<mmb::Family>(ctx.child("db").with_attribute("index", 1)).await;
611            tests::test_keyless_db_replay_with_trailing_appends(ctx, db, reopen::<mmb::Family>())
612                .await;
613        });
614    }
615
616    #[test_traced("INFO")]
617    fn test_keyless_db_get_out_of_bounds_mmb() {
618        deterministic::Runner::default().start(|ctx| async move {
619            let db = open_db::<mmb::Family>(ctx.child("storage")).await;
620            tests::test_keyless_db_get_out_of_bounds(db).await;
621        });
622    }
623
624    #[test_traced("INFO")]
625    fn test_keyless_db_metadata_mmb() {
626        deterministic::Runner::default().start(|ctx| async move {
627            let db = open_db::<mmb::Family>(ctx.child("db")).await;
628            tests::test_keyless_db_metadata(db).await;
629        });
630    }
631
632    #[test_traced("INFO")]
633    fn test_keyless_db_pruning_mmb() {
634        deterministic::Runner::default().start(|ctx| async move {
635            let db = open_db::<mmb::Family>(ctx.child("db")).await;
636            tests::test_keyless_db_pruning(db).await;
637        });
638    }
639
640    #[test_traced("INFO")]
641    fn test_keyless_batch_get_mmb() {
642        deterministic::Runner::default().start(|ctx| async move {
643            let db = open_db::<mmb::Family>(ctx.child("db")).await;
644            tests::test_keyless_batch_get(db).await;
645        });
646    }
647
648    #[test_traced("INFO")]
649    fn test_keyless_batch_stacked_get_mmb() {
650        deterministic::Runner::default().start(|ctx| async move {
651            let db = open_db::<mmb::Family>(ctx.child("db")).await;
652            tests::test_keyless_batch_stacked_get(db).await;
653        });
654    }
655
656    #[test_traced("INFO")]
657    fn test_keyless_batch_speculative_root_mmb() {
658        deterministic::Runner::default().start(|ctx| async move {
659            let db = open_db::<mmb::Family>(ctx.child("db")).await;
660            tests::test_keyless_batch_speculative_root(db).await;
661        });
662    }
663
664    #[test_traced("INFO")]
665    fn test_keyless_merkleized_batch_get_mmb() {
666        deterministic::Runner::default().start(|ctx| async move {
667            let db = open_db::<mmb::Family>(ctx.child("db")).await;
668            tests::test_keyless_merkleized_batch_get(db).await;
669        });
670    }
671
672    #[test_traced("INFO")]
673    fn test_keyless_batch_chained_mmb() {
674        deterministic::Runner::default().start(|ctx| async move {
675            let db = open_db::<mmb::Family>(ctx.child("db")).await;
676            tests::test_keyless_batch_chained(db).await;
677        });
678    }
679
680    #[test_traced("INFO")]
681    fn test_keyless_batch_chained_apply_sequential_mmb() {
682        deterministic::Runner::default().start(|ctx| async move {
683            let db = open_db::<mmb::Family>(ctx.child("db")).await;
684            tests::test_keyless_batch_chained_apply_sequential(db).await;
685        });
686    }
687
688    #[test_traced("INFO")]
689    fn test_keyless_batch_many_sequential_mmb() {
690        deterministic::Runner::default().start(|ctx| async move {
691            let db = open_db::<mmb::Family>(ctx.child("db")).await;
692            tests::test_keyless_batch_many_sequential(db).await;
693        });
694    }
695
696    #[test_traced("INFO")]
697    fn test_keyless_batch_empty_mmb() {
698        deterministic::Runner::default().start(|ctx| async move {
699            let db = open_db::<mmb::Family>(ctx.child("db")).await;
700            tests::test_keyless_batch_empty(db).await;
701        });
702    }
703
704    #[test_traced("INFO")]
705    fn test_keyless_batch_chained_merkleized_get_mmb() {
706        deterministic::Runner::default().start(|ctx| async move {
707            let db = open_db::<mmb::Family>(ctx.child("db")).await;
708            tests::test_keyless_batch_chained_merkleized_get(db).await;
709        });
710    }
711
712    #[test_traced("INFO")]
713    fn test_keyless_batch_large_mmb() {
714        deterministic::Runner::default().start(|ctx| async move {
715            let db = open_db::<mmb::Family>(ctx.child("db")).await;
716            tests::test_keyless_batch_large(db).await;
717        });
718    }
719
720    #[test_traced]
721    fn test_keyless_stale_batch_mmb() {
722        deterministic::Runner::default().start(|ctx| async move {
723            let db = open_db::<mmb::Family>(ctx.child("db")).await;
724            tests::test_keyless_stale_batch(db).await;
725        });
726    }
727
728    #[test_traced]
729    fn test_stale_batch_chained_mmb() {
730        deterministic::Runner::default().start(|ctx| async move {
731            let db = open_db::<mmb::Family>(ctx.child("db")).await;
732            tests::test_keyless_stale_batch_chained(db).await;
733        });
734    }
735
736    #[test_traced]
737    fn test_sequential_commit_parent_then_child_mmb() {
738        deterministic::Runner::default().start(|ctx| async move {
739            let db = open_db::<mmb::Family>(ctx.child("db")).await;
740            tests::test_keyless_sequential_commit_parent_then_child(db).await;
741        });
742    }
743
744    #[test_traced]
745    fn test_stale_batch_child_applied_before_parent_mmb() {
746        deterministic::Runner::default().start(|ctx| async move {
747            let db = open_db::<mmb::Family>(ctx.child("db")).await;
748            tests::test_keyless_stale_batch_child_before_parent(db).await;
749        });
750    }
751
752    #[test_traced]
753    fn test_keyless_to_batch_mmb() {
754        deterministic::Runner::default().start(|ctx| async move {
755            let db = open_db::<mmb::Family>(ctx.child("db")).await;
756            tests::test_keyless_to_batch(db).await;
757        });
758    }
759
760    #[test_traced]
761    fn test_keyless_child_root_matches_pending_and_committed_mmb() {
762        deterministic::Runner::default().start(|ctx| async move {
763            let db = open_db::<mmb::Family>(ctx.child("db")).await;
764            tests::test_keyless_child_root_matches_pending_and_committed(db).await;
765        });
766    }
767
768    #[test_traced("INFO")]
769    fn test_keyless_rewind_recovery_mmb() {
770        deterministic::Runner::default().start(|ctx| async move {
771            let db = open_db::<mmb::Family>(ctx.child("db")).await;
772            tests::test_keyless_db_rewind_recovery(ctx, db, reopen::<mmb::Family>()).await;
773        });
774    }
775
776    #[test_traced("INFO")]
777    fn test_keyless_rewind_pruned_target_errors_mmb() {
778        deterministic::Runner::default().start(|ctx| async move {
779            let db = open_db::<mmb::Family>(ctx.child("db")).await;
780            tests::test_keyless_db_rewind_pruned_target_errors(db).await;
781        });
782    }
783
784    #[test_traced("INFO")]
785    fn test_keyless_variable_floor_tracking_mmb() {
786        deterministic::Runner::default().start(|ctx| async move {
787            let db = open_db::<mmb::Family>(ctx.child("db").with_attribute("index", 1)).await;
788            tests::test_keyless_db_floor_tracking(ctx, db, reopen::<mmb::Family>()).await;
789        });
790    }
791
792    #[test_traced("INFO")]
793    fn test_keyless_variable_floor_regression_rejected_mmb() {
794        deterministic::Runner::default().start(|ctx| async move {
795            let db = open_db::<mmb::Family>(ctx.child("db")).await;
796            tests::test_keyless_db_floor_regression_rejected(db).await;
797        });
798    }
799
800    #[test_traced("INFO")]
801    fn test_keyless_variable_floor_beyond_commit_loc_rejected_mmb() {
802        deterministic::Runner::default().start(|ctx| async move {
803            let db = open_db::<mmb::Family>(ctx.child("db")).await;
804            tests::test_keyless_db_floor_beyond_commit_loc_rejected(db).await;
805        });
806    }
807
808    #[test_traced("INFO")]
809    fn test_keyless_variable_rewind_restores_floor_mmb() {
810        deterministic::Runner::default().start(|ctx| async move {
811            let db = open_db::<mmb::Family>(ctx.child("db")).await;
812            tests::test_keyless_db_rewind_restores_floor(db).await;
813        });
814    }
815
816    #[test_traced("INFO")]
817    fn test_keyless_variable_floor_changes_root_mmb() {
818        deterministic::Runner::default().start(|ctx| async move {
819            let db_a = open_db_with_suffix::<mmb::Family>("root-a", ctx.child("a")).await;
820            let db_b = open_db_with_suffix::<mmb::Family>("root-b", ctx.child("b")).await;
821            tests::test_keyless_db_floor_changes_root(db_a, db_b).await;
822        });
823    }
824
825    #[test_traced("INFO")]
826    fn test_keyless_variable_floor_at_commit_loc_accepted_mmb() {
827        deterministic::Runner::default().start(|ctx| async move {
828            let db = open_db::<mmb::Family>(ctx.child("db")).await;
829            tests::test_keyless_db_floor_at_commit_loc_accepted(db).await;
830        });
831    }
832
833    #[test_traced("INFO")]
834    fn test_keyless_variable_rewind_after_reopen_with_floor_mmb() {
835        deterministic::Runner::default().start(|ctx| async move {
836            let db = open_db::<mmb::Family>(ctx.child("db").with_attribute("index", 1)).await;
837            tests::test_keyless_db_rewind_after_reopen_with_floor(ctx, db, reopen::<mmb::Family>())
838                .await;
839        });
840    }
841
842    #[test_traced("INFO")]
843    fn test_keyless_variable_ancestor_floor_regression_rejected_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_ancestor_floor_regression_rejected(db).await;
847        });
848    }
849
850    #[test_traced("INFO")]
851    fn test_keyless_variable_ancestor_floor_beyond_commit_loc_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_ancestor_floor_beyond_commit_loc_rejected(db).await;
855        });
856    }
857
858    #[test_traced("INFO")]
859    fn test_keyless_variable_chained_apply_with_valid_floors_succeeds_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_chained_apply_with_valid_floors_succeeds(db).await;
863        });
864    }
865
866    #[test_traced("INFO")]
867    fn test_keyless_variable_single_commit_live_set_mmb() {
868        deterministic::Runner::default().start(|ctx| async move {
869            let db = open_db::<mmb::Family>(ctx.child("db").with_attribute("index", 1)).await;
870            tests::test_keyless_db_single_commit_live_set(ctx, db, reopen::<mmb::Family>()).await;
871        });
872    }
873
874    #[test_traced("INFO")]
875    fn test_keyless_variable_floor_tracking() {
876        deterministic::Runner::default().start(|ctx| async move {
877            let db = open_db::<mmr::Family>(ctx.child("db").with_attribute("index", 1)).await;
878            tests::test_keyless_db_floor_tracking(ctx, db, reopen::<mmr::Family>()).await;
879        });
880    }
881
882    #[test_traced("INFO")]
883    fn test_keyless_variable_floor_regression_rejected() {
884        deterministic::Runner::default().start(|ctx| async move {
885            let db = open_db::<mmr::Family>(ctx.child("db")).await;
886            tests::test_keyless_db_floor_regression_rejected(db).await;
887        });
888    }
889
890    #[test_traced("INFO")]
891    fn test_keyless_variable_floor_beyond_commit_loc_rejected() {
892        deterministic::Runner::default().start(|ctx| async move {
893            let db = open_db::<mmr::Family>(ctx.child("db")).await;
894            tests::test_keyless_db_floor_beyond_commit_loc_rejected(db).await;
895        });
896    }
897
898    #[test_traced("INFO")]
899    fn test_keyless_variable_rewind_restores_floor() {
900        deterministic::Runner::default().start(|ctx| async move {
901            let db = open_db::<mmr::Family>(ctx.child("db")).await;
902            tests::test_keyless_db_rewind_restores_floor(db).await;
903        });
904    }
905
906    #[test_traced("INFO")]
907    fn test_keyless_variable_floor_changes_root() {
908        deterministic::Runner::default().start(|ctx| async move {
909            let db_a = open_db_with_suffix::<mmr::Family>("root-a", ctx.child("a")).await;
910            let db_b = open_db_with_suffix::<mmr::Family>("root-b", ctx.child("b")).await;
911            tests::test_keyless_db_floor_changes_root(db_a, db_b).await;
912        });
913    }
914
915    #[test_traced("INFO")]
916    fn test_keyless_variable_floor_at_commit_loc_accepted() {
917        deterministic::Runner::default().start(|ctx| async move {
918            let db = open_db::<mmr::Family>(ctx.child("db")).await;
919            tests::test_keyless_db_floor_at_commit_loc_accepted(db).await;
920        });
921    }
922
923    #[test_traced("INFO")]
924    fn test_keyless_variable_rewind_after_reopen_with_floor() {
925        deterministic::Runner::default().start(|ctx| async move {
926            let db = open_db::<mmr::Family>(ctx.child("db").with_attribute("index", 1)).await;
927            tests::test_keyless_db_rewind_after_reopen_with_floor(ctx, db, reopen::<mmr::Family>())
928                .await;
929        });
930    }
931
932    #[test_traced("INFO")]
933    fn test_keyless_variable_ancestor_floor_regression_rejected() {
934        deterministic::Runner::default().start(|ctx| async move {
935            let db = open_db::<mmr::Family>(ctx.child("db")).await;
936            tests::test_keyless_db_ancestor_floor_regression_rejected(db).await;
937        });
938    }
939
940    #[test_traced("INFO")]
941    fn test_keyless_variable_ancestor_floor_beyond_commit_loc_rejected() {
942        deterministic::Runner::default().start(|ctx| async move {
943            let db = open_db::<mmr::Family>(ctx.child("db")).await;
944            tests::test_keyless_db_ancestor_floor_beyond_commit_loc_rejected(db).await;
945        });
946    }
947
948    #[test_traced("INFO")]
949    fn test_keyless_variable_chained_apply_with_valid_floors_succeeds() {
950        deterministic::Runner::default().start(|ctx| async move {
951            let db = open_db::<mmr::Family>(ctx.child("db")).await;
952            tests::test_keyless_db_chained_apply_with_valid_floors_succeeds(db).await;
953        });
954    }
955
956    #[test_traced("INFO")]
957    fn test_keyless_variable_single_commit_live_set() {
958        deterministic::Runner::default().start(|ctx| async move {
959            let db = open_db::<mmr::Family>(ctx.child("db").with_attribute("index", 1)).await;
960            tests::test_keyless_db_single_commit_live_set(ctx, db, reopen::<mmr::Family>()).await;
961        });
962    }
963
964    fn is_send<T: Send>(_: T) {}
965
966    #[allow(dead_code)]
967    fn assert_db_futures_are_send(
968        db: &mut TestDb<mmr::Family>,
969        loc: crate::merkle::Location<mmr::Family>,
970    ) {
971        is_send(db.get_metadata());
972        is_send(db.proof(loc, NZU64!(1)));
973        is_send(db.sync());
974        is_send(db.get(loc));
975        is_send(db.rewind(loc));
976    }
977}