use crate::{
journal::{
authenticated,
contiguous::{Contiguous as _, Mutable},
},
merkle::{
full::{self, Merkle},
Family, Location,
},
qmdb::{
self,
any::value::ValueEncoding,
keyless::{operation::Codec, CompactDb, Keyless, Metrics, Operation},
sync,
},
Context,
};
use commonware_codec::{EncodeShared, Read};
use commonware_cryptography::Hasher;
use commonware_parallel::Strategy;
use commonware_utils::range::NonEmptyRange;
impl<F, E, V, C, H, S> sync::Database for Keyless<F, E, V, C, H, S>
where
F: Family,
E: Context,
V: ValueEncoding + Codec,
C: Mutable<Item = Operation<F, V>> + sync::Journal<F, Context = E, Op = Operation<F, V>>,
C::Config: Clone + Send,
H: Hasher,
S: Strategy,
Operation<F, V>: EncodeShared,
{
type Family = F;
type Op = Operation<F, V>;
type Journal = C;
type Hasher = H;
type Config = super::Config<C::Config, S>;
type Digest = H::Digest;
type Context = E;
async fn from_sync_result(
context: Self::Context,
config: Self::Config,
log: Self::Journal,
pinned_nodes: Option<Vec<Self::Digest>>,
range: NonEmptyRange<Location<F>>,
apply_batch_size: usize,
) -> Result<Self, qmdb::Error<F>> {
let hasher = qmdb::hasher::<H>();
let merkle = Merkle::<F, _, _, S>::init_sync(
context.child("merkle"),
full::SyncConfig {
config: config.merkle.clone(),
range: range.clone(),
pinned_nodes,
},
)
.await?;
let journal = authenticated::Journal::<F, _, _, _, S>::from_components(
merkle,
log,
hasher,
apply_batch_size as u64,
)
.await?;
let (last_commit_loc, inactivity_floor_loc) = {
let bounds = journal.bounds();
let loc = bounds
.end
.checked_sub(1)
.ok_or(qmdb::Error::HistoricalFloorPruned(Location::new(
bounds.end,
)))?;
let floor =
qmdb::find_inactivity_floor_at::<F, _>(&journal, Location::new(bounds.end), |op| {
op.has_floor()
})
.await?;
(Location::new(loc), floor)
};
let inactive_peaks = F::inactive_peaks(
F::location_to_position(Location::new(*last_commit_loc + 1)),
inactivity_floor_loc,
);
let root = journal.root(inactive_peaks)?;
let metrics = Metrics::new(context);
let mut db = Self {
journal,
root,
last_commit_loc,
inactivity_floor_loc,
metrics,
};
db.update_metrics();
db.sync().await?;
Ok(db)
}
async fn local_boundary_nodes(
context: Self::Context,
config: &Self::Config,
target: &sync::Target<F, Self::Digest>,
journal: &Self::Journal,
) -> Result<Option<Vec<Self::Digest>>, qmdb::Error<F>> {
if target.range.start() == Location::new(0)
|| !sync::journal_covers_range(journal.bounds(), &target.range)
{
return Ok(None);
}
let inactivity_floor =
qmdb::find_inactivity_floor_at::<F, _>(journal, target.range.end(), |op| {
op.has_floor()
})
.await?;
sync::local_boundary_nodes::<F, _, H, S>(
context,
config.merkle.clone(),
target,
inactivity_floor,
)
.await
}
fn root(&self) -> Self::Digest {
self.root()
}
}
impl<F, E, V, H, Cfg, S> sync::compact::Database for CompactDb<F, E, V, H, Cfg, S>
where
F: Family,
E: Context,
V: ValueEncoding + Codec,
H: Hasher,
S: Strategy,
Operation<F, V>: EncodeShared,
Operation<F, V>: Read<Cfg = Cfg>,
Cfg: Clone + Send + Sync + 'static,
{
type Family = F;
type Op = Operation<F, V>;
type Config = super::CompactConfig<Cfg, S>;
type Digest = H::Digest;
type Context = E;
type Hasher = H;
async fn from_validated_state(
context: Self::Context,
config: Self::Config,
state: sync::compact::ValidatedState<Self::Family, Self::Op, Self::Digest>,
) -> Result<Self, qmdb::Error<F>> {
let journal: crate::qmdb::compact::witness::Journal<E, F, H::Digest> =
crate::journal::contiguous::variable::Journal::init(
context.child("witness"),
config.witness,
)
.await?;
Self::init_from_validated_state(config.strategy, journal, config.commit_codec_config, state)
}
fn inactivity_floor(op: &Self::Op) -> Option<Location<Self::Family>> {
op.has_floor()
}
fn root(&self) -> Self::Digest {
self.root()
}
async fn persist_compact_state(&mut self) -> Result<(), qmdb::Error<F>> {
self.sync().await
}
}
#[cfg(test)]
mod tests;