Skip to main content

commonware_storage/qmdb/immutable/
variable.rs

1//! An immutable authenticated database with variable-size values.
2//!
3//! For fixed-size values, use [super::fixed] instead.
4
5use super::{operation::Operation as BaseOperation, Config as BaseConfig, Immutable};
6use crate::{
7    journal::{
8        authenticated,
9        contiguous::variable::{self, Config as JournalConfig},
10    },
11    merkle::Family,
12    qmdb::{
13        any::{value::VariableEncoding, VariableValue},
14        operation::Key,
15        Error, ROOT_BAGGING,
16    },
17    translator::Translator,
18    Context,
19};
20use commonware_codec::Read;
21use commonware_cryptography::Hasher;
22use commonware_parallel::Strategy;
23
24/// Type alias for a variable-size operation.
25pub type Operation<F, K, V> = BaseOperation<F, K, VariableEncoding<V>>;
26
27/// Type alias for the variable-size immutable database.
28pub type Db<F, E, K, V, H, T, S> =
29    Immutable<F, E, K, VariableEncoding<V>, variable::Journal<E, Operation<F, K, V>>, H, T, S>;
30
31/// Type alias for the variable-size compact immutable db.
32pub type CompactDb<F, E, K, V, H, C, S> = super::CompactDb<F, E, K, VariableEncoding<V>, H, C, S>;
33
34type Journal<F, E, K, V, H, S> =
35    authenticated::Journal<F, E, variable::Journal<E, Operation<F, K, V>>, H, S>;
36
37/// Configuration for a variable-size immutable authenticated db.
38pub type Config<T, C, S> = BaseConfig<T, JournalConfig<C>, S>;
39
40/// Configuration for a variable-size compact immutable db.
41pub type CompactConfig<C, S> = super::CompactConfig<C, S>;
42
43impl<F: Family, E: Context, K: Key, V: VariableValue, H: Hasher, T: Translator, S: Strategy>
44    Db<F, E, K, V, H, T, S>
45{
46    /// Returns a [Db] initialized from `cfg`. Any uncommitted log operations will be
47    /// discarded and the state of the db will be as of the last committed operation.
48    pub async fn init(
49        context: E,
50        cfg: Config<T, <Operation<F, K, V> as Read>::Cfg, S>,
51    ) -> Result<Self, Error<F>> {
52        let journal: Journal<F, E, K, V, H, S> = Journal::new(
53            context.child("journal"),
54            cfg.merkle_config,
55            cfg.log,
56            Operation::<F, K, V>::is_commit,
57            ROOT_BAGGING,
58        )
59        .await?;
60        Self::init_from_journal(journal, context, cfg.translator, cfg.init_cache_size).await
61    }
62}
63
64impl<
65        F: Family,
66        E: Context,
67        K: Key,
68        V: VariableValue,
69        H: Hasher,
70        C: Clone + Send + Sync + 'static,
71        S: Strategy,
72    > CompactDb<F, E, K, V, H, C, S>
73where
74    Operation<F, K, V>: Read<Cfg = C>,
75{
76    /// Returns a [CompactDb] initialized from `cfg`.
77    pub async fn init(context: E, cfg: CompactConfig<C, S>) -> Result<Self, Error<F>> {
78        let merkle = crate::merkle::compact::Merkle::new(cfg.strategy);
79        Self::init_from_merkle(
80            merkle,
81            context.child("witness"),
82            cfg.witness,
83            cfg.commit_codec_config,
84        )
85        .await
86    }
87}
88
89#[cfg(test)]
90mod tests {
91    use super::*;
92    use crate::{
93        journal::contiguous::variable::Config as JournalConfig,
94        merkle::{full::Config as MmrConfig, mmb, mmr},
95        qmdb::immutable::test,
96        translator::TwoCap,
97    };
98    use commonware_cryptography::{sha256::Digest, Sha256};
99    use commonware_macros::{boxed, test_traced};
100    use commonware_parallel::Sequential;
101    use commonware_runtime::{
102        buffer::paged::CacheRef, deterministic, BufferPooler, Runner as _, Supervisor as _,
103    };
104    use commonware_utils::{NZUsize, NZU16, NZU64};
105    use core::{future::Future, pin::Pin};
106    use std::num::{NonZeroU16, NonZeroUsize};
107
108    const PAGE_SIZE: NonZeroU16 = NZU16!(77);
109    const PAGE_CACHE_SIZE: NonZeroUsize = NZUsize!(9);
110
111    fn config(suffix: &str, pooler: &impl BufferPooler) -> Config<TwoCap, ((), ()), Sequential> {
112        let page_cache = CacheRef::from_pooler(pooler, PAGE_SIZE, PAGE_CACHE_SIZE);
113        super::BaseConfig {
114            merkle_config: MmrConfig {
115                journal_partition: format!("journal-{suffix}"),
116                metadata_partition: format!("metadata-{suffix}"),
117                items_per_blob: NZU64!(11),
118                write_buffer: NZUsize!(1024),
119                strategy: Sequential,
120                page_cache: page_cache.clone(),
121            },
122            log: JournalConfig {
123                partition: format!("log-{suffix}"),
124                items_per_section: NZU64!(5),
125                compression: None,
126                codec_config: ((), ()),
127                page_cache,
128                write_buffer: NZUsize!(1024),
129            },
130            translator: TwoCap,
131            init_cache_size: Some(NZUsize!(1024)),
132        }
133    }
134
135    async fn open_db<F: Family>(
136        context: deterministic::Context,
137    ) -> Db<F, deterministic::Context, Digest, Digest, Sha256, TwoCap, Sequential> {
138        let cfg = config("partition", &context);
139        Db::init(context, cfg).await.unwrap()
140    }
141
142    async fn open_compact<F: Family>(
143        context: deterministic::Context,
144    ) -> CompactDb<F, deterministic::Context, Digest, Digest, Sha256, ((), ()), Sequential> {
145        let cfg = CompactConfig {
146            strategy: Sequential,
147            witness: crate::journal::contiguous::variable::Config {
148                partition: "compact-immutable-variable-witness".into(),
149                items_per_section: NZU64!(64),
150                compression: None,
151                codec_config: (),
152                page_cache: CacheRef::from_pooler(&context, PAGE_SIZE, PAGE_CACHE_SIZE),
153                write_buffer: NZUsize!(1024),
154            },
155            commit_codec_config: ((), ()),
156        };
157        CompactDb::init(context, cfg).await.unwrap()
158    }
159
160    #[allow(clippy::type_complexity)]
161    fn open<F: Family>(
162        ctx: deterministic::Context,
163    ) -> Pin<
164        Box<
165            dyn Future<
166                    Output = Db<
167                        F,
168                        deterministic::Context,
169                        Digest,
170                        Digest,
171                        Sha256,
172                        TwoCap,
173                        Sequential,
174                    >,
175                > + Send,
176        >,
177    > {
178        Box::pin(open_db::<F>(ctx))
179    }
180
181    fn is_send<T: Send>(_: T) {}
182
183    #[allow(dead_code)]
184    fn assert_db_futures_are_send(
185        db: &mut Db<
186            mmr::Family,
187            deterministic::Context,
188            Digest,
189            Digest,
190            Sha256,
191            TwoCap,
192            Sequential,
193        >,
194        key: Digest,
195        loc: crate::merkle::mmr::Location,
196    ) {
197        is_send(db.get(&key));
198        is_send(db.get_metadata());
199        is_send(db.proof(loc, NZU64!(1)));
200        is_send(db.sync());
201        is_send(db.rewind(loc));
202    }
203
204    fn small_sections_config(
205        suffix: &str,
206        pooler: &impl BufferPooler,
207    ) -> Config<TwoCap, ((), ()), Sequential> {
208        let mut cfg = config(suffix, pooler);
209        cfg.log.items_per_section = NZU64!(1);
210        cfg
211    }
212
213    async fn open_small_sections_db<F: Family>(
214        context: deterministic::Context,
215    ) -> Db<F, deterministic::Context, Digest, Digest, Sha256, TwoCap, Sequential> {
216        let cfg = small_sections_config("partition", &context);
217        Db::init(context, cfg).await.unwrap()
218    }
219
220    #[allow(clippy::type_complexity)]
221    fn open_small_sections<F: Family>(
222        ctx: deterministic::Context,
223    ) -> Pin<
224        Box<
225            dyn Future<
226                    Output = Db<
227                        F,
228                        deterministic::Context,
229                        Digest,
230                        Digest,
231                        Sha256,
232                        TwoCap,
233                        Sequential,
234                    >,
235                > + Send,
236        >,
237    > {
238        Box::pin(open_small_sections_db::<F>(ctx))
239    }
240
241    #[test_traced("WARN")]
242    fn test_variable_empty() {
243        let executor = deterministic::Runner::default();
244        executor.start(|ctx| async move {
245            test::test_immutable_empty(ctx, open::<mmr::Family>).await;
246        });
247    }
248
249    #[test_traced("WARN")]
250    fn test_variable_commit_after_sync_recovery() {
251        let executor = deterministic::Runner::default();
252        executor.start(|ctx| async move {
253            test::test_immutable_commit_after_sync_recovery(ctx, open::<mmr::Family>).await;
254        });
255    }
256
257    #[test_traced("DEBUG")]
258    fn test_variable_build_basic() {
259        let executor = deterministic::Runner::default();
260        executor.start(|ctx| async move {
261            test::test_immutable_build_basic(ctx, open::<mmr::Family>).await;
262        });
263    }
264
265    #[test_traced("WARN")]
266    fn test_variable_proof_verify() {
267        let executor = deterministic::Runner::default();
268        executor.start(|ctx| async move {
269            test::test_immutable_proof_verify(ctx, open::<mmr::Family>).await;
270        });
271    }
272
273    #[test_traced("DEBUG")]
274    fn test_variable_prune() {
275        let executor = deterministic::Runner::default();
276        executor.start(|ctx| async move {
277            test::test_immutable_prune(ctx, open::<mmr::Family>).await;
278        });
279    }
280
281    #[test_traced("DEBUG")]
282    fn test_variable_batch_chain() {
283        let executor = deterministic::Runner::default();
284        executor.start(|ctx| async move {
285            test::test_immutable_batch_chain(ctx, open::<mmr::Family>).await;
286        });
287    }
288
289    #[test_traced("WARN")]
290    fn test_variable_build_and_authenticate() {
291        let executor = deterministic::Runner::default();
292        executor.start(|ctx| async move {
293            test::test_immutable_build_and_authenticate(ctx, open::<mmr::Family>).await;
294        });
295    }
296
297    #[test_traced("WARN")]
298    fn test_variable_recovery_from_failed_merkle_sync() {
299        let executor = deterministic::Runner::default();
300        executor.start(|ctx| async move {
301            test::test_immutable_recovery_from_failed_merkle_sync(ctx, open::<mmr::Family>).await;
302        });
303    }
304
305    #[test_traced("WARN")]
306    fn test_variable_recovery_from_failed_log_sync() {
307        let executor = deterministic::Runner::default();
308        executor.start(|ctx| async move {
309            test::test_immutable_recovery_from_failed_log_sync(ctx, open::<mmr::Family>).await;
310        });
311    }
312
313    #[test_traced("WARN")]
314    fn test_variable_pruning() {
315        let executor = deterministic::Runner::default();
316        executor.start(|ctx| async move {
317            test::test_immutable_pruning(ctx, open::<mmr::Family>).await;
318        });
319    }
320
321    #[test_traced("INFO")]
322    fn test_variable_prune_beyond_floor() {
323        let executor = deterministic::Runner::default();
324        executor.start(|ctx| async move {
325            test::test_immutable_prune_beyond_floor(ctx, open::<mmr::Family>).await;
326        });
327    }
328
329    #[boxed]
330    async fn assert_compact_root_compatibility<F: Family>(ctx: deterministic::Context) {
331        let mut db = open_db::<F>(ctx.child("db")).await;
332        let mut compact = open_compact::<F>(ctx.child("compact")).await;
333        assert_eq!(db.root(), compact.root());
334
335        let k1 = Sha256::fill(1u8);
336        let v1 = Sha256::fill(11u8);
337        let k2 = Sha256::fill(2u8);
338        let v2 = Sha256::fill(22u8);
339        let metadata = Sha256::fill(99u8);
340
341        let floor = db.inactivity_floor_loc();
342        let retained = db
343            .new_batch()
344            .set(k1, v1)
345            .set(k2, v2)
346            .merkleize(&db, Some(metadata), floor)
347            .await;
348        let compact_batch = compact
349            .new_batch()
350            .set(k1, v1)
351            .set(k2, v2)
352            .merkleize(&compact, Some(metadata), floor)
353            .await;
354
355        assert_eq!(retained.root(), compact_batch.root());
356
357        db.apply_batch(retained).await.unwrap();
358        compact.apply_batch(compact_batch).unwrap();
359        db.commit().await.unwrap();
360        compact.sync().await.unwrap();
361
362        assert_eq!(db.root(), compact.root());
363        assert_eq!(compact.get_metadata(), Some(metadata));
364
365        drop(compact);
366        let reopened = open_compact::<F>(ctx.child("reopen")).await;
367        assert_eq!(db.root(), reopened.root());
368        assert_eq!(reopened.get_metadata(), Some(metadata));
369
370        reopened.destroy().await.unwrap();
371        db.destroy().await.unwrap();
372    }
373
374    #[test_traced("INFO")]
375    fn test_variable_compact_root_compatibility() {
376        let executor = deterministic::Runner::default();
377        executor.start(|ctx| async move {
378            assert_compact_root_compatibility::<mmr::Family>(ctx).await;
379        });
380    }
381
382    #[test_traced("INFO")]
383    fn test_variable_compact_root_compatibility_mmb() {
384        let executor = deterministic::Runner::default();
385        executor.start(|ctx| async move {
386            assert_compact_root_compatibility::<mmb::Family>(ctx).await;
387        });
388    }
389
390    #[test_traced("INFO")]
391    fn test_variable_batch_get_read_through() {
392        let executor = deterministic::Runner::default();
393        executor.start(|ctx| async move {
394            test::test_immutable_batch_get_read_through(ctx, open::<mmr::Family>).await;
395        });
396    }
397
398    #[test_traced("INFO")]
399    fn test_variable_batch_stacked_get() {
400        let executor = deterministic::Runner::default();
401        executor.start(|ctx| async move {
402            test::test_immutable_batch_stacked_get(ctx, open::<mmr::Family>).await;
403        });
404    }
405
406    #[test_traced("INFO")]
407    fn test_variable_batch_stacked_apply() {
408        let executor = deterministic::Runner::default();
409        executor.start(|ctx| async move {
410            test::test_immutable_batch_stacked_apply(ctx, open::<mmr::Family>).await;
411        });
412    }
413
414    #[test_traced("INFO")]
415    fn test_variable_batch_speculative_root() {
416        let executor = deterministic::Runner::default();
417        executor.start(|ctx| async move {
418            test::test_immutable_batch_speculative_root(ctx, open::<mmr::Family>).await;
419        });
420    }
421
422    #[test_traced("INFO")]
423    fn test_variable_merkleized_batch_get() {
424        let executor = deterministic::Runner::default();
425        executor.start(|ctx| async move {
426            test::test_immutable_merkleized_batch_get(ctx, open::<mmr::Family>).await;
427        });
428    }
429
430    #[test_traced("INFO")]
431    fn test_variable_batch_sequential_apply() {
432        let executor = deterministic::Runner::default();
433        executor.start(|ctx| async move {
434            test::test_immutable_batch_sequential_apply(ctx, open::<mmr::Family>).await;
435        });
436    }
437
438    #[test_traced("INFO")]
439    fn test_variable_batch_many_sequential() {
440        let executor = deterministic::Runner::default();
441        executor.start(|ctx| async move {
442            test::test_immutable_batch_many_sequential(ctx, open::<mmr::Family>).await;
443        });
444    }
445
446    #[test_traced("INFO")]
447    fn test_variable_batch_empty_batch() {
448        let executor = deterministic::Runner::default();
449        executor.start(|ctx| async move {
450            test::test_immutable_batch_empty_batch(ctx, open::<mmr::Family>).await;
451        });
452    }
453
454    #[test_traced("INFO")]
455    fn test_variable_batch_chained_merkleized_get() {
456        let executor = deterministic::Runner::default();
457        executor.start(|ctx| async move {
458            test::test_immutable_batch_chained_merkleized_get(ctx, open::<mmr::Family>).await;
459        });
460    }
461
462    #[test_traced("INFO")]
463    fn test_variable_batch_large() {
464        let executor = deterministic::Runner::default();
465        executor.start(|ctx| async move {
466            test::test_immutable_batch_large(ctx, open::<mmr::Family>).await;
467        });
468    }
469
470    #[test_traced("INFO")]
471    fn test_variable_batch_chained_key_override() {
472        let executor = deterministic::Runner::default();
473        executor.start(|ctx| async move {
474            test::test_immutable_batch_chained_key_override(ctx, open::<mmr::Family>).await;
475        });
476    }
477
478    #[test_traced("INFO")]
479    fn test_variable_batch_sequential_key_override() {
480        let executor = deterministic::Runner::default();
481        executor.start(|ctx| async move {
482            test::test_immutable_batch_sequential_key_override(
483                ctx,
484                open_small_sections::<mmr::Family>,
485            )
486            .await;
487        });
488    }
489
490    #[test_traced("INFO")]
491    fn test_variable_batch_metadata() {
492        let executor = deterministic::Runner::default();
493        executor.start(|ctx| async move {
494            test::test_immutable_batch_metadata(ctx, open::<mmr::Family>).await;
495        });
496    }
497
498    #[test_traced]
499    fn test_variable_stale_batch_rejected() {
500        let executor = deterministic::Runner::default();
501        executor.start(|ctx| async move {
502            test::test_immutable_stale_batch_rejected(ctx, open::<mmr::Family>).await;
503        });
504    }
505
506    #[test_traced]
507    fn test_variable_stale_batch_chained() {
508        let executor = deterministic::Runner::default();
509        executor.start(|ctx| async move {
510            test::test_immutable_stale_batch_chained(ctx, open::<mmr::Family>).await;
511        });
512    }
513
514    #[test_traced]
515    fn test_variable_sequential_commit_parent_then_child() {
516        let executor = deterministic::Runner::default();
517        executor.start(|ctx| async move {
518            test::test_immutable_sequential_commit_parent_then_child(ctx, open::<mmr::Family>)
519                .await;
520        });
521    }
522
523    #[test_traced]
524    fn test_variable_stale_batch_child_applied_before_parent() {
525        let executor = deterministic::Runner::default();
526        executor.start(|ctx| async move {
527            test::test_immutable_stale_batch_child_applied_before_parent(ctx, open::<mmr::Family>)
528                .await;
529        });
530    }
531
532    #[test_traced]
533    fn test_variable_partial_ancestor_commit() {
534        let executor = deterministic::Runner::default();
535        executor.start(|ctx| async move {
536            test::test_immutable_partial_ancestor_commit(ctx, open::<mmr::Family>).await;
537        });
538    }
539
540    #[test_traced]
541    fn test_variable_child_root_matches_pending_and_committed() {
542        let executor = deterministic::Runner::default();
543        executor.start(|ctx| async move {
544            test::test_immutable_child_root_matches_pending_and_committed(ctx, open::<mmr::Family>)
545                .await;
546        });
547    }
548
549    #[test_traced]
550    fn test_variable_to_batch() {
551        let executor = deterministic::Runner::default();
552        executor.start(|ctx| async move {
553            test::test_immutable_to_batch(ctx, open::<mmr::Family>).await;
554        });
555    }
556
557    #[test_traced("INFO")]
558    fn test_variable_rewind_recovery() {
559        let executor = deterministic::Runner::default();
560        executor.start(|ctx| async move {
561            test::test_immutable_rewind_recovery(ctx, open::<mmr::Family>).await;
562        });
563    }
564
565    #[test_traced("INFO")]
566    fn test_variable_rewind_pruned_target_errors() {
567        let executor = deterministic::Runner::default();
568        executor.start(|ctx| async move {
569            test::test_immutable_rewind_pruned_target_errors(
570                ctx,
571                open_small_sections::<mmr::Family>,
572            )
573            .await;
574        });
575    }
576
577    #[test_traced("INFO")]
578    fn test_variable_get_many() {
579        let executor = deterministic::Runner::default();
580        executor.start(|ctx| async move {
581            test::test_immutable_get_many(ctx, open::<mmr::Family>).await;
582        });
583    }
584
585    #[test_traced("INFO")]
586    fn test_variable_get_many_unexpected_data() {
587        let executor = deterministic::Runner::default();
588        executor.start(|ctx| async move {
589            test::test_immutable_get_many_unexpected_data(ctx, open::<mmr::Family>).await;
590        });
591    }
592
593    // -- MMB test wrappers --
594
595    #[test_traced("WARN")]
596    fn test_variable_empty_mmb() {
597        let executor = deterministic::Runner::default();
598        executor.start(|ctx| async move {
599            test::test_immutable_empty(ctx, open::<mmb::Family>).await;
600        });
601    }
602
603    #[test_traced("DEBUG")]
604    fn test_variable_build_basic_mmb() {
605        let executor = deterministic::Runner::default();
606        executor.start(|ctx| async move {
607            test::test_immutable_build_basic(ctx, open::<mmb::Family>).await;
608        });
609    }
610
611    #[test_traced("WARN")]
612    fn test_variable_proof_verify_mmb() {
613        let executor = deterministic::Runner::default();
614        executor.start(|ctx| async move {
615            test::test_immutable_proof_verify(ctx, open::<mmb::Family>).await;
616        });
617    }
618
619    #[test_traced("DEBUG")]
620    fn test_variable_prune_mmb() {
621        let executor = deterministic::Runner::default();
622        executor.start(|ctx| async move {
623            test::test_immutable_prune(ctx, open::<mmb::Family>).await;
624        });
625    }
626
627    #[test_traced("DEBUG")]
628    fn test_variable_batch_chain_mmb() {
629        let executor = deterministic::Runner::default();
630        executor.start(|ctx| async move {
631            test::test_immutable_batch_chain(ctx, open::<mmb::Family>).await;
632        });
633    }
634
635    #[test_traced("WARN")]
636    fn test_variable_build_and_authenticate_mmb() {
637        let executor = deterministic::Runner::default();
638        executor.start(|ctx| async move {
639            test::test_immutable_build_and_authenticate(ctx, open::<mmb::Family>).await;
640        });
641    }
642
643    #[test_traced("WARN")]
644    fn test_variable_recovery_from_failed_merkle_sync_mmb() {
645        let executor = deterministic::Runner::default();
646        executor.start(|ctx| async move {
647            test::test_immutable_recovery_from_failed_merkle_sync(ctx, open::<mmb::Family>).await;
648        });
649    }
650
651    #[test_traced("WARN")]
652    fn test_variable_recovery_from_failed_log_sync_mmb() {
653        let executor = deterministic::Runner::default();
654        executor.start(|ctx| async move {
655            test::test_immutable_recovery_from_failed_log_sync(ctx, open::<mmb::Family>).await;
656        });
657    }
658
659    #[test_traced("WARN")]
660    fn test_variable_pruning_mmb() {
661        let executor = deterministic::Runner::default();
662        executor.start(|ctx| async move {
663            test::test_immutable_pruning(ctx, open::<mmb::Family>).await;
664        });
665    }
666
667    #[test_traced("INFO")]
668    fn test_variable_prune_beyond_floor_mmb() {
669        let executor = deterministic::Runner::default();
670        executor.start(|ctx| async move {
671            test::test_immutable_prune_beyond_floor(ctx, open::<mmb::Family>).await;
672        });
673    }
674
675    #[test_traced("INFO")]
676    fn test_variable_batch_get_read_through_mmb() {
677        let executor = deterministic::Runner::default();
678        executor.start(|ctx| async move {
679            test::test_immutable_batch_get_read_through(ctx, open::<mmb::Family>).await;
680        });
681    }
682
683    #[test_traced("INFO")]
684    fn test_variable_batch_stacked_get_mmb() {
685        let executor = deterministic::Runner::default();
686        executor.start(|ctx| async move {
687            test::test_immutable_batch_stacked_get(ctx, open::<mmb::Family>).await;
688        });
689    }
690
691    #[test_traced("INFO")]
692    fn test_variable_batch_stacked_apply_mmb() {
693        let executor = deterministic::Runner::default();
694        executor.start(|ctx| async move {
695            test::test_immutable_batch_stacked_apply(ctx, open::<mmb::Family>).await;
696        });
697    }
698
699    #[test_traced("INFO")]
700    fn test_variable_batch_speculative_root_mmb() {
701        let executor = deterministic::Runner::default();
702        executor.start(|ctx| async move {
703            test::test_immutable_batch_speculative_root(ctx, open::<mmb::Family>).await;
704        });
705    }
706
707    #[test_traced("INFO")]
708    fn test_variable_merkleized_batch_get_mmb() {
709        let executor = deterministic::Runner::default();
710        executor.start(|ctx| async move {
711            test::test_immutable_merkleized_batch_get(ctx, open::<mmb::Family>).await;
712        });
713    }
714
715    #[test_traced("INFO")]
716    fn test_variable_batch_sequential_apply_mmb() {
717        let executor = deterministic::Runner::default();
718        executor.start(|ctx| async move {
719            test::test_immutable_batch_sequential_apply(ctx, open::<mmb::Family>).await;
720        });
721    }
722
723    #[test_traced("INFO")]
724    fn test_variable_batch_many_sequential_mmb() {
725        let executor = deterministic::Runner::default();
726        executor.start(|ctx| async move {
727            test::test_immutable_batch_many_sequential(ctx, open::<mmb::Family>).await;
728        });
729    }
730
731    #[test_traced("INFO")]
732    fn test_variable_batch_empty_batch_mmb() {
733        let executor = deterministic::Runner::default();
734        executor.start(|ctx| async move {
735            test::test_immutable_batch_empty_batch(ctx, open::<mmb::Family>).await;
736        });
737    }
738
739    #[test_traced("INFO")]
740    fn test_variable_batch_chained_merkleized_get_mmb() {
741        let executor = deterministic::Runner::default();
742        executor.start(|ctx| async move {
743            test::test_immutable_batch_chained_merkleized_get(ctx, open::<mmb::Family>).await;
744        });
745    }
746
747    #[test_traced("INFO")]
748    fn test_variable_batch_large_mmb() {
749        let executor = deterministic::Runner::default();
750        executor.start(|ctx| async move {
751            test::test_immutable_batch_large(ctx, open::<mmb::Family>).await;
752        });
753    }
754
755    #[test_traced("INFO")]
756    fn test_variable_batch_chained_key_override_mmb() {
757        let executor = deterministic::Runner::default();
758        executor.start(|ctx| async move {
759            test::test_immutable_batch_chained_key_override(ctx, open::<mmb::Family>).await;
760        });
761    }
762
763    #[test_traced("INFO")]
764    fn test_variable_batch_sequential_key_override_mmb() {
765        let executor = deterministic::Runner::default();
766        executor.start(|ctx| async move {
767            test::test_immutable_batch_sequential_key_override(
768                ctx,
769                open_small_sections::<mmb::Family>,
770            )
771            .await;
772        });
773    }
774
775    #[test_traced("INFO")]
776    fn test_variable_batch_metadata_mmb() {
777        let executor = deterministic::Runner::default();
778        executor.start(|ctx| async move {
779            test::test_immutable_batch_metadata(ctx, open::<mmb::Family>).await;
780        });
781    }
782
783    #[test_traced]
784    fn test_variable_stale_batch_rejected_mmb() {
785        let executor = deterministic::Runner::default();
786        executor.start(|ctx| async move {
787            test::test_immutable_stale_batch_rejected(ctx, open::<mmb::Family>).await;
788        });
789    }
790
791    #[test_traced]
792    fn test_variable_stale_batch_chained_mmb() {
793        let executor = deterministic::Runner::default();
794        executor.start(|ctx| async move {
795            test::test_immutable_stale_batch_chained(ctx, open::<mmb::Family>).await;
796        });
797    }
798
799    #[test_traced]
800    fn test_variable_sequential_commit_parent_then_child_mmb() {
801        let executor = deterministic::Runner::default();
802        executor.start(|ctx| async move {
803            test::test_immutable_sequential_commit_parent_then_child(ctx, open::<mmb::Family>)
804                .await;
805        });
806    }
807
808    #[test_traced]
809    fn test_variable_stale_batch_child_applied_before_parent_mmb() {
810        let executor = deterministic::Runner::default();
811        executor.start(|ctx| async move {
812            test::test_immutable_stale_batch_child_applied_before_parent(ctx, open::<mmb::Family>)
813                .await;
814        });
815    }
816
817    #[test_traced]
818    fn test_variable_child_root_matches_pending_and_committed_mmb() {
819        let executor = deterministic::Runner::default();
820        executor.start(|ctx| async move {
821            test::test_immutable_child_root_matches_pending_and_committed(ctx, open::<mmb::Family>)
822                .await;
823        });
824    }
825
826    #[test_traced]
827    fn test_variable_to_batch_mmb() {
828        let executor = deterministic::Runner::default();
829        executor.start(|ctx| async move {
830            test::test_immutable_to_batch(ctx, open::<mmb::Family>).await;
831        });
832    }
833
834    #[test_traced("INFO")]
835    fn test_variable_rewind_recovery_mmb() {
836        let executor = deterministic::Runner::default();
837        executor.start(|ctx| async move {
838            test::test_immutable_rewind_recovery(ctx, open::<mmb::Family>).await;
839        });
840    }
841
842    #[test_traced("INFO")]
843    fn test_variable_rewind_preserves_collision_bucket_mmb() {
844        let executor = deterministic::Runner::default();
845        executor.start(|ctx| async move {
846            test::test_immutable_rewind_preserves_collision_bucket(ctx, open::<mmb::Family>).await;
847        });
848    }
849
850    #[test_traced("INFO")]
851    fn test_variable_rewind_pruned_target_errors_mmb() {
852        let executor = deterministic::Runner::default();
853        executor.start(|ctx| async move {
854            test::test_immutable_rewind_pruned_target_errors(
855                ctx,
856                open_small_sections::<mmb::Family>,
857            )
858            .await;
859        });
860    }
861
862    #[test_traced("WARN")]
863    fn test_variable_apply_after_ancestor_dropped() {
864        let executor = deterministic::Runner::default();
865        executor.start(|ctx| async move {
866            test::test_immutable_apply_after_ancestor_dropped(ctx, open::<mmr::Family>).await;
867        });
868    }
869
870    #[test_traced("INFO")]
871    fn test_variable_inactivity_floor_tracking() {
872        let executor = deterministic::Runner::default();
873        executor.start(|ctx| async move {
874            test::test_immutable_inactivity_floor_tracking(ctx, open::<mmr::Family>).await;
875        });
876    }
877
878    #[test_traced("INFO")]
879    fn test_variable_floor_monotonicity() {
880        let executor = deterministic::Runner::default();
881        executor.start(|ctx| async move {
882            test::test_immutable_floor_monotonicity(ctx, open::<mmr::Family>).await;
883        });
884    }
885
886    #[test_traced("INFO")]
887    fn test_variable_floor_monotonicity_violation() {
888        let executor = deterministic::Runner::default();
889        executor.start(|ctx| async move {
890            test::test_immutable_floor_monotonicity_violation(ctx, open::<mmr::Family>).await;
891        });
892    }
893
894    #[test_traced("INFO")]
895    fn test_variable_floor_beyond_size() {
896        let executor = deterministic::Runner::default();
897        executor.start(|ctx| async move {
898            test::test_immutable_floor_beyond_size(ctx, open::<mmr::Family>).await;
899        });
900    }
901
902    #[test_traced("INFO")]
903    fn test_variable_chained_ancestor_floor_regression() {
904        let executor = deterministic::Runner::default();
905        executor.start(|ctx| async move {
906            test::test_immutable_chained_ancestor_floor_regression(ctx, open::<mmr::Family>).await;
907        });
908    }
909
910    #[test_traced("INFO")]
911    fn test_variable_chained_ancestor_floor_beyond_size() {
912        let executor = deterministic::Runner::default();
913        executor.start(|ctx| async move {
914            test::test_immutable_chained_ancestor_floor_beyond_size(ctx, open::<mmr::Family>).await;
915        });
916    }
917
918    #[test_traced("INFO")]
919    fn test_variable_rewind_restores_floor() {
920        let executor = deterministic::Runner::default();
921        executor.start(|ctx| async move {
922            test::test_immutable_rewind_restores_floor(ctx, open::<mmr::Family>).await;
923        });
924    }
925
926    #[test_traced("INFO")]
927    fn test_variable_inactivity_floor_tracking_mmb() {
928        let executor = deterministic::Runner::default();
929        executor.start(|ctx| async move {
930            test::test_immutable_inactivity_floor_tracking(ctx, open::<mmb::Family>).await;
931        });
932    }
933
934    #[test_traced("INFO")]
935    fn test_variable_floor_monotonicity_mmb() {
936        let executor = deterministic::Runner::default();
937        executor.start(|ctx| async move {
938            test::test_immutable_floor_monotonicity(ctx, open::<mmb::Family>).await;
939        });
940    }
941
942    #[test_traced("INFO")]
943    fn test_variable_floor_monotonicity_violation_mmb() {
944        let executor = deterministic::Runner::default();
945        executor.start(|ctx| async move {
946            test::test_immutable_floor_monotonicity_violation(ctx, open::<mmb::Family>).await;
947        });
948    }
949
950    #[test_traced("INFO")]
951    fn test_variable_floor_beyond_size_mmb() {
952        let executor = deterministic::Runner::default();
953        executor.start(|ctx| async move {
954            test::test_immutable_floor_beyond_size(ctx, open::<mmb::Family>).await;
955        });
956    }
957
958    #[test_traced("INFO")]
959    fn test_variable_chained_ancestor_floor_regression_mmb() {
960        let executor = deterministic::Runner::default();
961        executor.start(|ctx| async move {
962            test::test_immutable_chained_ancestor_floor_regression(ctx, open::<mmb::Family>).await;
963        });
964    }
965
966    #[test_traced("INFO")]
967    fn test_variable_chained_ancestor_floor_beyond_size_mmb() {
968        let executor = deterministic::Runner::default();
969        executor.start(|ctx| async move {
970            test::test_immutable_chained_ancestor_floor_beyond_size(ctx, open::<mmb::Family>).await;
971        });
972    }
973
974    #[test_traced("INFO")]
975    fn test_variable_rewind_restores_floor_mmb() {
976        let executor = deterministic::Runner::default();
977        executor.start(|ctx| async move {
978            test::test_immutable_rewind_restores_floor(ctx, open::<mmb::Family>).await;
979        });
980    }
981
982    #[test_traced("INFO")]
983    fn test_variable_single_commit_live_set() {
984        let executor = deterministic::Runner::default();
985        executor.start(|ctx| async move {
986            test::test_immutable_single_commit_live_set(ctx, open::<mmr::Family>).await;
987        });
988    }
989
990    #[test_traced("INFO")]
991    fn test_variable_single_commit_live_set_mmb() {
992        let executor = deterministic::Runner::default();
993        executor.start(|ctx| async move {
994            test::test_immutable_single_commit_live_set(ctx, open::<mmb::Family>).await;
995        });
996    }
997
998    #[test_traced("INFO")]
999    fn test_variable_rewind_after_reopen_with_floor_change() {
1000        let executor = deterministic::Runner::default();
1001        executor.start(|ctx| async move {
1002            test::test_immutable_rewind_after_reopen_with_floor_change(ctx, open::<mmr::Family>)
1003                .await;
1004        });
1005    }
1006
1007    #[test_traced("INFO")]
1008    fn test_variable_rewind_after_reopen_with_floor_change_mmb() {
1009        let executor = deterministic::Runner::default();
1010        executor.start(|ctx| async move {
1011            test::test_immutable_rewind_after_reopen_with_floor_change(ctx, open::<mmb::Family>)
1012                .await;
1013        });
1014    }
1015
1016    #[test_traced("INFO")]
1017    fn test_variable_rewind_after_reopen_partial_floor_gap() {
1018        let executor = deterministic::Runner::default();
1019        executor.start(|ctx| async move {
1020            test::test_immutable_rewind_after_reopen_partial_floor_gap(ctx, open::<mmr::Family>)
1021                .await;
1022        });
1023    }
1024
1025    #[test_traced("INFO")]
1026    fn test_variable_rewind_after_reopen_partial_floor_gap_mmb() {
1027        let executor = deterministic::Runner::default();
1028        executor.start(|ctx| async move {
1029            test::test_immutable_rewind_after_reopen_partial_floor_gap(ctx, open::<mmb::Family>)
1030                .await;
1031        });
1032    }
1033
1034    #[test_traced("INFO")]
1035    fn test_variable_rewind_after_reopen_repeated_key_gap() {
1036        let executor = deterministic::Runner::default();
1037        executor.start(|ctx| async move {
1038            test::test_immutable_rewind_after_reopen_repeated_key_gap(ctx, open::<mmb::Family>)
1039                .await;
1040        });
1041    }
1042
1043    #[test_traced("INFO")]
1044    fn test_variable_rewind_after_reopen_mixed_gap_retained() {
1045        let executor = deterministic::Runner::default();
1046        executor.start(|ctx| async move {
1047            test::test_immutable_rewind_after_reopen_mixed_gap_retained(ctx, open::<mmb::Family>)
1048                .await;
1049        });
1050    }
1051}