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