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