commonware_storage/adb/
mod.rs

1//! A collection of authenticated databases (ADB).
2//!
3//! # Terminology
4//!
5//! A _key_ in an authenticated database either has a _value_ or it doesn't. Two types of
6//! _operations_ can be applied to the db to modify the state of a specific key. A key that has a
7//! value can change to one without a value through the _delete_ operation. The _update_ operation
8//! gives a key a specific value whether it previously had no value or had a different value.
9//!
10//! Keys with values are called _active_. An operation is called _active_ if (1) its key is active,
11//! (2) it is an update operation, and (3) it is the most recent operation for that key.
12
13use crate::{journal::fixed::Journal, mmr::journaled};
14use commonware_cryptography::Hasher;
15use commonware_runtime::{Clock, Metrics, Storage};
16use thiserror::Error;
17
18pub mod any;
19pub mod current;
20pub mod immutable;
21pub mod keyless;
22pub mod sync;
23pub mod verify;
24use tracing::warn;
25pub use verify::{
26    create_multi_proof, create_proof, create_proof_store, create_proof_store_from_digests,
27    digests_required_for_proof, extract_pinned_nodes, verify_multi_proof, verify_proof,
28    verify_proof_and_extract_digests,
29};
30
31/// Errors that can occur when interacting with an authenticated database.
32#[derive(Error, Debug)]
33pub enum Error {
34    #[error("mmr error: {0}")]
35    Mmr(#[from] crate::mmr::Error),
36
37    #[error("metadata error: {0}")]
38    Metadata(#[from] crate::metadata::Error),
39
40    #[error("journal error: {0}")]
41    Journal(#[from] crate::journal::Error),
42
43    #[error("operation pruned: {0}")]
44    OperationPruned(u64),
45
46    /// The requested key was not found in the snapshot.
47    #[error("key not found")]
48    KeyNotFound,
49}
50
51/// Utility to align the sizes of an MMR and location journal pair, used by keyless, immutable &
52/// variable adb recovery. Returns the aligned size.
53async fn align_mmr_and_locations<E: Storage + Clock + Metrics, H: Hasher>(
54    mmr: &mut journaled::Mmr<E, H>,
55    locations: &mut Journal<E, u32>,
56) -> Result<u64, Error> {
57    let aligned_size = {
58        let locations_size = locations.size().await?;
59        let mmr_leaves = mmr.leaves();
60        if locations_size > mmr_leaves {
61            warn!(
62                mmr_leaves,
63                locations_size, "rewinding misaligned locations journal"
64            );
65            locations.rewind(mmr_leaves).await?;
66            locations.sync().await?;
67            mmr_leaves
68        } else if mmr_leaves > locations_size {
69            warn!(mmr_leaves, locations_size, "rewinding misaligned mmr");
70            mmr.pop((mmr_leaves - locations_size) as usize).await?;
71            locations_size
72        } else {
73            locations_size // happy path
74        }
75    };
76
77    // Verify post-conditions hold.
78    assert_eq!(aligned_size, locations.size().await?);
79    assert_eq!(aligned_size, mmr.leaves());
80
81    Ok(aligned_size)
82}