commonware_storage/qmdb/keyless/
variable.rs1use crate::{
6 journal::{
7 authenticated,
8 contiguous::variable::{self, Config as JournalConfig},
9 },
10 merkle::Family,
11 qmdb::{
12 any::value::{VariableEncoding, VariableValue},
13 keyless::operation::Operation as BaseOperation,
14 operation::Committable,
15 Error,
16 },
17};
18use commonware_codec::Read;
19use commonware_cryptography::Hasher;
20use commonware_runtime::{Clock, Metrics, Storage};
21
22pub type Operation<V> = BaseOperation<VariableEncoding<V>>;
24
25pub type Db<F, E, V, H> =
27 super::Keyless<F, E, VariableEncoding<V>, variable::Journal<E, Operation<V>>, H>;
28
29type Journal<F, E, V, H> = authenticated::Journal<F, E, variable::Journal<E, Operation<V>>, H>;
30
31pub type Config<C> = super::Config<JournalConfig<C>>;
33
34impl<F: Family, E: Storage + Clock + Metrics, V: VariableValue, H: Hasher> Db<F, E, V, H> {
35 pub async fn init(
38 context: E,
39 cfg: Config<<Operation<V> as Read>::Cfg>,
40 ) -> Result<Self, Error<F>> {
41 let journal: Journal<F, E, V, H> =
42 Journal::new(context, cfg.merkle, cfg.log, Operation::<V>::is_commit).await?;
43 Self::init_from_journal(journal).await
44 }
45}
46
47#[cfg(test)]
48mod test {
49 use super::*;
50 use crate::{
51 merkle::{mmb, mmr},
52 qmdb::keyless::tests,
53 };
54 use commonware_cryptography::Sha256;
55 use commonware_macros::test_traced;
56 use commonware_runtime::{
57 buffer::paged::CacheRef, deterministic, BufferPooler, Metrics, Runner as _,
58 };
59 use commonware_utils::{NZUsize, NZU16, NZU64};
60 use std::num::{NonZeroU16, NonZeroUsize};
61
62 const PAGE_SIZE: NonZeroU16 = NZU16!(101);
64 const PAGE_CACHE_SIZE: NonZeroUsize = NZUsize!(11);
65
66 fn db_config(
67 suffix: &str,
68 pooler: &impl BufferPooler,
69 ) -> Config<(commonware_codec::RangeCfg<usize>, ())> {
70 let page_cache = CacheRef::from_pooler(pooler, PAGE_SIZE, PAGE_CACHE_SIZE);
71 Config {
72 merkle: crate::merkle::journaled::Config {
73 journal_partition: format!("journal-{suffix}"),
74 metadata_partition: format!("metadata-{suffix}"),
75 items_per_blob: NZU64!(11),
76 write_buffer: NZUsize!(1024),
77 thread_pool: None,
78 page_cache: page_cache.clone(),
79 },
80 log: JournalConfig {
81 partition: format!("log-journal-{suffix}"),
82 items_per_section: NZU64!(7),
83 compression: None,
84 codec_config: ((0..=10000).into(), ()),
85 page_cache,
86 write_buffer: NZUsize!(1024),
87 },
88 }
89 }
90
91 type TestDb<F> = Db<F, deterministic::Context, Vec<u8>, Sha256>;
92
93 async fn open_db<F: crate::merkle::Family>(context: deterministic::Context) -> TestDb<F> {
95 let cfg = db_config("partition", &context);
96 TestDb::init(context, cfg).await.unwrap()
97 }
98
99 fn reopen<F: crate::merkle::Family>() -> tests::Reopen<TestDb<F>> {
100 Box::new(|ctx| Box::pin(open_db(ctx)))
101 }
102
103 #[test_traced("INFO")]
104 fn test_keyless_db_empty() {
105 deterministic::Runner::default().start(|ctx| async move {
106 let db = open_db::<mmr::Family>(ctx.with_label("db1")).await;
107 tests::test_keyless_db_empty(ctx, db, reopen::<mmr::Family>()).await;
108 });
109 }
110
111 #[test_traced("WARN")]
112 fn test_keyless_db_build_basic() {
113 deterministic::Runner::default().start(|ctx| async move {
114 let db = open_db::<mmr::Family>(ctx.with_label("db1")).await;
115 tests::test_keyless_db_build_basic(ctx, db, reopen::<mmr::Family>()).await;
116 });
117 }
118
119 #[test_traced("WARN")]
120 fn test_keyless_db_recovery() {
121 deterministic::Runner::default().start(|ctx| async move {
122 let db = open_db::<mmr::Family>(ctx.with_label("db1")).await;
123 tests::test_keyless_db_recovery(ctx, db, reopen::<mmr::Family>()).await;
124 });
125 }
126
127 #[test_traced("WARN")]
128 fn test_keyless_db_non_empty_recovery() {
129 deterministic::Runner::default().start(|ctx| async move {
130 let db = open_db::<mmr::Family>(ctx.with_label("db1")).await;
131 tests::test_keyless_db_non_empty_recovery(ctx, db, reopen::<mmr::Family>()).await;
132 });
133 }
134
135 #[test_traced("INFO")]
136 fn test_keyless_db_proof() {
137 deterministic::Runner::default().start(|ctx| async move {
138 let db = open_db::<mmr::Family>(ctx.clone()).await;
139 tests::test_keyless_db_proof(db).await;
140 });
141 }
142
143 #[test_traced("INFO")]
144 fn test_keyless_db_proof_comprehensive() {
145 deterministic::Runner::default().start(|ctx| async move {
146 let db = open_db::<mmr::Family>(ctx.clone()).await;
147 tests::test_keyless_db_proof_comprehensive(db).await;
148 });
149 }
150
151 #[test_traced("INFO")]
152 fn test_keyless_db_proof_with_pruning() {
153 deterministic::Runner::default().start(|ctx| async move {
154 let db = open_db::<mmr::Family>(ctx.with_label("db1")).await;
155 tests::test_keyless_db_proof_with_pruning(ctx, db, reopen::<mmr::Family>()).await;
156 });
157 }
158
159 #[test_traced("WARN")]
160 fn test_keyless_db_empty_db_recovery() {
161 deterministic::Runner::default().start(|ctx| async move {
162 let db = open_db::<mmr::Family>(ctx.with_label("db1")).await;
163 tests::test_keyless_db_empty_db_recovery(ctx, db, reopen::<mmr::Family>()).await;
164 });
165 }
166
167 #[test_traced("WARN")]
168 fn test_keyless_db_replay_with_trailing_appends() {
169 deterministic::Runner::default().start(|ctx| async move {
170 let db = open_db::<mmr::Family>(ctx.with_label("db1")).await;
171 tests::test_keyless_db_replay_with_trailing_appends(ctx, db, reopen::<mmr::Family>())
172 .await;
173 });
174 }
175
176 #[test_traced("INFO")]
177 fn test_keyless_db_get_out_of_bounds() {
178 deterministic::Runner::default().start(|ctx| async move {
179 let db = open_db::<mmr::Family>(ctx.clone()).await;
180 tests::test_keyless_db_get_out_of_bounds(db).await;
181 });
182 }
183
184 #[test_traced("INFO")]
185 fn test_keyless_db_metadata() {
186 deterministic::Runner::default().start(|ctx| async move {
187 let db = open_db::<mmr::Family>(ctx.with_label("db")).await;
188 tests::test_keyless_db_metadata(db).await;
189 });
190 }
191
192 #[test_traced("INFO")]
193 fn test_keyless_db_pruning() {
194 deterministic::Runner::default().start(|ctx| async move {
195 let db = open_db::<mmr::Family>(ctx.with_label("db")).await;
196 tests::test_keyless_db_pruning(db).await;
197 });
198 }
199
200 #[test_traced("INFO")]
201 fn test_keyless_batch_get() {
202 deterministic::Runner::default().start(|ctx| async move {
203 let db = open_db::<mmr::Family>(ctx.with_label("db")).await;
204 tests::test_keyless_batch_get(db).await;
205 });
206 }
207
208 #[test_traced("INFO")]
209 fn test_keyless_batch_stacked_get() {
210 deterministic::Runner::default().start(|ctx| async move {
211 let db = open_db::<mmr::Family>(ctx.with_label("db")).await;
212 tests::test_keyless_batch_stacked_get(db).await;
213 });
214 }
215
216 #[test_traced("INFO")]
217 fn test_keyless_batch_speculative_root() {
218 deterministic::Runner::default().start(|ctx| async move {
219 let db = open_db::<mmr::Family>(ctx.with_label("db")).await;
220 tests::test_keyless_batch_speculative_root(db).await;
221 });
222 }
223
224 #[test_traced("INFO")]
225 fn test_keyless_merkleized_batch_get() {
226 deterministic::Runner::default().start(|ctx| async move {
227 let db = open_db::<mmr::Family>(ctx.with_label("db")).await;
228 tests::test_keyless_merkleized_batch_get(db).await;
229 });
230 }
231
232 #[test_traced("INFO")]
233 fn test_keyless_batch_chained() {
234 deterministic::Runner::default().start(|ctx| async move {
235 let db = open_db::<mmr::Family>(ctx.with_label("db")).await;
236 tests::test_keyless_batch_chained(db).await;
237 });
238 }
239
240 #[test_traced("INFO")]
241 fn test_keyless_batch_chained_apply_sequential() {
242 deterministic::Runner::default().start(|ctx| async move {
243 let db = open_db::<mmr::Family>(ctx.with_label("db")).await;
244 tests::test_keyless_batch_chained_apply_sequential(db).await;
245 });
246 }
247
248 #[test_traced("INFO")]
249 fn test_keyless_batch_many_sequential() {
250 deterministic::Runner::default().start(|ctx| async move {
251 let db = open_db::<mmr::Family>(ctx.with_label("db")).await;
252 tests::test_keyless_batch_many_sequential(db).await;
253 });
254 }
255
256 #[test_traced("INFO")]
257 fn test_keyless_batch_empty() {
258 deterministic::Runner::default().start(|ctx| async move {
259 let db = open_db::<mmr::Family>(ctx.with_label("db")).await;
260 tests::test_keyless_batch_empty(db).await;
261 });
262 }
263
264 #[test_traced("INFO")]
265 fn test_keyless_batch_chained_merkleized_get() {
266 deterministic::Runner::default().start(|ctx| async move {
267 let db = open_db::<mmr::Family>(ctx.with_label("db")).await;
268 tests::test_keyless_batch_chained_merkleized_get(db).await;
269 });
270 }
271
272 #[test_traced("INFO")]
273 fn test_keyless_batch_large() {
274 deterministic::Runner::default().start(|ctx| async move {
275 let db = open_db::<mmr::Family>(ctx.with_label("db")).await;
276 tests::test_keyless_batch_large(db).await;
277 });
278 }
279
280 #[test_traced]
281 fn test_keyless_stale_batch() {
282 deterministic::Runner::default().start(|ctx| async move {
283 let db = open_db::<mmr::Family>(ctx.with_label("db")).await;
284 tests::test_keyless_stale_batch(db).await;
285 });
286 }
287
288 #[test_traced]
289 fn test_stale_batch_chained() {
290 deterministic::Runner::default().start(|ctx| async move {
291 let db = open_db::<mmr::Family>(ctx.with_label("db")).await;
292 tests::test_keyless_stale_batch_chained(db).await;
293 });
294 }
295
296 #[test_traced]
297 fn test_sequential_commit_parent_then_child() {
298 deterministic::Runner::default().start(|ctx| async move {
299 let db = open_db::<mmr::Family>(ctx.with_label("db")).await;
300 tests::test_keyless_sequential_commit_parent_then_child(db).await;
301 });
302 }
303
304 #[test_traced]
305 fn test_stale_batch_child_applied_before_parent() {
306 deterministic::Runner::default().start(|ctx| async move {
307 let db = open_db::<mmr::Family>(ctx.with_label("db")).await;
308 tests::test_keyless_stale_batch_child_before_parent(db).await;
309 });
310 }
311
312 #[test_traced]
313 fn test_partial_ancestor_commit() {
314 deterministic::Runner::default().start(|ctx| async move {
315 let db = open_db::<mmr::Family>(ctx.with_label("db")).await;
316 tests::test_keyless_partial_ancestor_commit(db).await;
317 });
318 }
319
320 #[test_traced]
321 fn test_keyless_to_batch() {
322 deterministic::Runner::default().start(|ctx| async move {
323 let db = open_db::<mmr::Family>(ctx.with_label("db")).await;
324 tests::test_keyless_to_batch(db).await;
325 });
326 }
327
328 #[test_traced]
329 fn test_keyless_child_root_matches_pending_and_committed() {
330 deterministic::Runner::default().start(|ctx| async move {
331 let db = open_db::<mmr::Family>(ctx.with_label("db")).await;
332 tests::test_keyless_child_root_matches_pending_and_committed(db).await;
333 });
334 }
335
336 #[test_traced("INFO")]
337 fn test_keyless_rewind_recovery() {
338 deterministic::Runner::default().start(|ctx| async move {
339 let db = open_db::<mmr::Family>(ctx.with_label("db")).await;
340 tests::test_keyless_db_rewind_recovery(ctx, db, reopen::<mmr::Family>()).await;
341 });
342 }
343
344 #[test_traced("INFO")]
345 fn test_keyless_rewind_pruned_target_errors() {
346 deterministic::Runner::default().start(|ctx| async move {
347 let db = open_db::<mmr::Family>(ctx.with_label("db")).await;
348 tests::test_keyless_db_rewind_pruned_target_errors(db).await;
349 });
350 }
351
352 #[test_traced("INFO")]
355 fn test_keyless_db_empty_mmb() {
356 deterministic::Runner::default().start(|ctx| async move {
357 let db = open_db::<mmb::Family>(ctx.with_label("db1")).await;
358 tests::test_keyless_db_empty(ctx, db, reopen::<mmb::Family>()).await;
359 });
360 }
361
362 #[test_traced("WARN")]
363 fn test_keyless_db_build_basic_mmb() {
364 deterministic::Runner::default().start(|ctx| async move {
365 let db = open_db::<mmb::Family>(ctx.with_label("db1")).await;
366 tests::test_keyless_db_build_basic(ctx, db, reopen::<mmb::Family>()).await;
367 });
368 }
369
370 #[test_traced("WARN")]
371 fn test_keyless_db_recovery_mmb() {
372 deterministic::Runner::default().start(|ctx| async move {
373 let db = open_db::<mmb::Family>(ctx.with_label("db1")).await;
374 tests::test_keyless_db_recovery(ctx, db, reopen::<mmb::Family>()).await;
375 });
376 }
377
378 #[test_traced("WARN")]
379 fn test_keyless_db_non_empty_recovery_mmb() {
380 deterministic::Runner::default().start(|ctx| async move {
381 let db = open_db::<mmb::Family>(ctx.with_label("db1")).await;
382 tests::test_keyless_db_non_empty_recovery(ctx, db, reopen::<mmb::Family>()).await;
383 });
384 }
385
386 #[test_traced("INFO")]
387 fn test_keyless_db_proof_mmb() {
388 deterministic::Runner::default().start(|ctx| async move {
389 let db = open_db::<mmb::Family>(ctx.clone()).await;
390 tests::test_keyless_db_proof(db).await;
391 });
392 }
393
394 #[test_traced("INFO")]
395 fn test_keyless_db_proof_comprehensive_mmb() {
396 deterministic::Runner::default().start(|ctx| async move {
397 let db = open_db::<mmb::Family>(ctx.clone()).await;
398 tests::test_keyless_db_proof_comprehensive(db).await;
399 });
400 }
401
402 #[test_traced("INFO")]
403 fn test_keyless_db_proof_with_pruning_mmb() {
404 deterministic::Runner::default().start(|ctx| async move {
405 let db = open_db::<mmb::Family>(ctx.with_label("db1")).await;
406 tests::test_keyless_db_proof_with_pruning(ctx, db, reopen::<mmb::Family>()).await;
407 });
408 }
409
410 #[test_traced("WARN")]
411 fn test_keyless_db_empty_db_recovery_mmb() {
412 deterministic::Runner::default().start(|ctx| async move {
413 let db = open_db::<mmb::Family>(ctx.with_label("db1")).await;
414 tests::test_keyless_db_empty_db_recovery(ctx, db, reopen::<mmb::Family>()).await;
415 });
416 }
417
418 #[test_traced("WARN")]
419 fn test_keyless_db_replay_with_trailing_appends_mmb() {
420 deterministic::Runner::default().start(|ctx| async move {
421 let db = open_db::<mmb::Family>(ctx.with_label("db1")).await;
422 tests::test_keyless_db_replay_with_trailing_appends(ctx, db, reopen::<mmb::Family>())
423 .await;
424 });
425 }
426
427 #[test_traced("INFO")]
428 fn test_keyless_db_get_out_of_bounds_mmb() {
429 deterministic::Runner::default().start(|ctx| async move {
430 let db = open_db::<mmb::Family>(ctx.clone()).await;
431 tests::test_keyless_db_get_out_of_bounds(db).await;
432 });
433 }
434
435 #[test_traced("INFO")]
436 fn test_keyless_db_metadata_mmb() {
437 deterministic::Runner::default().start(|ctx| async move {
438 let db = open_db::<mmb::Family>(ctx.with_label("db")).await;
439 tests::test_keyless_db_metadata(db).await;
440 });
441 }
442
443 #[test_traced("INFO")]
444 fn test_keyless_db_pruning_mmb() {
445 deterministic::Runner::default().start(|ctx| async move {
446 let db = open_db::<mmb::Family>(ctx.with_label("db")).await;
447 tests::test_keyless_db_pruning(db).await;
448 });
449 }
450
451 #[test_traced("INFO")]
452 fn test_keyless_batch_get_mmb() {
453 deterministic::Runner::default().start(|ctx| async move {
454 let db = open_db::<mmb::Family>(ctx.with_label("db")).await;
455 tests::test_keyless_batch_get(db).await;
456 });
457 }
458
459 #[test_traced("INFO")]
460 fn test_keyless_batch_stacked_get_mmb() {
461 deterministic::Runner::default().start(|ctx| async move {
462 let db = open_db::<mmb::Family>(ctx.with_label("db")).await;
463 tests::test_keyless_batch_stacked_get(db).await;
464 });
465 }
466
467 #[test_traced("INFO")]
468 fn test_keyless_batch_speculative_root_mmb() {
469 deterministic::Runner::default().start(|ctx| async move {
470 let db = open_db::<mmb::Family>(ctx.with_label("db")).await;
471 tests::test_keyless_batch_speculative_root(db).await;
472 });
473 }
474
475 #[test_traced("INFO")]
476 fn test_keyless_merkleized_batch_get_mmb() {
477 deterministic::Runner::default().start(|ctx| async move {
478 let db = open_db::<mmb::Family>(ctx.with_label("db")).await;
479 tests::test_keyless_merkleized_batch_get(db).await;
480 });
481 }
482
483 #[test_traced("INFO")]
484 fn test_keyless_batch_chained_mmb() {
485 deterministic::Runner::default().start(|ctx| async move {
486 let db = open_db::<mmb::Family>(ctx.with_label("db")).await;
487 tests::test_keyless_batch_chained(db).await;
488 });
489 }
490
491 #[test_traced("INFO")]
492 fn test_keyless_batch_chained_apply_sequential_mmb() {
493 deterministic::Runner::default().start(|ctx| async move {
494 let db = open_db::<mmb::Family>(ctx.with_label("db")).await;
495 tests::test_keyless_batch_chained_apply_sequential(db).await;
496 });
497 }
498
499 #[test_traced("INFO")]
500 fn test_keyless_batch_many_sequential_mmb() {
501 deterministic::Runner::default().start(|ctx| async move {
502 let db = open_db::<mmb::Family>(ctx.with_label("db")).await;
503 tests::test_keyless_batch_many_sequential(db).await;
504 });
505 }
506
507 #[test_traced("INFO")]
508 fn test_keyless_batch_empty_mmb() {
509 deterministic::Runner::default().start(|ctx| async move {
510 let db = open_db::<mmb::Family>(ctx.with_label("db")).await;
511 tests::test_keyless_batch_empty(db).await;
512 });
513 }
514
515 #[test_traced("INFO")]
516 fn test_keyless_batch_chained_merkleized_get_mmb() {
517 deterministic::Runner::default().start(|ctx| async move {
518 let db = open_db::<mmb::Family>(ctx.with_label("db")).await;
519 tests::test_keyless_batch_chained_merkleized_get(db).await;
520 });
521 }
522
523 #[test_traced("INFO")]
524 fn test_keyless_batch_large_mmb() {
525 deterministic::Runner::default().start(|ctx| async move {
526 let db = open_db::<mmb::Family>(ctx.with_label("db")).await;
527 tests::test_keyless_batch_large(db).await;
528 });
529 }
530
531 #[test_traced]
532 fn test_keyless_stale_batch_mmb() {
533 deterministic::Runner::default().start(|ctx| async move {
534 let db = open_db::<mmb::Family>(ctx.with_label("db")).await;
535 tests::test_keyless_stale_batch(db).await;
536 });
537 }
538
539 #[test_traced]
540 fn test_stale_batch_chained_mmb() {
541 deterministic::Runner::default().start(|ctx| async move {
542 let db = open_db::<mmb::Family>(ctx.with_label("db")).await;
543 tests::test_keyless_stale_batch_chained(db).await;
544 });
545 }
546
547 #[test_traced]
548 fn test_sequential_commit_parent_then_child_mmb() {
549 deterministic::Runner::default().start(|ctx| async move {
550 let db = open_db::<mmb::Family>(ctx.with_label("db")).await;
551 tests::test_keyless_sequential_commit_parent_then_child(db).await;
552 });
553 }
554
555 #[test_traced]
556 fn test_stale_batch_child_applied_before_parent_mmb() {
557 deterministic::Runner::default().start(|ctx| async move {
558 let db = open_db::<mmb::Family>(ctx.with_label("db")).await;
559 tests::test_keyless_stale_batch_child_before_parent(db).await;
560 });
561 }
562
563 #[test_traced]
564 fn test_keyless_to_batch_mmb() {
565 deterministic::Runner::default().start(|ctx| async move {
566 let db = open_db::<mmb::Family>(ctx.with_label("db")).await;
567 tests::test_keyless_to_batch(db).await;
568 });
569 }
570
571 #[test_traced]
572 fn test_keyless_child_root_matches_pending_and_committed_mmb() {
573 deterministic::Runner::default().start(|ctx| async move {
574 let db = open_db::<mmb::Family>(ctx.with_label("db")).await;
575 tests::test_keyless_child_root_matches_pending_and_committed(db).await;
576 });
577 }
578
579 #[test_traced("INFO")]
580 fn test_keyless_rewind_recovery_mmb() {
581 deterministic::Runner::default().start(|ctx| async move {
582 let db = open_db::<mmb::Family>(ctx.with_label("db")).await;
583 tests::test_keyless_db_rewind_recovery(ctx, db, reopen::<mmb::Family>()).await;
584 });
585 }
586
587 #[test_traced("INFO")]
588 fn test_keyless_rewind_pruned_target_errors_mmb() {
589 deterministic::Runner::default().start(|ctx| async move {
590 let db = open_db::<mmb::Family>(ctx.with_label("db")).await;
591 tests::test_keyless_db_rewind_pruned_target_errors(db).await;
592 });
593 }
594
595 fn is_send<T: Send>(_: T) {}
596
597 #[allow(dead_code)]
598 fn assert_db_futures_are_send(
599 db: &mut TestDb<mmr::Family>,
600 loc: crate::merkle::Location<mmr::Family>,
601 ) {
602 is_send(db.get_metadata());
603 is_send(db.proof(loc, NZU64!(1)));
604 is_send(db.sync());
605 is_send(db.get(loc));
606 is_send(db.rewind(loc));
607 }
608}