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