use crate::{
merkle::{full, Family, Location},
qmdb::sync::{Journal, Target},
translator::Translator,
Context,
};
use commonware_cryptography::{Digest, Hasher};
use commonware_parallel::Strategy;
use commonware_utils::range::NonEmptyRange;
use std::future::Future;
pub trait Config {
type JournalConfig;
fn journal_config(&self) -> Self::JournalConfig;
}
impl<T: Translator, J: Clone, S: Strategy> Config for crate::qmdb::any::Config<T, J, S> {
type JournalConfig = J;
fn journal_config(&self) -> Self::JournalConfig {
self.journal_config.clone()
}
}
impl<T: Translator, C: Clone, S: Strategy> Config for crate::qmdb::immutable::Config<T, C, S> {
type JournalConfig = C;
fn journal_config(&self) -> Self::JournalConfig {
self.log.clone()
}
}
impl<J: Clone, S: Strategy> Config for crate::qmdb::keyless::Config<J, S> {
type JournalConfig = J;
fn journal_config(&self) -> Self::JournalConfig {
self.log.clone()
}
}
pub trait Database: Sized + Send {
type Family: Family;
type Op: Send;
type Journal: Journal<Self::Family, Context = Self::Context, Op = Self::Op>;
type Config: Config<JournalConfig = <Self::Journal as Journal<Self::Family>>::Config>;
type Digest: Digest;
type Context: commonware_runtime::Storage
+ commonware_runtime::Clock
+ commonware_runtime::Metrics;
type Hasher: commonware_cryptography::Hasher<Digest = Self::Digest>;
fn from_sync_result(
context: Self::Context,
config: Self::Config,
journal: Self::Journal,
pinned_nodes: Option<Vec<Self::Digest>>,
range: NonEmptyRange<Location<Self::Family>>,
apply_batch_size: usize,
) -> impl Future<Output = Result<Self, crate::qmdb::Error<Self::Family>>> + Send;
fn local_boundary_nodes(
context: Self::Context,
config: &Self::Config,
target: &crate::qmdb::sync::Target<Self::Family, Self::Digest>,
journal: &Self::Journal,
) -> impl Future<Output = Result<Option<Vec<Self::Digest>>, crate::qmdb::Error<Self::Family>>> + Send;
fn root(&self) -> Self::Digest;
}
pub(crate) fn journal_covers_range<F: Family>(
bounds: std::ops::Range<u64>,
range: &NonEmptyRange<Location<F>>,
) -> bool {
Location::new(bounds.start) <= range.start() && Location::new(bounds.end) == range.end()
}
pub(crate) async fn local_boundary_nodes<F, E, H, S>(
context: E,
config: full::Config<S>,
target: &Target<F, H::Digest>,
inactivity_floor: Location<F>,
) -> Result<Option<Vec<H::Digest>>, crate::qmdb::Error<F>>
where
F: Family,
E: Context,
H: Hasher,
S: Strategy,
{
let hasher = crate::qmdb::hasher::<H>();
let merkle = full::Merkle::<F, _, _, S>::init(context, &hasher, config).await?;
let bounds = merkle.bounds();
if bounds.start > target.range.start() || bounds.end != target.range.end() {
return Ok(None);
}
let inactive_peaks = F::inactive_peaks(
F::location_to_position(target.range.end()),
inactivity_floor,
);
if merkle.root(&hasher, inactive_peaks)? != target.root {
return Ok(None);
}
merkle
.pinned_nodes_at(target.range.start())
.await
.map(Some)
.map_err(Into::into)
}