1use 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,
15 },
16 translator::Translator,
17};
18use commonware_cryptography::Hasher;
19use commonware_runtime::{Clock, Metrics, Storage};
20use commonware_utils::Array;
21
22pub type Operation<K, V> = BaseOperation<K, FixedEncoding<V>>;
24
25pub type Db<F, E, K, V, H, T> =
27 Immutable<F, E, K, FixedEncoding<V>, fixed::Journal<E, Operation<K, V>>, H, T>;
28
29type Journal<F, E, K, V, H> = authenticated::Journal<F, E, fixed::Journal<E, Operation<K, V>>, H>;
30
31pub type Config<T> = BaseConfig<T, JournalConfig>;
33
34impl<
35 F: Family,
36 E: Storage + Clock + Metrics,
37 K: Array,
38 V: FixedValue,
39 H: Hasher,
40 T: Translator,
41 > Db<F, E, K, V, H, T>
42{
43 pub async fn init(context: E, cfg: Config<T>) -> Result<Self, Error<F>> {
46 let journal: Journal<F, E, K, V, H> = Journal::new(
47 context.clone(),
48 cfg.merkle_config,
49 cfg.log,
50 Operation::<K, V>::is_commit,
51 )
52 .await?;
53 Self::init_from_journal(journal, context, cfg.translator).await
54 }
55}
56
57#[cfg(test)]
58mod tests {
59 use super::*;
60 use crate::{
61 merkle::{journaled::Config as MmrConfig, mmb, mmr},
62 qmdb::immutable::test,
63 translator::TwoCap,
64 };
65 use commonware_cryptography::{sha256::Digest, Sha256};
66 use commonware_macros::test_traced;
67 use commonware_runtime::{buffer::paged::CacheRef, deterministic, BufferPooler, Runner as _};
68 use commonware_utils::{NZUsize, NZU16, NZU64};
69 use core::{future::Future, pin::Pin};
70 use std::num::{NonZeroU16, NonZeroUsize};
71
72 const PAGE_SIZE: NonZeroU16 = NZU16!(77);
73 const PAGE_CACHE_SIZE: NonZeroUsize = NZUsize!(9);
74
75 fn config(suffix: &str, pooler: &impl BufferPooler) -> Config<TwoCap> {
76 let page_cache = CacheRef::from_pooler(pooler, PAGE_SIZE, PAGE_CACHE_SIZE);
77 Config {
78 merkle_config: MmrConfig {
79 journal_partition: format!("journal-{suffix}"),
80 metadata_partition: format!("metadata-{suffix}"),
81 items_per_blob: NZU64!(11),
82 write_buffer: NZUsize!(1024),
83 thread_pool: None,
84 page_cache: page_cache.clone(),
85 },
86 log: JournalConfig {
87 items_per_blob: NZU64!(5),
88 partition: format!("log-{suffix}"),
89 page_cache,
90 write_buffer: NZUsize!(1024),
91 },
92 translator: TwoCap,
93 }
94 }
95
96 async fn open_db<F: Family>(
97 context: deterministic::Context,
98 ) -> Db<F, deterministic::Context, Digest, Digest, Sha256, TwoCap> {
99 let cfg = config("partition", &context);
100 Db::init(context, cfg).await.unwrap()
101 }
102
103 #[allow(clippy::type_complexity)]
104 fn open<F: Family>(
105 ctx: deterministic::Context,
106 ) -> Pin<
107 Box<
108 dyn Future<Output = Db<F, deterministic::Context, Digest, Digest, Sha256, TwoCap>>
109 + Send,
110 >,
111 > {
112 Box::pin(open_db::<F>(ctx))
113 }
114
115 fn is_send<T: Send>(_: T) {}
116
117 #[allow(dead_code)]
118 fn assert_db_futures_are_send(
119 db: &mut Db<mmr::Family, deterministic::Context, Digest, Digest, Sha256, TwoCap>,
120 key: Digest,
121 loc: crate::merkle::mmr::Location,
122 ) {
123 is_send(db.get(&key));
124 is_send(db.get_metadata());
125 is_send(db.proof(loc, NZU64!(1)));
126 is_send(db.sync());
127 is_send(db.rewind(loc));
128 }
129
130 fn small_sections_config(suffix: &str, pooler: &impl BufferPooler) -> Config<TwoCap> {
131 let mut cfg = config(suffix, pooler);
132 cfg.log.items_per_blob = NZU64!(1);
133 cfg
134 }
135
136 async fn open_small_sections_db<F: Family>(
137 context: deterministic::Context,
138 ) -> Db<F, deterministic::Context, Digest, Digest, Sha256, TwoCap> {
139 let cfg = small_sections_config("partition", &context);
140 Db::init(context, cfg).await.unwrap()
141 }
142
143 #[allow(clippy::type_complexity)]
144 fn open_small_sections<F: Family>(
145 ctx: deterministic::Context,
146 ) -> Pin<
147 Box<
148 dyn Future<Output = Db<F, deterministic::Context, Digest, Digest, Sha256, TwoCap>>
149 + Send,
150 >,
151 > {
152 Box::pin(open_small_sections_db::<F>(ctx))
153 }
154
155 #[test_traced("WARN")]
156 fn test_fixed_empty() {
157 let executor = deterministic::Runner::default();
158 executor.start(|ctx| async move {
159 test::test_immutable_empty(ctx, open::<mmr::Family>).await;
160 });
161 }
162
163 #[test_traced("DEBUG")]
164 fn test_fixed_build_basic() {
165 let executor = deterministic::Runner::default();
166 executor.start(|ctx| async move {
167 test::test_immutable_build_basic(ctx, open::<mmr::Family>).await;
168 });
169 }
170
171 #[test_traced("WARN")]
172 fn test_fixed_proof_verify() {
173 let executor = deterministic::Runner::default();
174 executor.start(|ctx| async move {
175 test::test_immutable_proof_verify(ctx, open::<mmr::Family>).await;
176 });
177 }
178
179 #[test_traced("DEBUG")]
180 fn test_fixed_prune() {
181 let executor = deterministic::Runner::default();
182 executor.start(|ctx| async move {
183 test::test_immutable_prune(ctx, open::<mmr::Family>).await;
184 });
185 }
186
187 #[test_traced("DEBUG")]
188 fn test_fixed_batch_chain() {
189 let executor = deterministic::Runner::default();
190 executor.start(|ctx| async move {
191 test::test_immutable_batch_chain(ctx, open::<mmr::Family>).await;
192 });
193 }
194
195 #[test_traced("WARN")]
196 fn test_fixed_build_and_authenticate() {
197 let executor = deterministic::Runner::default();
198 executor.start(|ctx| async move {
199 test::test_immutable_build_and_authenticate(ctx, open::<mmr::Family>).await;
200 });
201 }
202
203 #[test_traced("WARN")]
204 fn test_fixed_recovery_from_failed_merkle_sync() {
205 let executor = deterministic::Runner::default();
206 executor.start(|ctx| async move {
207 test::test_immutable_recovery_from_failed_merkle_sync(ctx, open::<mmr::Family>).await;
208 });
209 }
210
211 #[test_traced("WARN")]
212 fn test_fixed_recovery_from_failed_log_sync() {
213 let executor = deterministic::Runner::default();
214 executor.start(|ctx| async move {
215 test::test_immutable_recovery_from_failed_log_sync(ctx, open::<mmr::Family>).await;
216 });
217 }
218
219 #[test_traced("WARN")]
220 fn test_fixed_pruning() {
221 let executor = deterministic::Runner::default();
222 executor.start(|ctx| async move {
223 test::test_immutable_pruning(ctx, open::<mmr::Family>).await;
224 });
225 }
226
227 #[test_traced("INFO")]
228 fn test_fixed_prune_beyond_commit() {
229 let executor = deterministic::Runner::default();
230 executor.start(|ctx| async move {
231 test::test_immutable_prune_beyond_commit(ctx, open::<mmr::Family>).await;
232 });
233 }
234
235 #[test_traced("INFO")]
236 fn test_fixed_batch_get_read_through() {
237 let executor = deterministic::Runner::default();
238 executor.start(|ctx| async move {
239 test::test_immutable_batch_get_read_through(ctx, open::<mmr::Family>).await;
240 });
241 }
242
243 #[test_traced("INFO")]
244 fn test_fixed_batch_stacked_get() {
245 let executor = deterministic::Runner::default();
246 executor.start(|ctx| async move {
247 test::test_immutable_batch_stacked_get(ctx, open::<mmr::Family>).await;
248 });
249 }
250
251 #[test_traced("INFO")]
252 fn test_fixed_batch_stacked_apply() {
253 let executor = deterministic::Runner::default();
254 executor.start(|ctx| async move {
255 test::test_immutable_batch_stacked_apply(ctx, open::<mmr::Family>).await;
256 });
257 }
258
259 #[test_traced("INFO")]
260 fn test_fixed_batch_speculative_root() {
261 let executor = deterministic::Runner::default();
262 executor.start(|ctx| async move {
263 test::test_immutable_batch_speculative_root(ctx, open::<mmr::Family>).await;
264 });
265 }
266
267 #[test_traced("INFO")]
268 fn test_fixed_merkleized_batch_get() {
269 let executor = deterministic::Runner::default();
270 executor.start(|ctx| async move {
271 test::test_immutable_merkleized_batch_get(ctx, open::<mmr::Family>).await;
272 });
273 }
274
275 #[test_traced("INFO")]
276 fn test_fixed_batch_sequential_apply() {
277 let executor = deterministic::Runner::default();
278 executor.start(|ctx| async move {
279 test::test_immutable_batch_sequential_apply(ctx, open::<mmr::Family>).await;
280 });
281 }
282
283 #[test_traced("INFO")]
284 fn test_fixed_batch_many_sequential() {
285 let executor = deterministic::Runner::default();
286 executor.start(|ctx| async move {
287 test::test_immutable_batch_many_sequential(ctx, open::<mmr::Family>).await;
288 });
289 }
290
291 #[test_traced("INFO")]
292 fn test_fixed_batch_empty_batch() {
293 let executor = deterministic::Runner::default();
294 executor.start(|ctx| async move {
295 test::test_immutable_batch_empty_batch(ctx, open::<mmr::Family>).await;
296 });
297 }
298
299 #[test_traced("INFO")]
300 fn test_fixed_batch_chained_merkleized_get() {
301 let executor = deterministic::Runner::default();
302 executor.start(|ctx| async move {
303 test::test_immutable_batch_chained_merkleized_get(ctx, open::<mmr::Family>).await;
304 });
305 }
306
307 #[test_traced("INFO")]
308 fn test_fixed_batch_large() {
309 let executor = deterministic::Runner::default();
310 executor.start(|ctx| async move {
311 test::test_immutable_batch_large(ctx, open::<mmr::Family>).await;
312 });
313 }
314
315 #[test_traced("INFO")]
316 fn test_fixed_batch_chained_key_override() {
317 let executor = deterministic::Runner::default();
318 executor.start(|ctx| async move {
319 test::test_immutable_batch_chained_key_override(ctx, open::<mmr::Family>).await;
320 });
321 }
322
323 #[test_traced("INFO")]
324 fn test_fixed_batch_sequential_key_override() {
325 let executor = deterministic::Runner::default();
326 executor.start(|ctx| async move {
327 test::test_immutable_batch_sequential_key_override(
328 ctx,
329 open_small_sections::<mmr::Family>,
330 )
331 .await;
332 });
333 }
334
335 #[test_traced("INFO")]
336 fn test_fixed_batch_metadata() {
337 let executor = deterministic::Runner::default();
338 executor.start(|ctx| async move {
339 test::test_immutable_batch_metadata(ctx, open::<mmr::Family>).await;
340 });
341 }
342
343 #[test_traced]
344 fn test_fixed_stale_batch_rejected() {
345 let executor = deterministic::Runner::default();
346 executor.start(|ctx| async move {
347 test::test_immutable_stale_batch_rejected(ctx, open::<mmr::Family>).await;
348 });
349 }
350
351 #[test_traced]
352 fn test_fixed_stale_batch_chained() {
353 let executor = deterministic::Runner::default();
354 executor.start(|ctx| async move {
355 test::test_immutable_stale_batch_chained(ctx, open::<mmr::Family>).await;
356 });
357 }
358
359 #[test_traced]
360 fn test_fixed_sequential_commit_parent_then_child() {
361 let executor = deterministic::Runner::default();
362 executor.start(|ctx| async move {
363 test::test_immutable_sequential_commit_parent_then_child(ctx, open::<mmr::Family>)
364 .await;
365 });
366 }
367
368 #[test_traced]
369 fn test_fixed_stale_batch_child_applied_before_parent() {
370 let executor = deterministic::Runner::default();
371 executor.start(|ctx| async move {
372 test::test_immutable_stale_batch_child_applied_before_parent(ctx, open::<mmr::Family>)
373 .await;
374 });
375 }
376
377 #[test_traced]
378 fn test_fixed_child_root_matches_pending_and_committed() {
379 let executor = deterministic::Runner::default();
380 executor.start(|ctx| async move {
381 test::test_immutable_child_root_matches_pending_and_committed(ctx, open::<mmr::Family>)
382 .await;
383 });
384 }
385
386 #[test_traced]
387 fn test_fixed_to_batch() {
388 let executor = deterministic::Runner::default();
389 executor.start(|ctx| async move {
390 test::test_immutable_to_batch(ctx, open::<mmr::Family>).await;
391 });
392 }
393
394 #[test_traced("INFO")]
395 fn test_fixed_rewind_recovery() {
396 let executor = deterministic::Runner::default();
397 executor.start(|ctx| async move {
398 test::test_immutable_rewind_recovery(ctx, open::<mmr::Family>).await;
399 });
400 }
401
402 #[test_traced("INFO")]
403 fn test_fixed_rewind_pruned_target_errors() {
404 let executor = deterministic::Runner::default();
405 executor.start(|ctx| async move {
406 test::test_immutable_rewind_pruned_target_errors(
407 ctx,
408 open_small_sections::<mmr::Family>,
409 )
410 .await;
411 });
412 }
413
414 #[test_traced("WARN")]
417 fn test_fixed_empty_mmb() {
418 let executor = deterministic::Runner::default();
419 executor.start(|ctx| async move {
420 test::test_immutable_empty(ctx, open::<mmb::Family>).await;
421 });
422 }
423
424 #[test_traced("DEBUG")]
425 fn test_fixed_build_basic_mmb() {
426 let executor = deterministic::Runner::default();
427 executor.start(|ctx| async move {
428 test::test_immutable_build_basic(ctx, open::<mmb::Family>).await;
429 });
430 }
431
432 #[test_traced("WARN")]
433 fn test_fixed_proof_verify_mmb() {
434 let executor = deterministic::Runner::default();
435 executor.start(|ctx| async move {
436 test::test_immutable_proof_verify(ctx, open::<mmb::Family>).await;
437 });
438 }
439
440 #[test_traced("DEBUG")]
441 fn test_fixed_prune_mmb() {
442 let executor = deterministic::Runner::default();
443 executor.start(|ctx| async move {
444 test::test_immutable_prune(ctx, open::<mmb::Family>).await;
445 });
446 }
447
448 #[test_traced("DEBUG")]
449 fn test_fixed_batch_chain_mmb() {
450 let executor = deterministic::Runner::default();
451 executor.start(|ctx| async move {
452 test::test_immutable_batch_chain(ctx, open::<mmb::Family>).await;
453 });
454 }
455
456 #[test_traced("WARN")]
457 fn test_fixed_build_and_authenticate_mmb() {
458 let executor = deterministic::Runner::default();
459 executor.start(|ctx| async move {
460 test::test_immutable_build_and_authenticate(ctx, open::<mmb::Family>).await;
461 });
462 }
463
464 #[test_traced("WARN")]
465 fn test_fixed_recovery_from_failed_merkle_sync_mmb() {
466 let executor = deterministic::Runner::default();
467 executor.start(|ctx| async move {
468 test::test_immutable_recovery_from_failed_merkle_sync(ctx, open::<mmb::Family>).await;
469 });
470 }
471
472 #[test_traced("WARN")]
473 fn test_fixed_recovery_from_failed_log_sync_mmb() {
474 let executor = deterministic::Runner::default();
475 executor.start(|ctx| async move {
476 test::test_immutable_recovery_from_failed_log_sync(ctx, open::<mmb::Family>).await;
477 });
478 }
479
480 #[test_traced("WARN")]
481 fn test_fixed_pruning_mmb() {
482 let executor = deterministic::Runner::default();
483 executor.start(|ctx| async move {
484 test::test_immutable_pruning(ctx, open::<mmb::Family>).await;
485 });
486 }
487
488 #[test_traced("INFO")]
489 fn test_fixed_prune_beyond_commit_mmb() {
490 let executor = deterministic::Runner::default();
491 executor.start(|ctx| async move {
492 test::test_immutable_prune_beyond_commit(ctx, open::<mmb::Family>).await;
493 });
494 }
495
496 #[test_traced("INFO")]
497 fn test_fixed_batch_get_read_through_mmb() {
498 let executor = deterministic::Runner::default();
499 executor.start(|ctx| async move {
500 test::test_immutable_batch_get_read_through(ctx, open::<mmb::Family>).await;
501 });
502 }
503
504 #[test_traced("INFO")]
505 fn test_fixed_batch_stacked_get_mmb() {
506 let executor = deterministic::Runner::default();
507 executor.start(|ctx| async move {
508 test::test_immutable_batch_stacked_get(ctx, open::<mmb::Family>).await;
509 });
510 }
511
512 #[test_traced("INFO")]
513 fn test_fixed_batch_stacked_apply_mmb() {
514 let executor = deterministic::Runner::default();
515 executor.start(|ctx| async move {
516 test::test_immutable_batch_stacked_apply(ctx, open::<mmb::Family>).await;
517 });
518 }
519
520 #[test_traced("INFO")]
521 fn test_fixed_batch_speculative_root_mmb() {
522 let executor = deterministic::Runner::default();
523 executor.start(|ctx| async move {
524 test::test_immutable_batch_speculative_root(ctx, open::<mmb::Family>).await;
525 });
526 }
527
528 #[test_traced("INFO")]
529 fn test_fixed_merkleized_batch_get_mmb() {
530 let executor = deterministic::Runner::default();
531 executor.start(|ctx| async move {
532 test::test_immutable_merkleized_batch_get(ctx, open::<mmb::Family>).await;
533 });
534 }
535
536 #[test_traced("INFO")]
537 fn test_fixed_batch_sequential_apply_mmb() {
538 let executor = deterministic::Runner::default();
539 executor.start(|ctx| async move {
540 test::test_immutable_batch_sequential_apply(ctx, open::<mmb::Family>).await;
541 });
542 }
543
544 #[test_traced("INFO")]
545 fn test_fixed_batch_many_sequential_mmb() {
546 let executor = deterministic::Runner::default();
547 executor.start(|ctx| async move {
548 test::test_immutable_batch_many_sequential(ctx, open::<mmb::Family>).await;
549 });
550 }
551
552 #[test_traced("INFO")]
553 fn test_fixed_batch_empty_batch_mmb() {
554 let executor = deterministic::Runner::default();
555 executor.start(|ctx| async move {
556 test::test_immutable_batch_empty_batch(ctx, open::<mmb::Family>).await;
557 });
558 }
559
560 #[test_traced("INFO")]
561 fn test_fixed_batch_chained_merkleized_get_mmb() {
562 let executor = deterministic::Runner::default();
563 executor.start(|ctx| async move {
564 test::test_immutable_batch_chained_merkleized_get(ctx, open::<mmb::Family>).await;
565 });
566 }
567
568 #[test_traced("INFO")]
569 fn test_fixed_batch_large_mmb() {
570 let executor = deterministic::Runner::default();
571 executor.start(|ctx| async move {
572 test::test_immutable_batch_large(ctx, open::<mmb::Family>).await;
573 });
574 }
575
576 #[test_traced("INFO")]
577 fn test_fixed_batch_chained_key_override_mmb() {
578 let executor = deterministic::Runner::default();
579 executor.start(|ctx| async move {
580 test::test_immutable_batch_chained_key_override(ctx, open::<mmb::Family>).await;
581 });
582 }
583
584 #[test_traced("INFO")]
585 fn test_fixed_batch_sequential_key_override_mmb() {
586 let executor = deterministic::Runner::default();
587 executor.start(|ctx| async move {
588 test::test_immutable_batch_sequential_key_override(
589 ctx,
590 open_small_sections::<mmb::Family>,
591 )
592 .await;
593 });
594 }
595
596 #[test_traced("INFO")]
597 fn test_fixed_batch_metadata_mmb() {
598 let executor = deterministic::Runner::default();
599 executor.start(|ctx| async move {
600 test::test_immutable_batch_metadata(ctx, open::<mmb::Family>).await;
601 });
602 }
603
604 #[test_traced]
605 fn test_fixed_stale_batch_rejected_mmb() {
606 let executor = deterministic::Runner::default();
607 executor.start(|ctx| async move {
608 test::test_immutable_stale_batch_rejected(ctx, open::<mmb::Family>).await;
609 });
610 }
611
612 #[test_traced]
613 fn test_fixed_stale_batch_chained_mmb() {
614 let executor = deterministic::Runner::default();
615 executor.start(|ctx| async move {
616 test::test_immutable_stale_batch_chained(ctx, open::<mmb::Family>).await;
617 });
618 }
619
620 #[test_traced]
621 fn test_fixed_sequential_commit_parent_then_child_mmb() {
622 let executor = deterministic::Runner::default();
623 executor.start(|ctx| async move {
624 test::test_immutable_sequential_commit_parent_then_child(ctx, open::<mmb::Family>)
625 .await;
626 });
627 }
628
629 #[test_traced]
630 fn test_fixed_stale_batch_child_applied_before_parent_mmb() {
631 let executor = deterministic::Runner::default();
632 executor.start(|ctx| async move {
633 test::test_immutable_stale_batch_child_applied_before_parent(ctx, open::<mmb::Family>)
634 .await;
635 });
636 }
637
638 #[test_traced]
639 fn test_fixed_child_root_matches_pending_and_committed_mmb() {
640 let executor = deterministic::Runner::default();
641 executor.start(|ctx| async move {
642 test::test_immutable_child_root_matches_pending_and_committed(ctx, open::<mmb::Family>)
643 .await;
644 });
645 }
646
647 #[test_traced]
648 fn test_fixed_to_batch_mmb() {
649 let executor = deterministic::Runner::default();
650 executor.start(|ctx| async move {
651 test::test_immutable_to_batch(ctx, open::<mmb::Family>).await;
652 });
653 }
654
655 #[test_traced("INFO")]
656 fn test_fixed_rewind_recovery_mmb() {
657 let executor = deterministic::Runner::default();
658 executor.start(|ctx| async move {
659 test::test_immutable_rewind_recovery(ctx, open::<mmb::Family>).await;
660 });
661 }
662
663 #[test_traced("INFO")]
664 fn test_fixed_rewind_pruned_target_errors_mmb() {
665 let executor = deterministic::Runner::default();
666 executor.start(|ctx| async move {
667 test::test_immutable_rewind_pruned_target_errors(
668 ctx,
669 open_small_sections::<mmb::Family>,
670 )
671 .await;
672 });
673 }
674}