Skip to content

Commit

Permalink
fix: supporting commit for non modified trees
Browse files Browse the repository at this point in the history
  • Loading branch information
nimrod-starkware committed Jun 9, 2024
1 parent d26e0e5 commit 006181c
Show file tree
Hide file tree
Showing 6 changed files with 76 additions and 2 deletions.
2 changes: 1 addition & 1 deletion crates/committer/src/hash/hash_trait.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,5 +6,5 @@ pub struct HashOutput(pub Felt);
impl HashOutput {
#[allow(dead_code)]
pub(crate) const ZERO: HashOutput = HashOutput(Felt::ZERO);
pub(crate) const ROOT_OF_EMPTY_TREE: HashOutput = Self::ZERO;
pub const ROOT_OF_EMPTY_TREE: HashOutput = Self::ZERO;
}
16 changes: 16 additions & 0 deletions crates/committer/src/patricia_merkle_tree/filled_tree/tree.rs
Original file line number Diff line number Diff line change
Expand Up @@ -185,6 +185,19 @@ impl FilledTreeImpl {
}
}
}

fn create_unmodified(
updated_skeleton: impl UpdatedSkeletonTree,
) -> Result<Self, FilledTreeError<LeafDataImpl>> {
let root_node = updated_skeleton.get_node(NodeIndex::ROOT)?;
let UpdatedSkeletonNode::UnmodifiedSubTree(root_hash) = root_node else {
panic!("A root of tree without modifications is expected to be a unmodified subtree.")
};
Ok(Self {
tree_map: HashMap::new(),
root_hash: *root_hash,
})
}
}

impl FilledTree<LeafDataImpl> for FilledTreeImpl {
Expand All @@ -195,6 +208,9 @@ impl FilledTree<LeafDataImpl> for FilledTreeImpl {
// Compute the filled tree in two steps:
// 1. Create a map containing the tree structure without hash values.
// 2. Fill in the hash values.
if leaf_modifications.is_empty() {
return Self::create_unmodified(updated_skeleton);
}
let filled_tree_map = Arc::new(Self::initialize_with_placeholders(&updated_skeleton));
let root_hash = Self::compute_filled_tree_rec::<TH>(
Arc::new(updated_skeleton),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -178,6 +178,14 @@ impl OriginalSkeletonTreeImpl {
sorted_leaf_indices: &[NodeIndex],
root_hash: HashOutput,
) -> OriginalSkeletonTreeResult<Self> {
if sorted_leaf_indices.is_empty() {
return Ok(Self {
nodes: HashMap::from([(
NodeIndex::ROOT,
OriginalSkeletonNode::UnmodifiedSubTree(root_hash),
)]),
});
}
if root_hash == HashOutput::ROOT_OF_EMPTY_TREE {
return Ok(Self {
nodes: HashMap::new(),
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
use std::collections::HashMap;

use crate::patricia_merkle_tree::node_data::inner_node::EdgePathLength;
use crate::patricia_merkle_tree::node_data::inner_node::PathToBottom;
use crate::patricia_merkle_tree::node_data::leaf::LeafModifications;
Expand All @@ -7,9 +9,11 @@ use crate::patricia_merkle_tree::original_skeleton_tree::tree::OriginalSkeletonN
use crate::patricia_merkle_tree::original_skeleton_tree::tree::OriginalSkeletonTree;
use crate::patricia_merkle_tree::original_skeleton_tree::utils::split_leaves;
use crate::patricia_merkle_tree::types::NodeIndex;
use crate::patricia_merkle_tree::updated_skeleton_tree::errors::UpdatedSkeletonTreeError;
use crate::patricia_merkle_tree::updated_skeleton_tree::node::UpdatedSkeletonNode;
use crate::patricia_merkle_tree::updated_skeleton_tree::tree::UpdatedSkeletonNodeMap;
use crate::patricia_merkle_tree::updated_skeleton_tree::tree::UpdatedSkeletonTreeImpl;
use crate::patricia_merkle_tree::updated_skeleton_tree::tree::UpdatedSkeletonTreeResult;

#[cfg(test)]
#[path = "compute_updated_skeleton_tree_test.rs"]
Expand Down Expand Up @@ -397,4 +401,23 @@ impl UpdatedSkeletonTreeImpl {

self.node_from_edge_data(&path_to_new_bottom, &new_bottom_index, &bottom)
}

pub(crate) fn create_unmodified(
original_skeleton: &impl OriginalSkeletonTree,
) -> UpdatedSkeletonTreeResult<Self> {
let original_root_node = original_skeleton
.get_nodes()
.get(&NodeIndex::ROOT)
.ok_or(UpdatedSkeletonTreeError::MissingNode(NodeIndex::ROOT))?;
let OriginalSkeletonNode::UnmodifiedSubTree(root_hash) = original_root_node else {
panic!("A root of tree without modifications is expected to be an unmodified node.")
};

Ok(Self {
skeleton_tree: HashMap::from([(
NodeIndex::ROOT,
UpdatedSkeletonNode::UnmodifiedSubTree(*root_hash),
)]),
})
}
}
Original file line number Diff line number Diff line change
@@ -1,19 +1,26 @@
use ethnum::U256;
use pretty_assertions::assert_eq;
use rstest::{fixture, rstest};
use std::collections::HashMap;

use crate::felt::Felt;
use crate::hash::hash_trait::HashOutput;
use crate::patricia_merkle_tree::filled_tree::tree::{FilledTree, FilledTreeImpl};
use crate::patricia_merkle_tree::node_data::inner_node::{EdgePathLength, PathToBottom};
use crate::patricia_merkle_tree::original_skeleton_tree::node::OriginalSkeletonNode;
use crate::patricia_merkle_tree::original_skeleton_tree::tree::OriginalSkeletonNodeMap;
use crate::patricia_merkle_tree::original_skeleton_tree::tree::OriginalSkeletonTreeImpl;
use crate::patricia_merkle_tree::test_utils::small_tree_index_to_full;
use crate::patricia_merkle_tree::types::{NodeIndex, SubTreeHeight};
use crate::patricia_merkle_tree::updated_skeleton_tree::compute_updated_skeleton_tree::{
get_path_to_lca, has_leaves_on_both_sides, TempSkeletonNode,
};
use crate::patricia_merkle_tree::updated_skeleton_tree::node::UpdatedSkeletonNode;
use crate::patricia_merkle_tree::updated_skeleton_tree::tree::UpdatedSkeletonTreeImpl;
use crate::patricia_merkle_tree::updated_skeleton_tree::{
hash_function::TreeHashFunctionImpl, tree::UpdatedSkeletonTree,
};
use crate::storage::map_storage::MapStorage;

#[fixture]
fn updated_skeleton(
Expand Down Expand Up @@ -490,3 +497,18 @@ pub(crate) fn as_fully_indexed(
.map(|index| NodeIndex::from_subtree_index(index, SubTreeHeight::new(subtree_height)))
.collect()
}

#[rstest]
#[case::empty_tree(HashOutput::ROOT_OF_EMPTY_TREE)]
#[case::non_empty_tree(HashOutput(Felt::from(77_u128)))]
#[tokio::test]
async fn test_update_non_modified_tree(#[case] root_hash: HashOutput) {
let mut original_skeleton_tree =
OriginalSkeletonTreeImpl::create_impl(&MapStorage::default(), &[], root_hash).unwrap();
let updated =
UpdatedSkeletonTreeImpl::create(&mut original_skeleton_tree, &HashMap::new()).unwrap();
let filled = FilledTreeImpl::create::<TreeHashFunctionImpl>(updated, HashMap::new())
.await
.unwrap();
assert_eq!(root_hash, filled.get_root_hash());
}
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,9 @@ impl UpdatedSkeletonTree for UpdatedSkeletonTreeImpl {
original_skeleton: &mut impl OriginalSkeletonTree,
leaf_modifications: &LeafModifications<SkeletonLeaf>,
) -> UpdatedSkeletonTreeResult<Self> {
if leaf_modifications.is_empty() {
return Self::create_unmodified(original_skeleton);
}
let skeleton_tree = Self::finalize_bottom_layer(original_skeleton, leaf_modifications);

let mut updated_skeleton_tree = UpdatedSkeletonTreeImpl { skeleton_tree };
Expand All @@ -64,7 +67,9 @@ impl UpdatedSkeletonTree for UpdatedSkeletonTreeImpl {
UpdatedSkeletonNode::Edge(path_to_bottom)
}
OriginalSkeletonNode::UnmodifiedSubTree(_) => {
unreachable!("Root node cannot be unmodified.")
unreachable!(
"Root node cannot be unmodified when there are some modifications."
)
}
};

Expand Down

0 comments on commit 006181c

Please sign in to comment.