Skip to content

Commit

Permalink
refactor: move updated skeleton and original skeleton to sub director…
Browse files Browse the repository at this point in the history
…ies (#57)
  • Loading branch information
AvivYossef-starkware authored Apr 21, 2024
1 parent 869bec1 commit 1e9eb88
Show file tree
Hide file tree
Showing 12 changed files with 218 additions and 217 deletions.
3 changes: 0 additions & 3 deletions crates/committer/src/patricia_merkle_tree.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,5 @@
pub mod errors;
pub mod filled_tree;
pub mod original_skeleton_calc;
pub mod original_skeleton_node;
pub mod original_skeleton_tree;
pub mod types;
pub mod updated_skeleton_node;
pub mod updated_skeleton_tree;
3 changes: 0 additions & 3 deletions crates/committer/src/patricia_merkle_tree/filled_tree/node.rs
Original file line number Diff line number Diff line change
Expand Up @@ -70,9 +70,6 @@ impl LeafDataTrait for LeafData {
}
}

#[allow(dead_code)]
impl FilledNode<LeafData> {}

impl LeafData {
/// Serializes the leaf data into a byte vector.
/// The serialization is done as follows:
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use crate::hash::hash_trait::HashOutput;
use crate::patricia_merkle_tree::filled_tree::node::{BinaryData, FilledNode, LeafData, NodeData};
use crate::patricia_merkle_tree::filled_tree::tree::FilledTreeResult;
use crate::patricia_merkle_tree::original_skeleton_tree::OriginalSkeletonTreeResult;
use crate::patricia_merkle_tree::original_skeleton_tree::tree::OriginalSkeletonTreeResult;
use crate::patricia_merkle_tree::types::{EdgeData, EdgePath, EdgePathLength, PathToBottom};
use crate::storage::storage_trait::{create_db_key, StorageKey, StorageValue};
use crate::types::Felt;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,29 +1,3 @@
use std::collections::HashMap;

use crate::hash::hash_trait::HashOutput;
use crate::patricia_merkle_tree::errors::OriginalSkeletonTreeError;
use crate::patricia_merkle_tree::types::{LeafDataTrait, NodeIndex, TreeHeight};
use crate::patricia_merkle_tree::updated_skeleton_tree::UpdatedSkeletonTree;
use crate::storage::storage_trait::Storage;

#[allow(dead_code)]
pub(crate) type OriginalSkeletonTreeResult<T> = Result<T, OriginalSkeletonTreeError>;

/// Consider a Patricia-Merkle Tree which should be updated with new leaves.
/// This trait represents the structure of the subtree which will be modified in the
/// update. It also contains the hashes (for edge siblings - also the edge data) of the Sibling
/// nodes on the Merkle paths from the updated leaves to the root.
pub(crate) trait OriginalSkeletonTree<L: LeafDataTrait + std::clone::Clone> {
fn create_tree(
storage: &impl Storage,
leaf_indices: &[NodeIndex],
root_hash: HashOutput,
tree_height: TreeHeight,
) -> OriginalSkeletonTreeResult<impl OriginalSkeletonTree<L>>;

/// Computes and returns updated skeleton tree.
fn compute_updated_skeleton_tree(
&self,
index_to_updated_leaf: HashMap<NodeIndex, L>,
) -> OriginalSkeletonTreeResult<impl UpdatedSkeletonTree<L>>;
}
pub mod node;
pub mod original_skeleton_calc;
pub mod tree;
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,15 @@ use crate::patricia_merkle_tree::filled_tree::node::BinaryData;
use crate::patricia_merkle_tree::filled_tree::node::FilledNode;
use crate::patricia_merkle_tree::filled_tree::node::LeafData;
use crate::patricia_merkle_tree::filled_tree::node::NodeData;
use crate::patricia_merkle_tree::original_skeleton_tree::OriginalSkeletonTree;
use crate::patricia_merkle_tree::original_skeleton_tree::OriginalSkeletonTreeResult;
use crate::patricia_merkle_tree::original_skeleton_tree::tree::OriginalSkeletonTree;
use crate::patricia_merkle_tree::original_skeleton_tree::tree::OriginalSkeletonTreeResult;
use crate::patricia_merkle_tree::types::EdgeData;
use crate::patricia_merkle_tree::types::PathToBottom;
use crate::patricia_merkle_tree::types::TreeHeight;
use crate::patricia_merkle_tree::updated_skeleton_tree::UpdatedSkeletonTreeImpl;
use crate::patricia_merkle_tree::{original_skeleton_node::OriginalSkeletonNode, types::NodeIndex};
use crate::patricia_merkle_tree::updated_skeleton_tree::tree::UpdatedSkeletonTreeImpl;
use crate::patricia_merkle_tree::{
original_skeleton_tree::node::OriginalSkeletonNode, types::NodeIndex,
};
use crate::storage::errors::StorageError;
use crate::storage::storage_trait::Storage;
use crate::storage::storage_trait::StorageKey;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use crate::hash::hash_trait::HashOutput;
use crate::patricia_merkle_tree::original_skeleton_calc::LeafData;
use crate::patricia_merkle_tree::original_skeleton_node::OriginalSkeletonNode;
use crate::patricia_merkle_tree::original_skeleton_tree::OriginalSkeletonTree;
use crate::patricia_merkle_tree::original_skeleton_tree::node::OriginalSkeletonNode;
use crate::patricia_merkle_tree::original_skeleton_tree::original_skeleton_calc::LeafData;
use crate::patricia_merkle_tree::original_skeleton_tree::tree::OriginalSkeletonTree;
use crate::patricia_merkle_tree::types::{EdgePath, EdgePathLength, NodeIndex, PathToBottom};
use crate::storage::map_storage::MapStorage;
use crate::types::Felt;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
use std::collections::HashMap;

use crate::hash::hash_trait::HashOutput;
use crate::patricia_merkle_tree::errors::OriginalSkeletonTreeError;
use crate::patricia_merkle_tree::types::{LeafDataTrait, NodeIndex, TreeHeight};
use crate::patricia_merkle_tree::updated_skeleton_tree::tree::UpdatedSkeletonTree;
use crate::storage::storage_trait::Storage;

#[allow(dead_code)]
pub(crate) type OriginalSkeletonTreeResult<T> = Result<T, OriginalSkeletonTreeError>;

/// Consider a Patricia-Merkle Tree which should be updated with new leaves.
/// This trait represents the structure of the subtree which will be modified in the
/// update. It also contains the hashes (for edge siblings - also the edge data) of the Sibling
/// nodes on the Merkle paths from the updated leaves to the root.
pub(crate) trait OriginalSkeletonTree<L: LeafDataTrait + std::clone::Clone> {
fn create_tree(
storage: &impl Storage,
leaf_indices: &[NodeIndex],
root_hash: HashOutput,
tree_height: TreeHeight,
) -> OriginalSkeletonTreeResult<impl OriginalSkeletonTree<L>>;

/// Computes and returns updated skeleton tree.
fn compute_updated_skeleton_tree(
&self,
index_to_updated_leaf: HashMap<NodeIndex, L>,
) -> OriginalSkeletonTreeResult<impl UpdatedSkeletonTree<L>>;
}
174 changes: 2 additions & 172 deletions crates/committer/src/patricia_merkle_tree/updated_skeleton_tree.rs
Original file line number Diff line number Diff line change
@@ -1,172 +1,2 @@
use std::collections::HashMap;
use std::sync::{Arc, Mutex};

use crate::hash::hash_trait::{HashFunction, HashOutput};
use crate::patricia_merkle_tree::errors::UpdatedSkeletonTreeError;
use crate::patricia_merkle_tree::filled_tree::tree::FilledTree;
use crate::patricia_merkle_tree::types::{LeafDataTrait, NodeIndex, TreeHashFunction};
use crate::patricia_merkle_tree::updated_skeleton_node::UpdatedSkeletonNode;
use crate::types::Felt;

use crate::patricia_merkle_tree::filled_tree::node::{BinaryData, FilledNode, NodeData};
use crate::patricia_merkle_tree::filled_tree::tree::FilledTreeImpl;
use crate::patricia_merkle_tree::types::EdgeData;

#[cfg(test)]
#[path = "updated_skeleton_tree_test.rs"]
pub mod updated_skeleton_tree_test;

/// Consider a Patricia-Merkle Tree which has been updated with new leaves.
/// This trait represents the structure of the subtree which was modified in the update.
/// It also contains the hashes of the Sibling nodes on the Merkle paths from the updated leaves
/// to the root.
pub(crate) trait UpdatedSkeletonTree<L: LeafDataTrait + std::clone::Clone> {
/// Computes and returns the filled tree.
fn compute_filled_tree<H: HashFunction, TH: TreeHashFunction<L, H>>(
&self,
) -> Result<impl FilledTree<L>, UpdatedSkeletonTreeError<L>>;
}

pub(crate) struct UpdatedSkeletonTreeImpl<L: LeafDataTrait + std::clone::Clone> {
skeleton_tree: HashMap<NodeIndex, UpdatedSkeletonNode<L>>,
}

impl<L: LeafDataTrait + std::clone::Clone + std::marker::Sync + std::marker::Send>
UpdatedSkeletonTreeImpl<L>
{
fn get_node(
&self,
index: NodeIndex,
) -> Result<&UpdatedSkeletonNode<L>, UpdatedSkeletonTreeError<L>> {
match self.skeleton_tree.get(&index) {
Some(node) => Ok(node),
None => Err(UpdatedSkeletonTreeError::MissingNode(index)),
}
}

/// Writes the hash and data to the output map. The writing is done in a thread-safe manner with
/// interior mutability to avoid thread contention.
fn write_to_output_map(
output_map: Arc<HashMap<NodeIndex, Mutex<Option<FilledNode<L>>>>>,
index: NodeIndex,
hash: HashOutput,
data: NodeData<L>,
) -> Result<(), UpdatedSkeletonTreeError<L>> {
match output_map.get(&index) {
Some(node) => {
let mut node = node.lock().map_err(|_| {
UpdatedSkeletonTreeError::PoisonedLock("Cannot lock node.".to_owned())
})?;
match node.take() {
Some(existing_node) => Err(UpdatedSkeletonTreeError::DoubleUpdate {
index,
existing_value: Box::new(existing_node),
}),
None => {
*node = Some(FilledNode { hash, data });
Ok(())
}
}
}
None => Err(UpdatedSkeletonTreeError::MissingNode(index)),
}
}

fn initialize_with_placeholders(&self) -> HashMap<NodeIndex, Mutex<Option<FilledNode<L>>>> {
let mut filled_tree_map = HashMap::new();
for (index, node) in &self.skeleton_tree {
if !matches!(node, UpdatedSkeletonNode::Sibling(_)) {
filled_tree_map.insert(*index, Mutex::new(None));
}
}
filled_tree_map
}

fn remove_arc_mutex_and_option(
hash_map_in: Arc<HashMap<NodeIndex, Mutex<Option<FilledNode<L>>>>>,
) -> Result<HashMap<NodeIndex, FilledNode<L>>, UpdatedSkeletonTreeError<L>> {
let mut hash_map_out = HashMap::new();
for (key, value) in hash_map_in.iter() {
let mut value = value.lock().map_err(|_| {
UpdatedSkeletonTreeError::PoisonedLock("Cannot lock node.".to_owned())
})?;
match value.take() {
Some(value) => {
hash_map_out.insert(*key, value);
}
None => return Err(UpdatedSkeletonTreeError::MissingNode(*key)),
}
}
Ok(hash_map_out)
}

fn compute_filled_tree_rec<H: HashFunction, TH: TreeHashFunction<L, H>>(
&self,
index: NodeIndex,
output_map: Arc<HashMap<NodeIndex, Mutex<Option<FilledNode<L>>>>>,
) -> Result<HashOutput, UpdatedSkeletonTreeError<L>> {
let node = self.get_node(index)?;
match node {
UpdatedSkeletonNode::Binary => {
let left_index = NodeIndex(index.0 * Felt::TWO);
let right_index = NodeIndex(left_index.0 + Felt::ONE);

let (left_hash, right_hash) = rayon::join(
|| self.compute_filled_tree_rec::<H, TH>(left_index, Arc::clone(&output_map)),
|| self.compute_filled_tree_rec::<H, TH>(right_index, Arc::clone(&output_map)),
);

let data = NodeData::Binary(BinaryData {
left_hash: left_hash?,
right_hash: right_hash?,
});

let hash_value = TH::compute_node_hash(&data);
Self::write_to_output_map(output_map, index, hash_value, data)?;
Ok(hash_value)
}
UpdatedSkeletonNode::Edge { path_to_bottom } => {
let bottom_node_index = NodeIndex::compute_bottom_index(index, path_to_bottom);
let bottom_hash = self
.compute_filled_tree_rec::<H, TH>(bottom_node_index, Arc::clone(&output_map))?;
let data = NodeData::Edge(EdgeData {
path_to_bottom: *path_to_bottom,
bottom_hash,
});
let hash_value = TH::compute_node_hash(&data);
Self::write_to_output_map(output_map, index, hash_value, data)?;
Ok(hash_value)
}
UpdatedSkeletonNode::Sibling(hash_result) => Ok(*hash_result),
UpdatedSkeletonNode::Leaf(node_data) => {
let data = NodeData::Leaf(node_data.clone());
let hash_value = TH::compute_node_hash(&data);
Self::write_to_output_map(output_map, index, hash_value, data)?;
Ok(hash_value)
}
}
}
}

impl<L: LeafDataTrait + std::clone::Clone + std::marker::Sync + std::marker::Send>
UpdatedSkeletonTree<L> for UpdatedSkeletonTreeImpl<L>
{
fn compute_filled_tree<H: HashFunction, TH: TreeHashFunction<L, H>>(
&self,
) -> Result<FilledTreeImpl<L>, UpdatedSkeletonTreeError<L>> {
// Compute the filled tree in two steps:
// 1. Create a map containing the tree structure without hash values.
// 2. Fill in the hash values.
let filled_tree_map = Arc::new(self.initialize_with_placeholders());

self.compute_filled_tree_rec::<H, TH>(
NodeIndex::root_index(),
Arc::clone(&filled_tree_map),
)?;

// Create and return a new FilledTreeImpl from the hashmap.
Ok(FilledTreeImpl::new(Self::remove_arc_mutex_and_option(
filled_tree_map,
)?))
}
}
pub mod node;
pub mod tree;
Loading

0 comments on commit 1e9eb88

Please sign in to comment.