mod backend;
mod config;
mod error;
mod history;
mod iterator;
mod lineage;
mod operation;
mod property_tests;
mod root;
mod test_utils;
mod tests;
mod utils;
use alloc::vec::Vec;
use core::num::NonZeroU8;
pub use backend::{Backend, BackendError, memory::InMemoryBackend};
#[cfg(feature = "persistent-forest")]
pub use backend::{
persistent::PersistentBackend, persistent::config::Config as PersistentBackendConfig,
};
pub use config::{Config, DEFAULT_MAX_HISTORY_VERSIONS, MIN_HISTORY_VERSIONS};
pub use error::{LargeSmtForestError, Result};
pub use operation::{ForestOperation, SmtForestUpdateBatch, SmtUpdateBatch};
pub use root::{LineageId, RootInfo, TreeEntry, TreeId, TreeWithRoot, VersionId};
use crate::{
EMPTY_WORD, Map, Set, Word,
merkle::{
NodeIndex, SparseMerklePath,
smt::{
LeafIndex, SMT_DEPTH, SmtLeaf, SmtProof,
large_forest::{
history::{History, HistoryView},
iterator::EntriesIterator,
lineage::LineageData,
root::{RootValue, UniqueRoot},
},
},
},
};
#[derive(Debug)]
pub struct LargeSmtForest<B: Backend> {
config: Config,
backend: B,
lineage_data: Map<LineageId, LineageData>,
non_empty_histories: Set<LineageId>,
}
impl<B: Backend + Clone> Clone for LargeSmtForest<B> {
fn clone(&self) -> Self {
Self {
config: self.config.clone(),
backend: self.backend.clone(),
lineage_data: self.lineage_data.clone(),
non_empty_histories: self.non_empty_histories.clone(),
}
}
}
impl<B: Backend> LargeSmtForest<B> {
pub fn new(backend: B) -> Result<Self> {
Self::with_config(backend, Config::default())
}
pub fn with_config(backend: B, config: Config) -> Result<Self> {
let lineage_data = backend
.trees()?
.map(|t| {
let data = LineageData {
history: History::empty(config.max_history_versions()),
latest_version: t.version(),
latest_root: t.root(),
};
(t.lineage(), data)
})
.collect::<Map<LineageId, LineageData>>();
let non_empty_histories = Set::default();
Ok(Self {
config,
backend,
lineage_data,
non_empty_histories,
})
}
}
impl<B: Backend> LargeSmtForest<B> {
pub fn roots(&self) -> impl Iterator<Item = UniqueRoot> {
self.lineage_data
.iter()
.flat_map(|(l, d)| d.roots().map(|r| UniqueRoot::new(*l, r)))
}
pub fn latest_version(&self, lineage: LineageId) -> Option<VersionId> {
self.lineage_data.get(&lineage).map(|d| d.latest_version)
}
pub fn lineage_roots(&self, lineage: LineageId) -> Option<impl Iterator<Item = RootValue>> {
self.lineage_data.get(&lineage).map(LineageData::roots)
}
pub fn latest_root(&self, lineage: LineageId) -> Option<RootValue> {
self.lineage_data.get(&lineage).map(|d| d.latest_root)
}
pub fn tree_count(&self) -> usize {
self.roots().count()
}
pub fn lineage_count(&self) -> usize {
self.lineage_data.len()
}
pub fn root_info(&self, root: TreeId) -> RootInfo {
let Some(d) = self.lineage_data.get(&root.lineage()) else {
return RootInfo::Missing;
};
if d.latest_version == root.version() {
return RootInfo::LatestVersion(d.latest_root);
}
if root.version() > d.latest_version {
return RootInfo::Missing;
}
match d.history.root_for_version(root.version()) {
Ok(r) => RootInfo::HistoricalVersion(r),
Err(_) => RootInfo::Missing,
}
}
pub fn truncate(&mut self, version: VersionId) {
let mut newly_empty = Set::default();
self.non_empty_histories.iter().for_each(|l| {
if let Some(d) = self.lineage_data.get_mut(l)
&& d.truncate(version)
{
newly_empty.insert(*l);
}
});
for l in &newly_empty {
self.non_empty_histories.remove(l);
}
}
}
impl<B: Backend> LargeSmtForest<B> {
pub fn open(&self, tree: TreeId, key: Word) -> Result<SmtProof> {
let lineage_data = self
.lineage_data
.get(&tree.lineage())
.ok_or(LargeSmtForestError::UnknownLineage(tree.lineage()))?;
if tree.version() > lineage_data.latest_version {
return Err(LargeSmtForestError::UnknownTree(tree));
}
if tree.version() == lineage_data.latest_version {
return self.backend.open(tree.lineage(), key).map_err(Into::into);
}
let Ok(view) = lineage_data.history.get_view_at(tree.version()) else {
return Err(LargeSmtForestError::UnknownTree(tree));
};
let leaf_index = LeafIndex::from(key);
let opening = self
.backend
.open(tree.lineage(), key)
.map_err(Into::<LargeSmtForestError>::into)?;
let sibling_leaf_index =
LeafIndex::new_max_depth(NodeIndex::from(leaf_index).sibling().position());
let mut target_leaf_changes = Vec::new();
let mut sibling_leaf_changes = Vec::new();
for (k, v) in view.changed_keys() {
let key_leaf = LeafIndex::from(k);
if key_leaf == leaf_index {
target_leaf_changes.push((k, v));
} else if key_leaf == sibling_leaf_index {
sibling_leaf_changes.push((k, v));
}
}
let new_leaf = Self::merge_leaves(opening.leaf(), view, &target_leaf_changes)?;
let new_path = Self::merge_paths(
&self.backend,
tree.lineage(),
leaf_index,
opening.path(),
view,
&sibling_leaf_changes,
)?;
Ok(SmtProof::new(new_path, new_leaf)?)
}
pub fn get(&self, tree: TreeId, key: Word) -> Result<Option<Word>> {
let lineage_data = self
.lineage_data
.get(&tree.lineage())
.ok_or(LargeSmtForestError::UnknownLineage(tree.lineage()))?;
if tree.version() > lineage_data.latest_version {
return Err(LargeSmtForestError::UnknownTree(tree));
}
if tree.version() == lineage_data.latest_version {
return self.backend.get(tree.lineage(), key).map_err(Into::into);
}
let Ok(view) = lineage_data.history.get_view_at(tree.version()) else {
return Err(LargeSmtForestError::UnknownTree(tree));
};
let result = if let Some(value) = view.value(&key) {
if value == EMPTY_WORD { None } else { Some(value) }
} else {
self.backend.get(tree.lineage(), key)?
};
Ok(result)
}
pub fn entry_count(&self, tree: TreeId) -> Result<usize> {
let Some(lineage_data) = self.lineage_data.get(&tree.lineage()) else {
return Err(LargeSmtForestError::UnknownLineage(tree.lineage()));
};
if tree.version() > lineage_data.latest_version {
return Err(LargeSmtForestError::UnknownTree(tree));
}
if tree.version() == lineage_data.latest_version {
return Ok(self.backend.entry_count(tree.lineage())?);
}
let Ok(view) = lineage_data.history.get_view_at(tree.version()) else {
return Err(LargeSmtForestError::UnknownTree(tree));
};
Ok(view.entry_count())
}
pub fn entries(&self, tree: TreeId) -> Result<impl Iterator<Item = Result<TreeEntry>>> {
let Some(lineage_data) = self.lineage_data.get(&tree.lineage()) else {
return Err(LargeSmtForestError::UnknownLineage(tree.lineage()));
};
if tree.version() > lineage_data.latest_version {
return Err(LargeSmtForestError::UnknownTree(tree));
}
if tree.version() == lineage_data.latest_version {
return Ok(EntriesIterator::new_without_history(self.backend.entries(tree.lineage())?));
}
let Ok(view) = lineage_data.history.get_view_at(tree.version()) else {
return Err(LargeSmtForestError::UnknownTree(tree));
};
Ok(EntriesIterator::new_with_history(self.backend.entries(tree.lineage())?, view))
}
}
impl<B: Backend> LargeSmtForest<B> {
pub fn add_lineage(
&mut self,
lineage: LineageId,
new_version: VersionId,
updates: SmtUpdateBatch,
) -> Result<TreeWithRoot> {
let tree_info = self.backend.add_lineage(lineage, new_version, updates)?;
let lineage_data = LineageData {
history: History::empty(self.config.max_history_versions()),
latest_version: tree_info.version(),
latest_root: tree_info.root(),
};
self.lineage_data.insert(lineage, lineage_data);
Ok(tree_info)
}
pub fn update_tree(
&mut self,
lineage: LineageId,
new_version: VersionId,
updates: SmtUpdateBatch,
) -> Result<TreeWithRoot> {
let lineage_data = if let Some(lineage_data) = self.lineage_data.get_mut(&lineage) {
if lineage_data.latest_version < new_version {
lineage_data
} else {
return Err(LargeSmtForestError::BadVersion {
provided: new_version,
latest: lineage_data.latest_version,
});
}
} else {
return Err(LargeSmtForestError::UnknownLineage(lineage));
};
let old_entry_count = self.backend.entry_count(lineage)?;
let reversion_set = self.backend.update_tree(lineage, new_version, updates)?;
if reversion_set.is_empty() {
return Ok(TreeWithRoot::new(
lineage,
lineage_data.latest_version,
lineage_data.latest_root,
));
}
let updated_root = reversion_set.old_root;
lineage_data
.history
.add_version_from_mutation_set(
lineage_data.latest_version,
reversion_set,
old_entry_count,
)
.unwrap_or_else(|_| {
panic!("Unable to add valid version {} to history", lineage_data.latest_version)
});
self.non_empty_histories.insert(lineage);
lineage_data.latest_root = updated_root;
lineage_data.latest_version = new_version;
Ok(TreeWithRoot::new(lineage, new_version, updated_root))
}
}
impl<B: Backend> LargeSmtForest<B> {
pub fn add_lineages(
&mut self,
version: VersionId,
lineages: SmtForestUpdateBatch,
) -> Result<Vec<TreeWithRoot>> {
for lineage in lineages.lineages() {
if self.lineage_data.contains_key(lineage) {
return Err(LargeSmtForestError::DuplicateLineage(*lineage));
}
}
let results = self.backend.add_lineages(version, lineages)?;
results
.into_iter()
.map(|(lineage, tree_info)| {
let lineage_data = LineageData {
history: History::empty(self.config.max_history_versions()),
latest_version: tree_info.version(),
latest_root: tree_info.root(),
};
self.lineage_data.insert(lineage, lineage_data);
Ok(tree_info)
})
.collect()
}
pub fn update_forest(
&mut self,
new_version: VersionId,
updates: SmtForestUpdateBatch,
) -> Result<Vec<TreeWithRoot>> {
updates
.lineages()
.map(|lineage| {
let Some(lineage_data) = self.lineage_data.get(lineage) else {
return Err(LargeSmtForestError::UnknownLineage(*lineage));
};
if lineage_data.latest_version < new_version {
Ok(())
} else {
Err(LargeSmtForestError::BadVersion {
provided: new_version,
latest: lineage_data.latest_version,
})
}
})
.collect::<Result<Vec<_>>>()?;
let old_entry_counts: Map<LineageId, usize> = updates
.lineages()
.map(|lineage| Ok((*lineage, self.backend.entry_count(*lineage)?)))
.collect::<Result<_>>()?;
let reversion_sets = self.backend.update_forest(new_version, updates)?;
reversion_sets
.into_iter()
.map(|(lineage, reversion)| {
let old_entry_count = old_entry_counts[&lineage];
let lineage_data = self
.lineage_data
.get_mut(&lineage)
.expect("Lineage has been checked to be present");
if reversion.is_empty() {
return Ok(TreeWithRoot::new(
lineage,
lineage_data.latest_version,
lineage_data.latest_root,
));
}
let updated_root = reversion.old_root;
lineage_data
.history
.add_version_from_mutation_set(
lineage_data.latest_version,
reversion,
old_entry_count,
)
.unwrap_or_else(|_| {
panic!(
"Unable to add valid version {} to history",
lineage_data.latest_version
)
});
self.non_empty_histories.insert(lineage);
lineage_data.latest_root = updated_root;
lineage_data.latest_version = new_version;
Ok(TreeWithRoot::new(lineage, new_version, updated_root))
})
.collect::<Result<Vec<_>>>()
}
}
impl<B: Backend> LargeSmtForest<B> {
fn merge_leaves(
full_tree_leaf: &SmtLeaf,
history_view: HistoryView,
leaf_changes: &[(Word, Word)],
) -> Result<SmtLeaf> {
let mut leaf_entries = Map::new();
for (k, v) in full_tree_leaf.to_entries() {
if history_view.is_key_removed(k) {
continue;
}
leaf_entries.insert(*k, *v);
}
leaf_entries.extend(leaf_changes.iter().filter(|(_, v)| !v.is_empty()).copied());
debug_assert!(
leaf_entries.iter().all(|(_, v)| !v.is_empty()),
"Leaf entries should not contain entries with empty values"
);
let mut entries = leaf_entries.into_iter().collect::<Vec<_>>();
entries.sort_by_key(|(key, value)| (*key, *value));
Ok(SmtLeaf::new(entries, full_tree_leaf.index())?)
}
fn merge_paths(
backend: &B,
lineage: LineageId,
leaf_index: LeafIndex<SMT_DEPTH>,
full_tree_path: &SparseMerklePath,
history_view: HistoryView,
sibling_leaf_changes: &[(Word, Word)],
) -> Result<SparseMerklePath> {
let mut path_elems = [EMPTY_WORD; SMT_DEPTH as usize];
let mut current_node_ix = NodeIndex::from(leaf_index);
for depth in (1..=SMT_DEPTH).rev() {
let path_node_ix = current_node_ix.sibling();
if let Some(historical_value) = history_view.node_value(&path_node_ix) {
path_elems[depth as usize - 1] = *historical_value;
} else if path_node_ix.depth() == SMT_DEPTH {
if !sibling_leaf_changes.is_empty() {
let sibling_leaf_index = LeafIndex::new_max_depth(path_node_ix.position());
let sibling_leaf = backend.get_leaf(lineage, sibling_leaf_index)?;
let sibling_leaf =
Self::merge_leaves(&sibling_leaf, history_view, sibling_leaf_changes)?;
path_elems[depth as usize - 1] = sibling_leaf.hash();
} else {
let bounded_depth = NonZeroU8::new(depth).expect("depth ∈ 1 ..= SMT_DEPTH]");
path_elems[depth as usize - 1] = full_tree_path.at_depth(bounded_depth)?;
}
} else {
let bounded_depth = NonZeroU8::new(depth).expect("depth ∈ 1 ..= SMT_DEPTH]");
path_elems[depth as usize - 1] = full_tree_path.at_depth(bounded_depth)?
}
current_node_ix = current_node_ix.parent();
}
Ok(SparseMerklePath::from_sized_iter(path_elems.into_iter().rev())?)
}
}
#[cfg(test)]
impl<B: Backend> LargeSmtForest<B> {
pub fn get_backend(&self) -> &B {
&self.backend
}
pub fn get_backend_mut(&mut self) -> &mut B {
&mut self.backend
}
pub fn get_config(&self) -> &Config {
&self.config
}
pub fn get_history(&self, lineage: LineageId) -> &History {
self.lineage_data
.get(&lineage)
.map(|d| &d.history)
.unwrap_or_else(|| panic!("Lineage {lineage} had no data"))
}
pub fn get_non_empty_histories(&self) -> &Set<LineageId> {
&self.non_empty_histories
}
}