Skip to content

Commit

Permalink
chore: building original skeleton
Browse files Browse the repository at this point in the history
  • Loading branch information
nimrod-starkware committed Apr 15, 2024
1 parent ac3f787 commit a83e4e5
Show file tree
Hide file tree
Showing 14 changed files with 608 additions and 10 deletions.
7 changes: 7 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ derive_more = "0.99.17"
pretty_assertions = "1.2.1"
rstest = "0.17.0"
starknet-types-core = { version = "0.0.11", features = ["hash"] }
bisection = "0.1.0"

[workspace.lints.rust]
warnings = "deny"
Expand Down
2 changes: 2 additions & 0 deletions crates/committer/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -16,3 +16,5 @@ rstest.workspace = true
[dependencies]
derive_more.workspace = true
starknet-types-core.workspace = true
bisection.workspace = true

2 changes: 1 addition & 1 deletion crates/committer/src/hash/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ use crate::types::Felt;
pub(crate) struct HashInputPair(pub Felt, pub Felt);

#[allow(dead_code)]
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
#[derive(Debug, PartialEq, Eq, Clone, Copy, Hash)]
pub(crate) struct HashOutput(pub Felt);

#[allow(dead_code)]
Expand Down
1 change: 1 addition & 0 deletions crates/committer/src/patricia_merkle_tree.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
pub mod errors;
pub mod filled_node;
pub mod filled_tree;
pub mod original_skeleton_calc;
pub mod original_skeleton_node;
pub mod original_skeleton_tree;
pub mod types;
Expand Down
6 changes: 5 additions & 1 deletion crates/committer/src/patricia_merkle_tree/errors.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
// TODO(Amos, 01/04/2024): Add error types.
#[derive(Debug)]
pub(crate) enum OriginalSkeletonTreeError {}
#[allow(dead_code)]
pub(crate) enum OriginalSkeletonTreeError {
Deserializtion(String),
StorageRead,
}

#[derive(Debug)]
pub(crate) enum UpdatedSkeletonTreeError {
Expand Down
3 changes: 3 additions & 0 deletions crates/committer/src/patricia_merkle_tree/filled_node.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,10 @@ use crate::patricia_merkle_tree::types::{EdgeData, LeafDataTrait};
use crate::{hash::types::HashOutput, types::Felt};
// TODO(Nimrod, 1/6/2024): Swap to starknet-types-core types once implemented.
#[allow(dead_code)]
#[derive(Debug, PartialEq, Eq)]
pub(crate) struct ClassHash(pub Felt);
#[allow(dead_code)]
#[derive(Debug, PartialEq, Eq)]
pub(crate) struct Nonce(pub Felt);

#[allow(dead_code)]
Expand All @@ -28,6 +30,7 @@ pub(crate) struct BinaryData {
}

#[allow(dead_code)]
#[derive(Debug, PartialEq, Eq)]
pub(crate) enum LeafData {
StorageValue(Felt),
CompiledClassHash(ClassHash),
Expand Down
177 changes: 177 additions & 0 deletions crates/committer/src/patricia_merkle_tree/original_skeleton_calc.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,177 @@
use bisection::{bisect_left, bisect_right};

use crate::hash::types::HashOutput;
use crate::patricia_merkle_tree::original_skeleton_tree::OriginalSkeletonTreeResult;
use crate::patricia_merkle_tree::types::EdgeData;
use crate::patricia_merkle_tree::types::TreeHeight;
use crate::patricia_merkle_tree::{
filled_node::LeafData, original_skeleton_node::OriginalSkeletonNode, types::NodeIndex,
};
use crate::storage::storage_trait::{StorageKey, StorageValue};
use crate::types::Felt;
use std::collections::HashMap;

use super::errors::OriginalSkeletonTreeError;

#[allow(dead_code)]
pub(crate) struct SkeletonTree<'a> {
nodes: HashMap<NodeIndex, OriginalSkeletonNode<LeafData>>,
leaf_modifications: &'a HashMap<NodeIndex, LeafData>,
tree_height: TreeHeight,
}
#[allow(dead_code)]
impl SkeletonTree<'_> {
fn fetch_nodes(
&mut self,
subtrees: Vec<SubTree<'_>>,
storage: HashMap<StorageKey, StorageValue>,
// TODO(Nimrod, 25/4/2024): Change input type to Storage once Amos has implemented the
// Storage trait for HashMap.
) -> OriginalSkeletonTreeResult<()> {
if subtrees.is_empty() {
return Ok(());
}
let mut next_subtrees = Vec::new();
let root_vals: Vec<&StorageValue> = (subtrees
.iter()
.map(|subtree| {
storage
.get(&subtree.root_hash.with_patricia_prefix())
.ok_or(OriginalSkeletonTreeError::StorageRead)
})
.collect::<OriginalSkeletonTreeResult<Vec<_>>>())?;
for (root_val, subtree) in root_vals.iter().zip(subtrees.iter()) {
if root_val.is_binary_node() {
// Binary node.
if subtree.is_sibling() {
self.nodes.insert(
subtree.root_index,
OriginalSkeletonNode::LeafOrBinarySibling(HashOutput(
Felt::from_bytes_be_slice(&subtree.root_hash.0),
)),
);
continue;
}
self.nodes
.insert(subtree.root_index, OriginalSkeletonNode::Binary);
let (left_key, right_key) = root_val.deserialize_binary_node()?;
let (left_leaves, right_leaves) = subtree.split_leaves(&self.tree_height);
let left_root_index = subtree.root_index.shift_left(1);
let left_subtree = SubTree {
sorted_leaf_indices: left_leaves,
root_index: left_root_index,
root_hash: left_key,
};
let right_subtree = SubTree {
sorted_leaf_indices: right_leaves,
root_index: left_root_index + NodeIndex(Felt::ONE),
root_hash: right_key,
};
if subtree.get_height(&self.tree_height).is_of_height_one() {
// Children are leaves.
if left_subtree.is_sibling() {
self.nodes.insert(
left_subtree.root_index,
OriginalSkeletonNode::LeafOrBinarySibling(HashOutput(
Felt::from_bytes_be_slice(&left_subtree.root_hash.0),
)),
);
}
if right_subtree.is_sibling() {
self.nodes.insert(
right_subtree.root_index,
OriginalSkeletonNode::LeafOrBinarySibling(HashOutput(
Felt::from_bytes_be_slice(&right_subtree.root_hash.0),
)),
);
}
continue;
}
next_subtrees.extend(vec![left_subtree, right_subtree]);
} else {
let (bottom_hash, path_to_bottom) = root_val.deserialize_edge_node()?;
if subtree.is_sibling() {
// Sibling will remain an edge node. No need to open the bottom.
self.nodes.insert(
subtree.root_index,
OriginalSkeletonNode::EdgeSibling(EdgeData {
bottom_hash: HashOutput(Felt::from_bytes_be_slice(&bottom_hash.0)),
path_to_bottom,
}),
);
continue;
}
// Parse bottom.
let bottom_index = path_to_bottom.bottom_index(subtree.root_index);
let bottom_height =
subtree.get_height(&self.tree_height) - TreeHeight(path_to_bottom.length.0);
let leftmost_in_subtree = bottom_index.shift_left(bottom_height.0);
let rightmost_in_subtree = leftmost_in_subtree
+ (NodeIndex(Felt::ONE).shift_left(bottom_height.0))
- NodeIndex(Felt::ONE);
let bottom_leaves = &subtree.sorted_leaf_indices[bisect_left(
subtree.sorted_leaf_indices,
&leftmost_in_subtree,
)
..bisect_right(subtree.sorted_leaf_indices, &rightmost_in_subtree)];
self.nodes.insert(
subtree.root_index,
OriginalSkeletonNode::Edge { path_to_bottom },
);
if bottom_height.is_leaf_height() {
if bottom_leaves.is_empty() {
// Bottom is a leaf sibling.
self.nodes.insert(
bottom_index,
OriginalSkeletonNode::LeafOrBinarySibling(HashOutput(
Felt::from_bytes_be_slice(&bottom_hash.0),
)),
);
}
continue;
}
let bottom_subtree = SubTree {
sorted_leaf_indices: bottom_leaves,
root_index: bottom_index,
root_hash: bottom_hash,
};
next_subtrees.push(bottom_subtree);
}
}
self.fetch_nodes(next_subtrees, storage)
}
}
#[allow(dead_code)]
struct SubTree<'a> {
pub sorted_leaf_indices: &'a [NodeIndex],
pub root_index: NodeIndex,
pub root_hash: StorageKey,
}
#[allow(dead_code)]
impl<'a> SubTree<'a> {
pub(crate) fn get_height(&self, total_tree_height: &TreeHeight) -> TreeHeight {
TreeHeight(total_tree_height.0 - self.root_index.0.bits() + 1)
}

pub(crate) fn split_leaves(
&self,
total_tree_height: &TreeHeight,
) -> (&'a [NodeIndex], &'a [NodeIndex]) {
let height = self.get_height(total_tree_height);
let leftmost_index_in_right_subtree =
((self.root_index.shift_left(1)) + NodeIndex(Felt::ONE)).shift_left(height.0 - 1);
let mid = bisect_left(self.sorted_leaf_indices, &leftmost_index_in_right_subtree);
(
&self.sorted_leaf_indices[..mid],
&self.sorted_leaf_indices[mid..],
)
}

pub(crate) fn is_sibling(&self) -> bool {
self.sorted_leaf_indices.is_empty()
}
}

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

0 comments on commit a83e4e5

Please sign in to comment.