Skip to content

Commit

Permalink
smt: add from_raw_parts() to trait interface
Browse files Browse the repository at this point in the history
This commit adds a new required method to the SparseMerkleTree trait,
to allow generic construction from pre-computed parts.

This will be used to add a generic version of `with_entries()` in a
later commit.
  • Loading branch information
Qyriad committed Nov 15, 2024
1 parent 5cc527f commit 9f0245b
Show file tree
Hide file tree
Showing 3 changed files with 70 additions and 0 deletions.
30 changes: 30 additions & 0 deletions src/merkle/smt/full/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,23 @@ impl Smt {
Ok(tree)
}

/// Returns a new [`Smt`] instantiated from already computed leaves and nodes.
///
/// This function performs minimal consistency checking. It is the caller's responsibility to
/// ensure the passed arguments are correct and consistent with each other.
///
/// # Panics
/// With debug assertions on, this function panics if `root` does not match the root node in
/// `inner_nodes`.
pub fn from_raw_parts(
inner_nodes: BTreeMap<NodeIndex, InnerNode>,
leaves: BTreeMap<u64, SmtLeaf>,
root: RpoDigest,
) -> Self {
// Our particular implementation of `from_raw_parts()` never returns `Err`.
<Self as SparseMerkleTree<SMT_DEPTH>>::from_raw_parts(inner_nodes, leaves, root).unwrap()
}

// PUBLIC ACCESSORS
// --------------------------------------------------------------------------------------------

Expand Down Expand Up @@ -280,6 +297,19 @@ impl SparseMerkleTree<SMT_DEPTH> for Smt {
const EMPTY_VALUE: Self::Value = EMPTY_WORD;
const EMPTY_ROOT: RpoDigest = *EmptySubtreeRoots::entry(SMT_DEPTH, 0);

fn from_raw_parts(
inner_nodes: BTreeMap<NodeIndex, InnerNode>,
leaves: BTreeMap<u64, SmtLeaf>,
root: RpoDigest,
) -> Result<Self, MerkleError> {
if cfg!(debug_assertions) {
let root_node = inner_nodes.get(&NodeIndex::root()).unwrap();
assert_eq!(root_node.hash(), root);
}

Ok(Self { root, inner_nodes, leaves })
}

fn root(&self) -> RpoDigest {
self.root
}
Expand Down
10 changes: 10 additions & 0 deletions src/merkle/smt/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -292,6 +292,16 @@ pub(crate) trait SparseMerkleTree<const DEPTH: u8> {
// REQUIRED METHODS
// ---------------------------------------------------------------------------------------------

/// Construct this type from already computed leaves and nodes. The caller ensures passed
/// arguments are correct and consistent with each other.
fn from_raw_parts(
inner_nodes: BTreeMap<NodeIndex, InnerNode>,
leaves: BTreeMap<u64, Self::Leaf>,
root: RpoDigest,
) -> Result<Self, MerkleError>
where
Self: Sized;

/// The root of the tree
fn root(&self) -> RpoDigest;

Expand Down
30 changes: 30 additions & 0 deletions src/merkle/smt/simple/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,23 @@ impl<const DEPTH: u8> SimpleSmt<DEPTH> {
Ok(tree)
}

/// Returns a new [`SimpleSmt`] instantiated from already computed leaves and nodes.
///
/// This function performs minimal consistency checking. It is the caller's responsibility to
/// ensure the passed arguments are correct and consistent with each other.
///
/// # Panics
/// With debug assertions on, this function panics if `root` does not match the root node in
/// `inner_nodes`.
pub fn from_raw_parts(
inner_nodes: BTreeMap<NodeIndex, InnerNode>,
leaves: BTreeMap<u64, Word>,
root: RpoDigest,
) -> Self {
// Our particular implementation of `from_raw_parts()` never returns `Err`.
<Self as SparseMerkleTree<DEPTH>>::from_raw_parts(inner_nodes, leaves, root).unwrap()
}

/// Wrapper around [`SimpleSmt::with_leaves`] which inserts leaves at contiguous indices
/// starting at index 0.
pub fn with_contiguous_leaves(
Expand Down Expand Up @@ -309,6 +326,19 @@ impl<const DEPTH: u8> SparseMerkleTree<DEPTH> for SimpleSmt<DEPTH> {
const EMPTY_VALUE: Self::Value = EMPTY_WORD;
const EMPTY_ROOT: RpoDigest = *EmptySubtreeRoots::entry(DEPTH, 0);

fn from_raw_parts(
inner_nodes: BTreeMap<NodeIndex, InnerNode>,
leaves: BTreeMap<u64, Word>,
root: RpoDigest,
) -> Result<Self, MerkleError> {
if cfg!(debug_assertions) {
let root_node = inner_nodes.get(&NodeIndex::root()).unwrap();
assert_eq!(root_node.hash(), root);
}

Ok(Self { root, inner_nodes, leaves })
}

fn root(&self) -> RpoDigest {
self.root
}
Expand Down

0 comments on commit 9f0245b

Please sign in to comment.