Skip to main content

commonware_storage/qmdb/immutable/
fixed.rs

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