diff --git a/.github/workflows/committer_ci.yml b/.github/workflows/committer_ci.yml index d4aadf2ce4..ef816bc5d8 100644 --- a/.github/workflows/committer_ci.yml +++ b/.github/workflows/committer_ci.yml @@ -13,6 +13,7 @@ on: - 'Cargo.lock' - 'crates/committer/**' - 'crates/committer_cli/**' + - 'crates/starknet_committer/**' pull_request: types: @@ -27,6 +28,7 @@ on: - 'Cargo.lock' - 'crates/committer/**' - 'crates/committer_cli/**' + - 'crates/starknet_committer/**' jobs: run-regression-tests: diff --git a/Cargo.lock b/Cargo.lock index 08fe483b3b..93b1fdeba3 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2006,6 +2006,7 @@ dependencies = [ "serde_repr", "starknet-types-core", "starknet_api", + "starknet_committer", "strum 0.25.0", "strum_macros 0.25.3", "tempfile", @@ -8931,6 +8932,21 @@ dependencies = [ "url", ] +[[package]] +name = "starknet_committer" +version = "0.1.0-rc.0" +dependencies = [ + "committer", + "hex", + "pretty_assertions", + "rstest", + "serde_json", + "starknet-types-core", + "thiserror", + "tokio", + "tracing", +] + [[package]] name = "starknet_gateway" version = "0.0.0" diff --git a/Cargo.toml b/Cargo.toml index 4814680dcd..8cf8577ed7 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -33,6 +33,7 @@ members = [ "crates/sequencing/papyrus_consensus", "crates/starknet_api", "crates/starknet_client", + "crates/starknet_committer", "crates/starknet_sierra_compile", "crates/task_executor", "crates/tests-integration", diff --git a/crates/committer/Cargo.toml b/crates/committer/Cargo.toml index c96ddccecd..bf7a63a4f3 100644 --- a/crates/committer/Cargo.toml +++ b/crates/committer/Cargo.toml @@ -4,7 +4,7 @@ version = "0.1.0-rc.0" edition.workspace = true repository.workspace = true license-file.workspace = true -description = "Computes and manages Starknet state." +description = "Library for computing and updating Patricia trees." [lints] workspace = true diff --git a/crates/committer/src/felt.rs b/crates/committer/src/felt.rs index e31e1a31e0..3f0fcf7d0d 100644 --- a/crates/committer/src/felt.rs +++ b/crates/committer/src/felt.rs @@ -24,7 +24,7 @@ pub struct Felt(pub StarknetTypesFelt); macro_rules! impl_from_hex_for_felt_wrapper { ($wrapper:ty) => { impl $wrapper { - pub(crate) fn from_hex(hex_string: &str) -> Result { + pub fn from_hex(hex_string: &str) -> Result { Ok(Self(Felt::from_hex(hex_string)?)) } } @@ -76,11 +76,11 @@ impl fmt::Debug for Felt { impl Felt { pub const ZERO: Felt = Felt(StarknetTypesFelt::ZERO); #[allow(dead_code)] - pub(crate) const ONE: Felt = Felt(StarknetTypesFelt::ONE); + pub const ONE: Felt = Felt(StarknetTypesFelt::ONE); #[allow(dead_code)] - pub(crate) const TWO: Felt = Felt(StarknetTypesFelt::TWO); + pub const TWO: Felt = Felt(StarknetTypesFelt::TWO); #[allow(dead_code)] - pub(crate) const THREE: Felt = Felt(StarknetTypesFelt::THREE); + pub const THREE: Felt = Felt(StarknetTypesFelt::THREE); pub const MAX: Felt = Felt(StarknetTypesFelt::MAX); pub fn from_bytes_be_slice(bytes: &[u8]) -> Self { diff --git a/crates/committer/src/lib.rs b/crates/committer/src/lib.rs index d87fb19818..a22e4808ab 100644 --- a/crates/committer/src/lib.rs +++ b/crates/committer/src/lib.rs @@ -1,6 +1,4 @@ -pub mod block_committer; pub mod felt; -pub mod forest_errors; pub mod hash; pub mod patricia_merkle_tree; pub mod storage; diff --git a/crates/committer/src/patricia_merkle_tree/external_test_utils.rs b/crates/committer/src/patricia_merkle_tree/external_test_utils.rs index cf1f236f22..f503bcccbf 100644 --- a/crates/committer/src/patricia_merkle_tree/external_test_utils.rs +++ b/crates/committer/src/patricia_merkle_tree/external_test_utils.rs @@ -6,16 +6,19 @@ use rand::Rng; use serde_json::json; use super::filled_tree::tree::{FilledTree, FilledTreeImpl}; +use super::node_data::inner_node::{EdgePathLength, PathToBottom}; use super::node_data::leaf::{Leaf, LeafModifications, SkeletonLeaf}; use super::original_skeleton_tree::config::OriginalSkeletonTreeConfig; +use super::original_skeleton_tree::node::OriginalSkeletonNode; use super::original_skeleton_tree::tree::{OriginalSkeletonTree, OriginalSkeletonTreeImpl}; -use super::types::{NodeIndex, SortedLeafIndices}; +use super::types::{NodeIndex, SortedLeafIndices, SubTreeHeight}; use super::updated_skeleton_tree::hash_function::TreeHashFunction; use super::updated_skeleton_tree::tree::{UpdatedSkeletonTree, UpdatedSkeletonTreeImpl}; use crate::felt::Felt; use crate::hash::hash_trait::HashOutput; use crate::patricia_merkle_tree::errors::TypesError; use crate::storage::map_storage::MapStorage; +use crate::storage::storage_trait::{create_db_key, StarknetPrefix, StorageKey, StorageValue}; impl TryFrom<&U256> for Felt { type Error = TypesError; @@ -127,3 +130,112 @@ pub async fn single_tree_flow_test + result_map.insert("storage_changes", json_storage); serde_json::to_string(&result_map).expect("serialization failed") } + +pub fn create_32_bytes_entry(simple_val: u128) -> [u8; 32] { + U256::from(simple_val).to_be_bytes() +} + +fn create_patricia_key(val: u128) -> StorageKey { + create_db_key(StarknetPrefix::InnerNode.to_storage_prefix(), &U256::from(val).to_be_bytes()) +} + +fn create_binary_val(left: u128, right: u128) -> StorageValue { + StorageValue( + (create_32_bytes_entry(left).into_iter().chain(create_32_bytes_entry(right))).collect(), + ) +} + +fn create_edge_val(hash: u128, path: u128, length: u8) -> StorageValue { + StorageValue( + create_32_bytes_entry(hash) + .into_iter() + .chain(create_32_bytes_entry(path)) + .chain([length]) + .collect(), + ) +} + +pub fn create_binary_entry(left: u128, right: u128) -> (StorageKey, StorageValue) { + (create_patricia_key(left + right), create_binary_val(left, right)) +} + +pub fn create_edge_entry(hash: u128, path: u128, length: u8) -> (StorageKey, StorageValue) { + (create_patricia_key(hash + path + u128::from(length)), create_edge_val(hash, path, length)) +} + +pub fn create_binary_skeleton_node(idx: u128) -> (NodeIndex, OriginalSkeletonNode) { + (NodeIndex::from(idx), OriginalSkeletonNode::Binary) +} + +pub fn create_edge_skeleton_node( + idx: u128, + path: u128, + length: u8, +) -> (NodeIndex, OriginalSkeletonNode) { + ( + NodeIndex::from(idx), + OriginalSkeletonNode::Edge( + PathToBottom::new(path.into(), EdgePathLength::new(length).unwrap()).unwrap(), + ), + ) +} + +pub fn create_unmodified_subtree_skeleton_node( + idx: u128, + hash_output: u128, +) -> (NodeIndex, OriginalSkeletonNode) { + ( + NodeIndex::from(idx), + OriginalSkeletonNode::UnmodifiedSubTree(HashOutput(Felt::from(hash_output))), + ) +} + +pub fn create_root_edge_entry( + old_root: u128, + subtree_height: SubTreeHeight, +) -> (StorageKey, StorageValue) { + // Assumes path is 0. + let length = SubTreeHeight::ACTUAL_HEIGHT.0 - subtree_height.0; + let new_root = old_root + u128::from(length); + let key = create_db_key( + StarknetPrefix::InnerNode.to_storage_prefix(), + &Felt::from(new_root).to_bytes_be(), + ); + let value = StorageValue( + Felt::from(old_root) + .to_bytes_be() + .into_iter() + .chain(Felt::from(0_u128).to_bytes_be()) + .chain([length]) + .collect(), + ); + (key, value) +} + +pub fn create_expected_skeleton_nodes( + nodes: Vec<(NodeIndex, OriginalSkeletonNode)>, + height: u8, +) -> HashMap { + let subtree_height = SubTreeHeight::new(height); + nodes + .into_iter() + .map(|(node_index, node)| (NodeIndex::from_subtree_index(node_index, subtree_height), node)) + .chain([( + NodeIndex::ROOT, + OriginalSkeletonNode::Edge( + PathToBottom::new(0.into(), EdgePathLength::new(251 - height).unwrap()).unwrap(), + ), + )]) + .collect() +} + +impl NodeIndex { + /// Assumes self represents an index in a smaller tree height. Returns a node index represents + /// the same index in the starknet state tree as if the smaller tree was 'planted' at the lowest + /// leftmost node from the root. + pub fn from_subtree_index(subtree_index: Self, subtree_height: SubTreeHeight) -> Self { + let height_diff = SubTreeHeight::ACTUAL_HEIGHT.0 - subtree_height.0; + let offset = (NodeIndex::ROOT << height_diff) - 1.into(); + subtree_index + (offset << (subtree_index.bit_length() - 1)) + } +} diff --git a/crates/committer/src/patricia_merkle_tree/filled_tree.rs b/crates/committer/src/patricia_merkle_tree/filled_tree.rs index 4357d7f2fb..70248208b7 100644 --- a/crates/committer/src/patricia_merkle_tree/filled_tree.rs +++ b/crates/committer/src/patricia_merkle_tree/filled_tree.rs @@ -1,5 +1,4 @@ pub mod errors; -pub mod forest; pub mod node; pub mod node_serde; pub mod tree; diff --git a/crates/committer/src/patricia_merkle_tree/filled_tree/errors.rs b/crates/committer/src/patricia_merkle_tree/filled_tree/errors.rs index 7bc74950c6..cad437874f 100644 --- a/crates/committer/src/patricia_merkle_tree/filled_tree/errors.rs +++ b/crates/committer/src/patricia_merkle_tree/filled_tree/errors.rs @@ -1,9 +1,8 @@ use tokio::task::JoinError; -use crate::block_committer::input::StarknetStorageValue; -use crate::patricia_merkle_tree::filled_tree::node::{CompiledClassHash, FilledNode}; +use crate::patricia_merkle_tree::filled_tree::node::FilledNode; use crate::patricia_merkle_tree::node_data::errors::LeafError; -use crate::patricia_merkle_tree::node_data::leaf::{ContractState, Leaf}; +use crate::patricia_merkle_tree::node_data::leaf::Leaf; use crate::patricia_merkle_tree::types::NodeIndex; use crate::patricia_merkle_tree::updated_skeleton_tree::errors::UpdatedSkeletonTreeError; @@ -28,7 +27,3 @@ pub enum FilledTreeError { #[error(transparent)] JoinError(#[from] JoinError), } - -pub type StorageTrieError = FilledTreeError; -pub type ClassesTrieError = FilledTreeError; -pub type ContractsTrieError = FilledTreeError; diff --git a/crates/committer/src/patricia_merkle_tree/filled_tree/node.rs b/crates/committer/src/patricia_merkle_tree/filled_tree/node.rs index 62aaa93877..86e3788039 100644 --- a/crates/committer/src/patricia_merkle_tree/filled_tree/node.rs +++ b/crates/committer/src/patricia_merkle_tree/filled_tree/node.rs @@ -1,33 +1,6 @@ -use starknet_types_core::felt::FromStrError; - -use crate::felt::Felt; use crate::hash::hash_trait::HashOutput; -use crate::impl_from_hex_for_felt_wrapper; use crate::patricia_merkle_tree::node_data::inner_node::NodeData; use crate::patricia_merkle_tree::node_data::leaf::Leaf; -use crate::patricia_merkle_tree::types::NodeIndex; - -// TODO(Nimrod, 1/6/2024): Use the ClassHash defined in starknet-types-core when available. - -#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Hash)] -pub struct ClassHash(pub Felt); - -impl From<&ClassHash> for NodeIndex { - fn from(class_hash: &ClassHash) -> NodeIndex { - NodeIndex::from_leaf_felt(&class_hash.0) - } -} - -impl_from_hex_for_felt_wrapper!(ClassHash); -#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Hash)] -pub struct Nonce(pub Felt); - -impl_from_hex_for_felt_wrapper!(Nonce); - -#[derive(Clone, Copy, Debug, Default, Eq, PartialEq)] -pub struct CompiledClassHash(pub Felt); - -impl_from_hex_for_felt_wrapper!(CompiledClassHash); #[derive(Clone, Debug, PartialEq, Eq)] /// A node in a Patricia-Merkle tree which was modified during an update. diff --git a/crates/committer/src/patricia_merkle_tree/filled_tree/tree.rs b/crates/committer/src/patricia_merkle_tree/filled_tree/tree.rs index 21d2551e56..ea3658004d 100644 --- a/crates/committer/src/patricia_merkle_tree/filled_tree/tree.rs +++ b/crates/committer/src/patricia_merkle_tree/filled_tree/tree.rs @@ -4,12 +4,11 @@ use std::sync::{Arc, Mutex}; use async_recursion::async_recursion; -use crate::block_committer::input::{ContractAddress, StarknetStorageValue}; use crate::hash::hash_trait::HashOutput; use crate::patricia_merkle_tree::filled_tree::errors::FilledTreeError; -use crate::patricia_merkle_tree::filled_tree::node::{CompiledClassHash, FilledNode}; +use crate::patricia_merkle_tree::filled_tree::node::FilledNode; use crate::patricia_merkle_tree::node_data::inner_node::{BinaryData, EdgeData, NodeData}; -use crate::patricia_merkle_tree::node_data::leaf::{ContractState, Leaf, LeafModifications}; +use crate::patricia_merkle_tree::node_data::leaf::{Leaf, LeafModifications}; use crate::patricia_merkle_tree::types::NodeIndex; use crate::patricia_merkle_tree::updated_skeleton_tree::hash_function::TreeHashFunction; use crate::patricia_merkle_tree::updated_skeleton_tree::node::UpdatedSkeletonNode; @@ -25,7 +24,7 @@ pub(crate) type FilledTreeResult = Result>; /// Consider a Patricia-Merkle Tree which has been updated with new leaves. /// FilledTree consists of all nodes which were modified in the update, including their updated /// data and hashes. -pub(crate) trait FilledTree: Sized { +pub trait FilledTree: Sized { /// Computes and returns the filled tree. fn create<'a, TH: TreeHashFunction + 'static>( updated_skeleton: Arc + 'static>, @@ -46,11 +45,6 @@ pub struct FilledTreeImpl { pub root_hash: HashOutput, } -pub type StorageTrie = FilledTreeImpl; -pub type ClassesTrie = FilledTreeImpl; -pub type ContractsTrie = FilledTreeImpl; -pub type StorageTrieMap = HashMap; - impl FilledTreeImpl { fn initialize_with_placeholders<'a>( updated_skeleton: &Arc>, diff --git a/crates/committer/src/patricia_merkle_tree/internal_test_utils.rs b/crates/committer/src/patricia_merkle_tree/internal_test_utils.rs index 1d42d8a989..b0dc33f3cb 100644 --- a/crates/committer/src/patricia_merkle_tree/internal_test_utils.rs +++ b/crates/committer/src/patricia_merkle_tree/internal_test_utils.rs @@ -114,17 +114,6 @@ pub(crate) fn random() -> ThreadRng { rand::thread_rng() } -impl NodeIndex { - /// Assumes self represents an index in a smaller tree height. Returns a node index represents - /// the same index in the starknet state tree as if the smaller tree was 'planted' at the lowest - /// leftmost node from the root. - pub(crate) fn from_subtree_index(subtree_index: Self, subtree_height: SubTreeHeight) -> Self { - let height_diff = SubTreeHeight::ACTUAL_HEIGHT.0 - subtree_height.0; - let offset = (NodeIndex::ROOT << height_diff) - 1.into(); - subtree_index + (offset << (subtree_index.bit_length() - 1)) - } -} - pub(crate) fn small_tree_index_to_full(index: U256, height: SubTreeHeight) -> NodeIndex { NodeIndex::from_subtree_index(NodeIndex::new(index), height) } diff --git a/crates/committer/src/patricia_merkle_tree/node_data.rs b/crates/committer/src/patricia_merkle_tree/node_data.rs index 4e528cf888..aa66540091 100644 --- a/crates/committer/src/patricia_merkle_tree/node_data.rs +++ b/crates/committer/src/patricia_merkle_tree/node_data.rs @@ -1,4 +1,3 @@ pub mod errors; pub mod inner_node; pub mod leaf; -pub mod leaf_serde; diff --git a/crates/committer/src/patricia_merkle_tree/node_data/leaf.rs b/crates/committer/src/patricia_merkle_tree/node_data/leaf.rs index 2855b41020..f52dcdbc0c 100644 --- a/crates/committer/src/patricia_merkle_tree/node_data/leaf.rs +++ b/crates/committer/src/patricia_merkle_tree/node_data/leaf.rs @@ -3,10 +3,7 @@ use std::fmt::Debug; use std::future::Future; use std::sync::Arc; -use crate::block_committer::input::StarknetStorageValue; use crate::felt::Felt; -use crate::hash::hash_trait::HashOutput; -use crate::patricia_merkle_tree::filled_tree::node::{ClassHash, CompiledClassHash, Nonce}; use crate::patricia_merkle_tree::node_data::errors::{LeafError, LeafResult}; use crate::patricia_merkle_tree::types::NodeIndex; use crate::storage::db_object::{DBObject, Deserializable}; @@ -40,54 +37,6 @@ pub trait Leaf: Clone + Sync + Send + DBObject + Deserializable + Default + Debu } } -#[derive(Clone, Debug, Default, Eq, PartialEq)] -pub struct ContractState { - pub nonce: Nonce, - pub storage_root_hash: HashOutput, - pub class_hash: ClassHash, -} - -impl Leaf for StarknetStorageValue { - fn is_empty(&self) -> bool { - self.0 == Felt::ZERO - } - - async fn create( - index: &NodeIndex, - leaf_modifications: Arc>, - ) -> LeafResult { - Self::from_modifications(index, leaf_modifications) - } -} - -impl Leaf for CompiledClassHash { - fn is_empty(&self) -> bool { - self.0 == Felt::ZERO - } - - async fn create( - index: &NodeIndex, - leaf_modifications: Arc>, - ) -> LeafResult { - Self::from_modifications(index, leaf_modifications) - } -} - -impl Leaf for ContractState { - fn is_empty(&self) -> bool { - self.nonce.0 == Felt::ZERO - && self.class_hash.0 == Felt::ZERO - && self.storage_root_hash.0 == Felt::ZERO - } - - async fn create( - index: &NodeIndex, - leaf_modifications: Arc>, - ) -> LeafResult { - Self::from_modifications(index, leaf_modifications) - } -} - #[derive(Copy, Clone, Debug, Eq, PartialEq)] pub enum SkeletonLeaf { Zero, diff --git a/crates/committer/src/patricia_merkle_tree/original_skeleton_tree.rs b/crates/committer/src/patricia_merkle_tree/original_skeleton_tree.rs index 7ca88b9db0..d9f47d5d40 100644 --- a/crates/committer/src/patricia_merkle_tree/original_skeleton_tree.rs +++ b/crates/committer/src/patricia_merkle_tree/original_skeleton_tree.rs @@ -2,6 +2,5 @@ pub mod config; pub mod create_tree; pub mod errors; pub mod node; -pub mod skeleton_forest; pub mod tree; pub mod utils; diff --git a/crates/committer/src/patricia_merkle_tree/original_skeleton_tree/config.rs b/crates/committer/src/patricia_merkle_tree/original_skeleton_tree/config.rs index f472f69edf..c93d34baed 100644 --- a/crates/committer/src/patricia_merkle_tree/original_skeleton_tree/config.rs +++ b/crates/committer/src/patricia_merkle_tree/original_skeleton_tree/config.rs @@ -1,7 +1,4 @@ -use crate::block_committer::input::StarknetStorageValue; -use crate::patricia_merkle_tree::filled_tree::node::CompiledClassHash; -use crate::patricia_merkle_tree::node_data::leaf::{ContractState, Leaf, LeafModifications}; -use crate::patricia_merkle_tree::original_skeleton_tree::errors::OriginalSkeletonTreeError; +use crate::patricia_merkle_tree::node_data::leaf::Leaf; use crate::patricia_merkle_tree::original_skeleton_tree::tree::OriginalSkeletonTreeResult; use crate::patricia_merkle_tree::types::NodeIndex; @@ -11,7 +8,7 @@ pub trait OriginalSkeletonTreeConfig { /// warning when encountering a trivial modification. fn compare_modified_leaves(&self) -> bool; - /// Compares the previous leaf to the modified and returns true iff they are equal. + /// Compares the previous leaf to the modified and returns true if they are equal. fn compare_leaf( &self, index: &NodeIndex, @@ -19,18 +16,22 @@ pub trait OriginalSkeletonTreeConfig { ) -> OriginalSkeletonTreeResult; } +// TODO(Aviv 05/08/2024): Move this macro to starknet_committer crate #[macro_export] macro_rules! generate_trie_config { ($struct_name:ident, $leaf_type:ty) => { pub struct $struct_name<'a> { - modifications: &'a LeafModifications<$leaf_type>, + modifications: + &'a $crate::patricia_merkle_tree::node_data::leaf::LeafModifications<$leaf_type>, compare_modified_leaves: bool, } impl<'a> $struct_name<'a> { #[allow(dead_code)] pub fn new( - modifications: &'a LeafModifications<$leaf_type>, + modifications: &'a $crate::patricia_merkle_tree::node_data::leaf::LeafModifications< + $leaf_type, + >, compare_modified_leaves: bool, ) -> Self { Self { modifications, compare_modified_leaves } @@ -56,29 +57,3 @@ macro_rules! generate_trie_config { } }; } - -generate_trie_config!(OriginalSkeletonStorageTrieConfig, StarknetStorageValue); - -generate_trie_config!(OriginalSkeletonClassesTrieConfig, CompiledClassHash); - -pub(crate) struct OriginalSkeletonContractsTrieConfig; - -impl OriginalSkeletonTreeConfig for OriginalSkeletonContractsTrieConfig { - fn compare_modified_leaves(&self) -> bool { - false - } - - fn compare_leaf( - &self, - _index: &NodeIndex, - _previous_leaf: &ContractState, - ) -> OriginalSkeletonTreeResult { - Ok(false) - } -} - -impl OriginalSkeletonContractsTrieConfig { - pub(crate) fn new() -> Self { - Self - } -} diff --git a/crates/committer/src/patricia_merkle_tree/original_skeleton_tree/create_tree_test.rs b/crates/committer/src/patricia_merkle_tree/original_skeleton_tree/create_tree_test.rs index 223ed32303..c02e7aaba0 100644 --- a/crates/committer/src/patricia_merkle_tree/original_skeleton_tree/create_tree_test.rs +++ b/crates/committer/src/patricia_merkle_tree/original_skeleton_tree/create_tree_test.rs @@ -7,6 +7,15 @@ use rstest::rstest; use super::OriginalSkeletonTreeImpl; use crate::felt::Felt; use crate::hash::hash_trait::HashOutput; +use crate::patricia_merkle_tree::external_test_utils::{ + create_binary_entry, + create_binary_skeleton_node, + create_edge_entry, + create_edge_skeleton_node, + create_expected_skeleton_nodes, + create_root_edge_entry, + create_unmodified_subtree_skeleton_node, +}; use crate::patricia_merkle_tree::internal_test_utils::{ small_tree_index_to_full, MockLeaf, @@ -20,7 +29,7 @@ use crate::patricia_merkle_tree::original_skeleton_tree::tree::OriginalSkeletonT use crate::patricia_merkle_tree::types::{NodeIndex, SortedLeafIndices, SubTreeHeight}; use crate::storage::db_object::DBObject; use crate::storage::map_storage::MapStorage; -use crate::storage::storage_trait::{create_db_key, StarknetPrefix, StorageKey, StorageValue}; +use crate::storage::storage_trait::{StorageKey, StorageValue}; #[rstest] // This test assumes for simplicity that hash is addition (i.e hash(a,b) = a + b). @@ -401,35 +410,11 @@ fn test_get_bottom_subtree( assert_eq!(subtree, expected_subtree); } -pub(crate) fn create_32_bytes_entry(simple_val: u128) -> [u8; 32] { - U256::from(simple_val).to_be_bytes() -} - pub(crate) fn create_mock_leaf_entry(val: u128) -> (StorageKey, StorageValue) { let leaf = MockLeaf(Felt::from(val)); (leaf.get_db_key(&leaf.0.to_bytes_be()), leaf.serialize()) } -fn create_patricia_key(val: u128) -> StorageKey { - create_db_key(StarknetPrefix::InnerNode.to_storage_prefix(), &U256::from(val).to_be_bytes()) -} - -fn create_binary_val(left: u128, right: u128) -> StorageValue { - StorageValue( - (create_32_bytes_entry(left).into_iter().chain(create_32_bytes_entry(right))).collect(), - ) -} - -fn create_edge_val(hash: u128, path: u128, length: u8) -> StorageValue { - StorageValue( - create_32_bytes_entry(hash) - .into_iter() - .chain(create_32_bytes_entry(path)) - .chain([length]) - .collect(), - ) -} - fn create_mock_leaf_modifications( leaf_modifications: Vec<(u128, u128)>, ) -> LeafModifications { @@ -439,80 +424,6 @@ fn create_mock_leaf_modifications( .collect() } -pub(crate) fn create_binary_entry(left: u128, right: u128) -> (StorageKey, StorageValue) { - (create_patricia_key(left + right), create_binary_val(left, right)) -} - -pub(crate) fn create_edge_entry(hash: u128, path: u128, length: u8) -> (StorageKey, StorageValue) { - (create_patricia_key(hash + path + u128::from(length)), create_edge_val(hash, path, length)) -} - -pub(crate) fn create_expected_skeleton_nodes( - nodes: Vec<(NodeIndex, OriginalSkeletonNode)>, - height: u8, -) -> HashMap { - let subtree_height = SubTreeHeight::new(height); - nodes - .into_iter() - .map(|(node_index, node)| (NodeIndex::from_subtree_index(node_index, subtree_height), node)) - .chain([( - NodeIndex::ROOT, - OriginalSkeletonNode::Edge( - PathToBottom::new(0.into(), EdgePathLength::new(251 - height).unwrap()).unwrap(), - ), - )]) - .collect() -} - -pub(crate) fn create_binary_skeleton_node(idx: u128) -> (NodeIndex, OriginalSkeletonNode) { - (NodeIndex::from(idx), OriginalSkeletonNode::Binary) -} - -pub(crate) fn create_edge_skeleton_node( - idx: u128, - path: u128, - length: u8, -) -> (NodeIndex, OriginalSkeletonNode) { - ( - NodeIndex::from(idx), - OriginalSkeletonNode::Edge( - PathToBottom::new(path.into(), EdgePathLength::new(length).unwrap()).unwrap(), - ), - ) -} - -pub(crate) fn create_unmodified_subtree_skeleton_node( - idx: u128, - hash_output: u128, -) -> (NodeIndex, OriginalSkeletonNode) { - ( - NodeIndex::from(idx), - OriginalSkeletonNode::UnmodifiedSubTree(HashOutput(Felt::from(hash_output))), - ) -} - -pub(crate) fn create_root_edge_entry( - old_root: u128, - subtree_height: SubTreeHeight, -) -> (StorageKey, StorageValue) { - // Assumes path is 0. - let length = SubTreeHeight::ACTUAL_HEIGHT.0 - subtree_height.0; - let new_root = old_root + u128::from(length); - let key = create_db_key( - StarknetPrefix::InnerNode.to_storage_prefix(), - &Felt::from(new_root).to_bytes_be(), - ); - let value = StorageValue( - Felt::from(old_root) - .to_bytes_be() - .into_iter() - .chain(Felt::from(0_u128).to_bytes_be()) - .chain([length]) - .collect(), - ); - (key, value) -} - fn create_previously_empty_leaf_indices<'a>( tree_leaf_indices: &'a [NodeIndex], subtree_leaf_indices: &'a [NodeIndex], diff --git a/crates/committer/src/patricia_merkle_tree/original_skeleton_tree/node.rs b/crates/committer/src/patricia_merkle_tree/original_skeleton_tree/node.rs index 0843201ffd..d4f31f0292 100644 --- a/crates/committer/src/patricia_merkle_tree/original_skeleton_tree/node.rs +++ b/crates/committer/src/patricia_merkle_tree/original_skeleton_tree/node.rs @@ -3,7 +3,7 @@ use crate::patricia_merkle_tree::node_data::inner_node::PathToBottom; #[derive(Copy, Clone, Debug, PartialEq, Eq)] /// A node in the structure of a Patricia-Merkle tree, before the update. -pub(crate) enum OriginalSkeletonNode { +pub enum OriginalSkeletonNode { Binary, Edge(PathToBottom), // Represents a root of a subtree where none of it's descendants has changed. diff --git a/crates/committer/src/patricia_merkle_tree/original_skeleton_tree/tree.rs b/crates/committer/src/patricia_merkle_tree/original_skeleton_tree/tree.rs index 68a195eb9c..42530983eb 100644 --- a/crates/committer/src/patricia_merkle_tree/original_skeleton_tree/tree.rs +++ b/crates/committer/src/patricia_merkle_tree/original_skeleton_tree/tree.rs @@ -8,14 +8,14 @@ use crate::patricia_merkle_tree::original_skeleton_tree::node::OriginalSkeletonN use crate::patricia_merkle_tree::types::{NodeIndex, SortedLeafIndices}; use crate::storage::storage_trait::Storage; -pub(crate) type OriginalSkeletonNodeMap = HashMap; -pub(crate) type OriginalSkeletonTreeResult = Result; +pub type OriginalSkeletonNodeMap = HashMap; +pub type OriginalSkeletonTreeResult = Result; /// 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 unmodified /// nodes on the Merkle paths from the updated leaves to the root. -pub(crate) trait OriginalSkeletonTree<'a>: Sized { +pub trait OriginalSkeletonTree<'a>: Sized { fn create( storage: &impl Storage, root_hash: HashOutput, @@ -40,9 +40,9 @@ pub(crate) trait OriginalSkeletonTree<'a>: Sized { // TODO(Dori, 1/7/2024): Make this a tuple struct. #[derive(Debug, PartialEq)] -pub(crate) struct OriginalSkeletonTreeImpl<'a> { - pub(crate) nodes: HashMap, - pub(crate) sorted_leaf_indices: SortedLeafIndices<'a>, +pub struct OriginalSkeletonTreeImpl<'a> { + pub nodes: HashMap, + pub sorted_leaf_indices: SortedLeafIndices<'a>, } impl<'a> OriginalSkeletonTree<'a> for OriginalSkeletonTreeImpl<'a> { diff --git a/crates/committer/src/patricia_merkle_tree/types.rs b/crates/committer/src/patricia_merkle_tree/types.rs index 4445253d16..c70b49af1c 100644 --- a/crates/committer/src/patricia_merkle_tree/types.rs +++ b/crates/committer/src/patricia_merkle_tree/types.rs @@ -126,11 +126,11 @@ impl NodeIndex { .expect("Illegal PathToBottom") } - pub(crate) fn from_leaf_felt(felt: &Felt) -> Self { + pub fn from_leaf_felt(felt: &Felt) -> Self { Self::FIRST_LEAF + Self::from_felt_value(felt) } - fn from_felt_value(felt: &Felt) -> Self { + pub(crate) fn from_felt_value(felt: &Felt) -> Self { Self(U256::from(felt)) } } @@ -206,19 +206,19 @@ impl TryFrom for Felt { } #[derive(Clone, Copy, Debug, Default, PartialEq)] -pub(crate) struct SortedLeafIndices<'a>(&'a [NodeIndex]); +pub struct SortedLeafIndices<'a>(&'a [NodeIndex]); impl<'a> SortedLeafIndices<'a> { /// Creates a new instance by sorting the given indices. // TODO(Nimrod, 1/8/2024): Remove duplicates from the given indices. - pub(crate) fn new(indices: &'a mut [NodeIndex]) -> Self { + pub fn new(indices: &'a mut [NodeIndex]) -> Self { indices.sort(); Self(indices) } /// Returns a subslice of the indices stored at self, at the range [leftmost_idx, /// rightmost_idx). - pub(crate) fn subslice(&self, leftmost_idx: usize, rightmost_idx: usize) -> Self { + pub fn subslice(&self, leftmost_idx: usize, rightmost_idx: usize) -> Self { Self(&self.0[leftmost_idx..rightmost_idx]) } diff --git a/crates/committer/src/patricia_merkle_tree/types_test.rs b/crates/committer/src/patricia_merkle_tree/types_test.rs index 2caef578ee..08447d3b6f 100644 --- a/crates/committer/src/patricia_merkle_tree/types_test.rs +++ b/crates/committer/src/patricia_merkle_tree/types_test.rs @@ -3,7 +3,6 @@ use rand::rngs::ThreadRng; use rand::Rng; use rstest::rstest; -use crate::block_committer::input::{ContractAddress, StarknetStorageKey}; use crate::felt::Felt; use crate::patricia_merkle_tree::external_test_utils::get_random_u256; use crate::patricia_merkle_tree::internal_test_utils::random; @@ -29,20 +28,6 @@ fn test_compute_bottom_index( assert_eq!(bottom_index, expected); } -#[rstest] -fn test_cast_to_node_index( - #[values(0, 15, 0xDEADBEEF)] leaf_index: u128, - #[values(true, false)] from_contract_address: bool, -) { - let expected_node_index = NodeIndex::FIRST_LEAF + leaf_index; - let actual: NodeIndex = if from_contract_address { - (&ContractAddress(Felt::from(leaf_index))).into() - } else { - (&StarknetStorageKey(Felt::from(leaf_index))).into() - }; - assert_eq!(actual, expected_node_index); -} - #[rstest] #[case(uint!("1"), uint!("1"), uint!("1"))] #[case(uint!("2"), uint!("5"), uint!("2"))] diff --git a/crates/committer/src/patricia_merkle_tree/updated_skeleton_tree.rs b/crates/committer/src/patricia_merkle_tree/updated_skeleton_tree.rs index 2869b48e3e..77f5f35772 100644 --- a/crates/committer/src/patricia_merkle_tree/updated_skeleton_tree.rs +++ b/crates/committer/src/patricia_merkle_tree/updated_skeleton_tree.rs @@ -2,5 +2,4 @@ pub mod create_tree_helper; pub mod errors; pub mod hash_function; pub mod node; -pub mod skeleton_forest; pub mod tree; diff --git a/crates/committer/src/patricia_merkle_tree/updated_skeleton_tree/hash_function.rs b/crates/committer/src/patricia_merkle_tree/updated_skeleton_tree/hash_function.rs index f203c6decf..c35224ca10 100644 --- a/crates/committer/src/patricia_merkle_tree/updated_skeleton_tree/hash_function.rs +++ b/crates/committer/src/patricia_merkle_tree/updated_skeleton_tree/hash_function.rs @@ -1,20 +1,12 @@ -use starknet_types_core::hash::{Pedersen, Poseidon, StarkHash}; - -use crate::block_committer::input::StarknetStorageValue; use crate::felt::Felt; use crate::hash::hash_trait::HashOutput; -use crate::patricia_merkle_tree::filled_tree::node::CompiledClassHash; use crate::patricia_merkle_tree::node_data::inner_node::{ BinaryData, EdgeData, NodeData, PathToBottom, }; -use crate::patricia_merkle_tree::node_data::leaf::{ContractState, Leaf}; - -#[cfg(test)] -#[path = "hash_function_test.rs"] -pub mod hash_function_test; +use crate::patricia_merkle_tree::node_data::leaf::Leaf; /// Trait for hash functions. pub trait HashFunction { @@ -22,22 +14,6 @@ pub trait HashFunction { fn hash(left: &Felt, right: &Felt) -> HashOutput; } -/// Implementation of HashFunction for Pedersen hash function. -pub struct PedersenHashFunction; -impl HashFunction for PedersenHashFunction { - fn hash(left: &Felt, right: &Felt) -> HashOutput { - HashOutput(Felt(Pedersen::hash(&left.0, &right.0))) - } -} - -/// Implementation of HashFunction for Poseidon hash function. -pub struct PoseidonHashFunction; -impl HashFunction for PoseidonHashFunction { - fn hash(left: &Felt, right: &Felt) -> HashOutput { - HashOutput(Felt(Poseidon::hash(&left.0, &right.0))) - } -} - pub trait TreeHashFunction { /// Computes the hash of the given leaf. fn compute_leaf_hash(leaf_data: &L) -> HashOutput; @@ -62,83 +38,3 @@ pub trait TreeHashFunction { } } } - -pub struct TreeHashFunctionImpl; - -impl TreeHashFunctionImpl { - // TODO(Aner, 11/4/24): Verify the correctness of the implementation. - pub const CONTRACT_STATE_HASH_VERSION: Felt = Felt::ZERO; - - // The hex string corresponding to b'CONTRACT_CLASS_LEAF_V0' in big-endian. - pub const CONTRACT_CLASS_LEAF_V0: &'static str = - "0x434f4e54524143545f434c4153535f4c4541465f5630"; -} - -/// Implementation of TreeHashFunction for contracts trie. -/// The implementation is based on the following reference: -/// -impl TreeHashFunction for TreeHashFunctionImpl { - fn compute_leaf_hash(contract_state: &ContractState) -> HashOutput { - HashOutput( - Pedersen::hash( - &Pedersen::hash( - &Pedersen::hash( - &contract_state.class_hash.0.into(), - &contract_state.storage_root_hash.0.into(), - ), - &contract_state.nonce.0.into(), - ), - &Self::CONTRACT_STATE_HASH_VERSION.into(), - ) - .into(), - ) - } - fn compute_node_hash(node_data: &NodeData) -> HashOutput { - Self::compute_node_hash_with_inner_hash_function::(node_data) - } -} - -/// Implementation of TreeHashFunction for the classes trie. -/// The implementation is based on the following reference: -/// -impl TreeHashFunction for TreeHashFunctionImpl { - fn compute_leaf_hash(compiled_class_hash: &CompiledClassHash) -> HashOutput { - let contract_class_leaf_version: Felt = Felt::from_hex(Self::CONTRACT_CLASS_LEAF_V0) - .expect( - "could not parse hex string corresponding to b'CONTRACT_CLASS_LEAF_V0' to Felt", - ); - HashOutput( - Poseidon::hash(&contract_class_leaf_version.into(), &compiled_class_hash.0.into()) - .into(), - ) - } - fn compute_node_hash(node_data: &NodeData) -> HashOutput { - Self::compute_node_hash_with_inner_hash_function::(node_data) - } -} - -/// Implementation of TreeHashFunction for the storage trie. -/// The implementation is based on the following reference: -/// -impl TreeHashFunction for TreeHashFunctionImpl { - fn compute_leaf_hash(storage_value: &StarknetStorageValue) -> HashOutput { - HashOutput(storage_value.0) - } - fn compute_node_hash(node_data: &NodeData) -> HashOutput { - Self::compute_node_hash_with_inner_hash_function::(node_data) - } -} - -/// Combined trait for all specific implementations. -pub(crate) trait ForestHashFunction: - TreeHashFunction - + TreeHashFunction - + TreeHashFunction -{ -} -impl ForestHashFunction for T where - T: TreeHashFunction - + TreeHashFunction - + TreeHashFunction -{ -} diff --git a/crates/committer/src/patricia_merkle_tree/updated_skeleton_tree/node.rs b/crates/committer/src/patricia_merkle_tree/updated_skeleton_tree/node.rs index 0789412f04..0a9139cfd6 100644 --- a/crates/committer/src/patricia_merkle_tree/updated_skeleton_tree/node.rs +++ b/crates/committer/src/patricia_merkle_tree/updated_skeleton_tree/node.rs @@ -3,7 +3,7 @@ use crate::patricia_merkle_tree::node_data::inner_node::PathToBottom; /// A node in the structure of a Patricia-Merkle tree, after the update. #[derive(Debug, Clone, PartialEq)] -pub(crate) enum UpdatedSkeletonNode { +pub enum UpdatedSkeletonNode { Binary, Edge(PathToBottom), // Represents a root of a subtree where none of it's descendants has changed. diff --git a/crates/committer/src/patricia_merkle_tree/updated_skeleton_tree/tree.rs b/crates/committer/src/patricia_merkle_tree/updated_skeleton_tree/tree.rs index 5de0475a40..6afc0cf02f 100644 --- a/crates/committer/src/patricia_merkle_tree/updated_skeleton_tree/tree.rs +++ b/crates/committer/src/patricia_merkle_tree/updated_skeleton_tree/tree.rs @@ -20,7 +20,7 @@ pub(crate) type UpdatedSkeletonTreeResult = Result: Sized + Send + Sync { +pub trait UpdatedSkeletonTree<'a>: Sized + Send + Sync { /// Creates an updated tree from an original tree and modifications. fn create( original_skeleton: &mut impl OriginalSkeletonTree<'a>, @@ -37,7 +37,7 @@ pub(crate) trait UpdatedSkeletonTree<'a>: Sized + Send + Sync { fn get_node(&self, index: NodeIndex) -> UpdatedSkeletonTreeResult<&UpdatedSkeletonNode>; } // TODO(Dori, 1/7/2024): Make this a tuple struct. -pub(crate) struct UpdatedSkeletonTreeImpl { +pub struct UpdatedSkeletonTreeImpl { pub(crate) skeleton_tree: UpdatedSkeletonNodeMap, } diff --git a/crates/committer/src/storage/storage_trait.rs b/crates/committer/src/storage/storage_trait.rs index 190bf5f027..07d681cc7b 100644 --- a/crates/committer/src/storage/storage_trait.rs +++ b/crates/committer/src/storage/storage_trait.rs @@ -43,7 +43,7 @@ pub enum StarknetPrefix { /// Describes a storage prefix as used in Aerospike DB. impl StarknetPrefix { - pub(crate) fn to_bytes(&self) -> &'static [u8] { + pub fn to_bytes(&self) -> &'static [u8] { match self { Self::InnerNode => b"patricia_node", Self::StorageLeaf => b"starknet_storage_leaf", @@ -52,7 +52,7 @@ impl StarknetPrefix { } } - pub(crate) fn to_storage_prefix(&self) -> Vec { + pub fn to_storage_prefix(&self) -> Vec { self.to_bytes().to_vec() } } diff --git a/crates/committer_cli/Cargo.toml b/crates/committer_cli/Cargo.toml index eb703c88e6..e2a6e0a1a2 100644 --- a/crates/committer_cli/Cargo.toml +++ b/crates/committer_cli/Cargo.toml @@ -28,6 +28,7 @@ serde_json = "1.0.116" serde_repr = "0.1.19" starknet-types-core.workspace = true starknet_api.workspace = true +starknet_committer = { path = "../starknet_committer" } strum.workspace = true strum_macros.workspace = true thiserror.workspace = true diff --git a/crates/committer_cli/benches/committer_bench.rs b/crates/committer_cli/benches/committer_bench.rs index 94bf33506a..07bb7096b2 100644 --- a/crates/committer_cli/benches/committer_bench.rs +++ b/crates/committer_cli/benches/committer_bench.rs @@ -10,16 +10,16 @@ use std::collections::HashMap; use std::sync::Arc; -use committer::block_committer::input::StarknetStorageValue; use committer::patricia_merkle_tree::external_test_utils::tree_computation_flow; use committer::patricia_merkle_tree::node_data::leaf::LeafModifications; -use committer::patricia_merkle_tree::original_skeleton_tree::config::OriginalSkeletonStorageTrieConfig; use committer::patricia_merkle_tree::types::NodeIndex; -use committer::patricia_merkle_tree::updated_skeleton_tree::hash_function::TreeHashFunctionImpl; use committer_cli::commands::commit; use committer_cli::parse_input::read::parse_input; use committer_cli::tests::utils::parse_from_python::TreeFlowInput; use criterion::{criterion_group, criterion_main, Criterion}; +use starknet_committer::block_committer::input::StarknetStorageValue; +use starknet_committer::hash_function::hash::TreeHashFunctionImpl; +use starknet_committer::patricia_merkle_tree::tree::OriginalSkeletonStorageTrieConfig; const CONCURRENCY_MODE: bool = true; const SINGLE_TREE_FLOW_INPUT: &str = include_str!("../test_inputs/tree_flow_inputs.json"); diff --git a/crates/committer_cli/src/commands.rs b/crates/committer_cli/src/commands.rs index a6c55633c3..fad171a4cb 100644 --- a/crates/committer_cli/src/commands.rs +++ b/crates/committer_cli/src/commands.rs @@ -1,5 +1,5 @@ -use committer::block_committer::commit::commit_block; -use committer::block_committer::input::{Config, ConfigImpl, Input}; +use starknet_committer::block_committer::commit::commit_block; +use starknet_committer::block_committer::input::{Config, ConfigImpl, Input}; use tracing::info; use tracing::level_filters::LevelFilter; use tracing_subscriber::reload::Handle; @@ -15,7 +15,7 @@ pub async fn parse_and_commit( ) { let input = parse_input(input_string).expect("Failed to parse the given input."); info!( - "Parsed committer input successfully. Original Contracts Trie Root Hash: {:?}, + "Parsed committer input successfully. Original Contracts Trie Root Hash: {:?}, Original Classes Trie Root Hash: {:?}", input.contracts_trie_root_hash, input.classes_trie_root_hash, ); @@ -32,7 +32,7 @@ pub async fn commit(input: Input, output_path: String) { let output = serialized_filled_forest.forest_to_output(); write_to_file(&output_path, &output); info!( - "Successfully committed given block. Updated Contracts Trie Root Hash: {:?}, + "Successfully committed given block. Updated Contracts Trie Root Hash: {:?}, Updated Classes Trie Root Hash: {:?}", output.contract_storage_root_hash, output.compiled_class_root_hash, ); diff --git a/crates/committer_cli/src/filled_tree_output/errors.rs b/crates/committer_cli/src/filled_tree_output/errors.rs index 410cf07eb2..73fc6c5e64 100644 --- a/crates/committer_cli/src/filled_tree_output/errors.rs +++ b/crates/committer_cli/src/filled_tree_output/errors.rs @@ -1,6 +1,6 @@ use std::fmt::Debug; -use committer::patricia_merkle_tree::filled_tree::errors::{ +use starknet_committer::patricia_merkle_tree::types::{ ClassesTrieError, ContractsTrieError, StorageTrieError, diff --git a/crates/committer_cli/src/filled_tree_output/filled_forest.rs b/crates/committer_cli/src/filled_tree_output/filled_forest.rs index b0912499f0..e61107f817 100644 --- a/crates/committer_cli/src/filled_tree_output/filled_forest.rs +++ b/crates/committer_cli/src/filled_tree_output/filled_forest.rs @@ -1,6 +1,6 @@ -use committer::patricia_merkle_tree::filled_tree::forest::FilledForest; use committer::storage::map_storage::MapStorage; use serde::Serialize; +use starknet_committer::forest::filled_forest::FilledForest; pub struct SerializedForest(pub FilledForest); diff --git a/crates/committer_cli/src/parse_input/cast.rs b/crates/committer_cli/src/parse_input/cast.rs index 730db39c7a..c9c1cc3319 100644 --- a/crates/committer_cli/src/parse_input/cast.rs +++ b/crates/committer_cli/src/parse_input/cast.rs @@ -1,6 +1,10 @@ use std::collections::HashMap; -use committer::block_committer::input::{ +use committer::felt::Felt; +use committer::hash::hash_trait::HashOutput; +use committer::storage::errors::DeserializationError; +use committer::storage::storage_trait::{StorageKey, StorageValue}; +use starknet_committer::block_committer::input::{ ConfigImpl, ContractAddress, Input, @@ -8,11 +12,7 @@ use committer::block_committer::input::{ StarknetStorageValue, StateDiff, }; -use committer::felt::Felt; -use committer::hash::hash_trait::HashOutput; -use committer::patricia_merkle_tree::filled_tree::node::{ClassHash, CompiledClassHash, Nonce}; -use committer::storage::errors::DeserializationError; -use committer::storage::storage_trait::{StorageKey, StorageValue}; +use starknet_committer::patricia_merkle_tree::types::{ClassHash, CompiledClassHash, Nonce}; use crate::parse_input::raw_input::RawInput; diff --git a/crates/committer_cli/src/parse_input/raw_input.rs b/crates/committer_cli/src/parse_input/raw_input.rs index 95c13849b9..3efac6c788 100644 --- a/crates/committer_cli/src/parse_input/raw_input.rs +++ b/crates/committer_cli/src/parse_input/raw_input.rs @@ -1,6 +1,6 @@ -use committer::block_committer::input::ConfigImpl; use serde::{Deserialize, Serialize}; use serde_repr::Deserialize_repr; +use starknet_committer::block_committer::input::ConfigImpl; use tracing::level_filters::LevelFilter; type RawFelt = [u8; 32]; diff --git a/crates/committer_cli/src/parse_input/read_test.rs b/crates/committer_cli/src/parse_input/read_test.rs index 71ac25c94f..0d9876d7e6 100644 --- a/crates/committer_cli/src/parse_input/read_test.rs +++ b/crates/committer_cli/src/parse_input/read_test.rs @@ -1,6 +1,11 @@ use std::collections::HashMap; -use committer::block_committer::input::{ +use committer::felt::Felt; +use committer::hash::hash_trait::HashOutput; +use committer::storage::errors::DeserializationError; +use committer::storage::storage_trait::{StorageKey, StorageValue}; +use pretty_assertions::assert_eq; +use starknet_committer::block_committer::input::{ ConfigImpl, ContractAddress, Input, @@ -8,12 +13,7 @@ use committer::block_committer::input::{ StarknetStorageValue, StateDiff, }; -use committer::felt::Felt; -use committer::hash::hash_trait::HashOutput; -use committer::patricia_merkle_tree::filled_tree::node::{ClassHash, CompiledClassHash, Nonce}; -use committer::storage::errors::DeserializationError; -use committer::storage::storage_trait::{StorageKey, StorageValue}; -use pretty_assertions::assert_eq; +use starknet_committer::patricia_merkle_tree::types::{ClassHash, CompiledClassHash, Nonce}; use tracing::level_filters::LevelFilter; use super::parse_input; diff --git a/crates/committer_cli/src/tests/python_tests.rs b/crates/committer_cli/src/tests/python_tests.rs index e44febd094..dfe8363a5e 100644 --- a/crates/committer_cli/src/tests/python_tests.rs +++ b/crates/committer_cli/src/tests/python_tests.rs @@ -2,22 +2,10 @@ use std::collections::HashMap; use std::fmt::Debug; use std::io; -use committer::block_committer::input::{ - ContractAddress, - StarknetStorageKey, - StarknetStorageValue, - StateDiff, -}; use committer::felt::Felt; use committer::hash::hash_trait::HashOutput; use committer::patricia_merkle_tree::external_test_utils::single_tree_flow_test; -use committer::patricia_merkle_tree::filled_tree::forest::FilledForest; -use committer::patricia_merkle_tree::filled_tree::node::{ - ClassHash, - CompiledClassHash, - FilledNode, - Nonce, -}; +use committer::patricia_merkle_tree::filled_tree::node::FilledNode; use committer::patricia_merkle_tree::node_data::inner_node::{ BinaryData, EdgeData, @@ -25,10 +13,7 @@ use committer::patricia_merkle_tree::node_data::inner_node::{ NodeData, PathToBottom, }; -use committer::patricia_merkle_tree::node_data::leaf::ContractState; -use committer::patricia_merkle_tree::original_skeleton_tree::config::OriginalSkeletonStorageTrieConfig; use committer::patricia_merkle_tree::types::SubTreeHeight; -use committer::patricia_merkle_tree::updated_skeleton_tree::hash_function::TreeHashFunctionImpl; use committer::storage::db_object::DBObject; use committer::storage::errors::{DeserializationError, SerializationError}; use committer::storage::map_storage::MapStorage; @@ -41,6 +26,17 @@ use starknet_api::block_hash::block_hash_calculator::{ }; use starknet_api::state::ThinStateDiff; use starknet_api::transaction::TransactionExecutionStatus; +use starknet_committer::block_committer::input::{ + ContractAddress, + StarknetStorageKey, + StarknetStorageValue, + StateDiff, +}; +use starknet_committer::forest::filled_forest::FilledForest; +use starknet_committer::hash_function::hash::TreeHashFunctionImpl; +use starknet_committer::patricia_merkle_tree::leaf::leaf_impl::ContractState; +use starknet_committer::patricia_merkle_tree::tree::OriginalSkeletonStorageTrieConfig; +use starknet_committer::patricia_merkle_tree::types::{ClassHash, CompiledClassHash, Nonce}; use starknet_types_core::hash::{Pedersen, StarkHash}; use thiserror; use tracing::{debug, error, info, warn}; diff --git a/crates/committer_cli/src/tests/regression_tests.rs b/crates/committer_cli/src/tests/regression_tests.rs index 0b418eb059..f737ee7bfb 100644 --- a/crates/committer_cli/src/tests/regression_tests.rs +++ b/crates/committer_cli/src/tests/regression_tests.rs @@ -2,12 +2,12 @@ use std::collections::HashMap; use std::fs; use clap::Error; -use committer::block_committer::input::{ConfigImpl, Input, StarknetStorageValue}; use committer::patricia_merkle_tree::external_test_utils::single_tree_flow_test; -use committer::patricia_merkle_tree::original_skeleton_tree::config::OriginalSkeletonStorageTrieConfig; -use committer::patricia_merkle_tree::updated_skeleton_tree::hash_function::TreeHashFunctionImpl; use serde::{Deserialize, Deserializer}; use serde_json::{Map, Value}; +use starknet_committer::block_committer::input::{ConfigImpl, Input, StarknetStorageValue}; +use starknet_committer::hash_function::hash::TreeHashFunctionImpl; +use starknet_committer::patricia_merkle_tree::tree::OriginalSkeletonStorageTrieConfig; use tempfile::NamedTempFile; use super::utils::parse_from_python::parse_input_single_storage_tree_flow_test; diff --git a/crates/committer_cli/src/tests/utils/parse_from_python.rs b/crates/committer_cli/src/tests/utils/parse_from_python.rs index 78ace87dac..43678ddbdd 100644 --- a/crates/committer_cli/src/tests/utils/parse_from_python.rs +++ b/crates/committer_cli/src/tests/utils/parse_from_python.rs @@ -1,6 +1,5 @@ use std::collections::HashMap; -use committer::block_committer::input::StarknetStorageValue; use committer::felt::Felt; use committer::hash::hash_trait::HashOutput; use committer::patricia_merkle_tree::node_data::leaf::LeafModifications; @@ -9,6 +8,7 @@ use committer::storage::map_storage::MapStorage; use committer::storage::storage_trait::{StorageKey, StorageValue}; use ethnum::U256; use serde::{Deserialize, Deserializer}; +use starknet_committer::block_committer::input::StarknetStorageValue; use crate::parse_input::cast::add_unique; use crate::parse_input::raw_input::RawStorageEntry; diff --git a/crates/committer_cli/src/tests/utils/random_structs.rs b/crates/committer_cli/src/tests/utils/random_structs.rs index caf0995b8c..fe04930277 100644 --- a/crates/committer_cli/src/tests/utils/random_structs.rs +++ b/crates/committer_cli/src/tests/utils/random_structs.rs @@ -1,23 +1,10 @@ use std::cmp::min; use std::collections::HashMap; -use committer::block_committer::input::{ContractAddress, StarknetStorageValue}; use committer::felt::Felt; use committer::hash::hash_trait::HashOutput; use committer::patricia_merkle_tree::external_test_utils::get_random_u256; -use committer::patricia_merkle_tree::filled_tree::forest::FilledForest; -use committer::patricia_merkle_tree::filled_tree::node::{ - ClassHash, - CompiledClassHash, - FilledNode, - Nonce, -}; -use committer::patricia_merkle_tree::filled_tree::tree::{ - ClassesTrie, - ContractsTrie, - StorageTrie, - StorageTrieMap, -}; +use committer::patricia_merkle_tree::filled_tree::node::FilledNode; use committer::patricia_merkle_tree::node_data::inner_node::{ BinaryData, EdgeData, @@ -27,13 +14,24 @@ use committer::patricia_merkle_tree::node_data::inner_node::{ NodeDataDiscriminants as NodeDataVariants, PathToBottom, }; -use committer::patricia_merkle_tree::node_data::leaf::ContractState; use committer::patricia_merkle_tree::types::NodeIndex; use ethnum::U256; use rand::prelude::IteratorRandom; use rand::Rng; use rand_distr::num_traits::ToPrimitive; use rand_distr::{Distribution, Geometric}; +use starknet_committer::block_committer::input::{ContractAddress, StarknetStorageValue}; +use starknet_committer::forest::filled_forest::FilledForest; +use starknet_committer::patricia_merkle_tree::leaf::leaf_impl::ContractState; +use starknet_committer::patricia_merkle_tree::types::{ + ClassHash, + ClassesTrie, + CompiledClassHash, + ContractsTrie, + Nonce, + StorageTrie, + StorageTrieMap, +}; use strum::IntoEnumIterator; pub trait RandomValue { diff --git a/crates/starknet_committer/Cargo.toml b/crates/starknet_committer/Cargo.toml new file mode 100644 index 0000000000..5b0bca0fb8 --- /dev/null +++ b/crates/starknet_committer/Cargo.toml @@ -0,0 +1,23 @@ +[package] +name = "starknet_committer" +version = "0.1.0-rc.0" +edition.workspace = true +repository.workspace = true +license.workspace = true +license-file.workspace = true +description = "Computes and manages Starknet state." + + +[dependencies] +committer = { path = "../committer", features = ["testing"] } +hex.workspace = true +pretty_assertions.workspace = true +rstest.workspace = true +serde_json.workspace = true +starknet-types-core.workspace = true +thiserror.workspace = true +tokio.workspace = true +tracing.workspace = true + +[lints] +workspace = true diff --git a/crates/committer/src/block_committer.rs b/crates/starknet_committer/src/block_committer.rs similarity index 100% rename from crates/committer/src/block_committer.rs rename to crates/starknet_committer/src/block_committer.rs diff --git a/crates/committer/src/block_committer/commit.rs b/crates/starknet_committer/src/block_committer/commit.rs similarity index 88% rename from crates/committer/src/block_committer/commit.rs rename to crates/starknet_committer/src/block_committer/commit.rs index 5b614e5e5f..36ba909cd1 100644 --- a/crates/committer/src/block_committer/commit.rs +++ b/crates/starknet_committer/src/block_committer/commit.rs @@ -1,20 +1,17 @@ use std::collections::HashMap; +use committer::patricia_merkle_tree::types::{NodeIndex, SortedLeafIndices}; +use committer::storage::map_storage::MapStorage; use tracing::{info, warn}; use crate::block_committer::errors::BlockCommitmentError; use crate::block_committer::input::{Config, ConfigImpl, ContractAddress, Input, StateDiff}; -use crate::patricia_merkle_tree::filled_tree::forest::FilledForest; -use crate::patricia_merkle_tree::filled_tree::node::{ClassHash, Nonce}; -use crate::patricia_merkle_tree::node_data::leaf::ContractState; -use crate::patricia_merkle_tree::original_skeleton_tree::skeleton_forest::{ - ForestSortedIndices, - OriginalSkeletonForest, -}; -use crate::patricia_merkle_tree::types::{NodeIndex, SortedLeafIndices}; -use crate::patricia_merkle_tree::updated_skeleton_tree::hash_function::TreeHashFunctionImpl; -use crate::patricia_merkle_tree::updated_skeleton_tree::skeleton_forest::UpdatedSkeletonForest; -use crate::storage::map_storage::MapStorage; +use crate::forest::filled_forest::FilledForest; +use crate::forest::original_skeleton_forest::{ForestSortedIndices, OriginalSkeletonForest}; +use crate::forest::updated_skeleton_forest::UpdatedSkeletonForest; +use crate::hash_function::hash::TreeHashFunctionImpl; +use crate::patricia_merkle_tree::leaf::leaf_impl::ContractState; +use crate::patricia_merkle_tree::types::{ClassHash, Nonce}; type BlockCommitmentResult = Result; diff --git a/crates/committer/src/block_committer/errors.rs b/crates/starknet_committer/src/block_committer/errors.rs similarity index 75% rename from crates/committer/src/block_committer/errors.rs rename to crates/starknet_committer/src/block_committer/errors.rs index f2c7d4d2ae..e9a6a7651d 100644 --- a/crates/committer/src/block_committer/errors.rs +++ b/crates/starknet_committer/src/block_committer/errors.rs @@ -1,6 +1,6 @@ use thiserror::Error; -use crate::forest_errors::ForestError; +use crate::forest::forest_errors::ForestError; #[derive(Debug, Error)] pub enum BlockCommitmentError { diff --git a/crates/committer/src/block_committer/input.rs b/crates/starknet_committer/src/block_committer/input.rs similarity index 93% rename from crates/committer/src/block_committer/input.rs rename to crates/starknet_committer/src/block_committer/input.rs index ef0805e6e3..61c1bbc99d 100644 --- a/crates/committer/src/block_committer/input.rs +++ b/crates/starknet_committer/src/block_committer/input.rs @@ -1,14 +1,14 @@ use std::collections::{HashMap, HashSet}; use std::fmt::Debug; +use committer::felt::Felt; +use committer::hash::hash_trait::HashOutput; +use committer::patricia_merkle_tree::node_data::leaf::{LeafModifications, SkeletonLeaf}; +use committer::patricia_merkle_tree::types::NodeIndex; +use committer::storage::storage_trait::{StorageKey, StorageValue}; use tracing::level_filters::LevelFilter; -use crate::felt::Felt; -use crate::hash::hash_trait::HashOutput; -use crate::patricia_merkle_tree::filled_tree::node::{ClassHash, CompiledClassHash, Nonce}; -use crate::patricia_merkle_tree::node_data::leaf::{LeafModifications, SkeletonLeaf}; -use crate::patricia_merkle_tree::types::NodeIndex; -use crate::storage::storage_trait::{StorageKey, StorageValue}; +use crate::patricia_merkle_tree::types::{ClassHash, CompiledClassHash, Nonce}; #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] // TODO(Nimrod, 1/6/2025): Use the ContractAddress defined in starknet-types-core when available. diff --git a/crates/starknet_committer/src/forest.rs b/crates/starknet_committer/src/forest.rs new file mode 100644 index 0000000000..2da6badbc6 --- /dev/null +++ b/crates/starknet_committer/src/forest.rs @@ -0,0 +1,6 @@ +pub mod filled_forest; +pub mod forest_errors; +pub mod original_skeleton_forest; +#[cfg(test)] +pub mod skeleton_forest_test; +pub mod updated_skeleton_forest; diff --git a/crates/committer/src/patricia_merkle_tree/filled_tree/forest.rs b/crates/starknet_committer/src/forest/filled_forest.rs similarity index 85% rename from crates/committer/src/patricia_merkle_tree/filled_tree/forest.rs rename to crates/starknet_committer/src/forest/filled_forest.rs index effa59490b..2f472560b2 100644 --- a/crates/committer/src/patricia_merkle_tree/filled_tree/forest.rs +++ b/crates/starknet_committer/src/forest/filled_forest.rs @@ -1,25 +1,28 @@ use std::collections::HashMap; use std::sync::Arc; +use committer::hash::hash_trait::HashOutput; +use committer::patricia_merkle_tree::filled_tree::tree::FilledTree; +use committer::patricia_merkle_tree::node_data::leaf::LeafModifications; +use committer::patricia_merkle_tree::types::NodeIndex; +use committer::patricia_merkle_tree::updated_skeleton_tree::tree::UpdatedSkeletonTreeImpl; +use committer::storage::storage_trait::Storage; use tokio::task::JoinSet; use crate::block_committer::input::{ContractAddress, StarknetStorageValue}; -use crate::forest_errors::{ForestError, ForestResult}; -use crate::hash::hash_trait::HashOutput; -use crate::patricia_merkle_tree::filled_tree::node::{ClassHash, CompiledClassHash, Nonce}; -use crate::patricia_merkle_tree::filled_tree::tree::{ +use crate::forest::forest_errors::{ForestError, ForestResult}; +use crate::forest::updated_skeleton_forest::UpdatedSkeletonForest; +use crate::hash_function::hash::ForestHashFunction; +use crate::patricia_merkle_tree::leaf::leaf_impl::ContractState; +use crate::patricia_merkle_tree::types::{ + ClassHash, ClassesTrie, + CompiledClassHash, ContractsTrie, - FilledTree, + Nonce, StorageTrie, StorageTrieMap, }; -use crate::patricia_merkle_tree::node_data::leaf::{ContractState, LeafModifications}; -use crate::patricia_merkle_tree::types::NodeIndex; -use crate::patricia_merkle_tree::updated_skeleton_tree::hash_function::ForestHashFunction; -use crate::patricia_merkle_tree::updated_skeleton_tree::skeleton_forest::UpdatedSkeletonForest; -use crate::patricia_merkle_tree::updated_skeleton_tree::tree::UpdatedSkeletonTreeImpl; -use crate::storage::storage_trait::Storage; pub struct FilledForest { pub storage_tries: StorageTrieMap, diff --git a/crates/committer/src/forest_errors.rs b/crates/starknet_committer/src/forest/forest_errors.rs similarity index 80% rename from crates/committer/src/forest_errors.rs rename to crates/starknet_committer/src/forest/forest_errors.rs index 36549bfd53..a34b12511b 100644 --- a/crates/committer/src/forest_errors.rs +++ b/crates/starknet_committer/src/forest/forest_errors.rs @@ -1,14 +1,10 @@ +use committer::patricia_merkle_tree::original_skeleton_tree::errors::OriginalSkeletonTreeError; +use committer::patricia_merkle_tree::updated_skeleton_tree::errors::UpdatedSkeletonTreeError; use thiserror::Error; use tokio::task::JoinError; use crate::block_committer::input::ContractAddress; -use crate::patricia_merkle_tree::filled_tree::errors::{ - ClassesTrieError, - ContractsTrieError, - StorageTrieError, -}; -use crate::patricia_merkle_tree::original_skeleton_tree::errors::OriginalSkeletonTreeError; -use crate::patricia_merkle_tree::updated_skeleton_tree::errors::UpdatedSkeletonTreeError; +use crate::patricia_merkle_tree::types::{ClassesTrieError, ContractsTrieError, StorageTrieError}; pub(crate) type ForestResult = Result; diff --git a/crates/committer/src/patricia_merkle_tree/original_skeleton_tree/skeleton_forest.rs b/crates/starknet_committer/src/forest/original_skeleton_forest.rs similarity index 90% rename from crates/committer/src/patricia_merkle_tree/original_skeleton_tree/skeleton_forest.rs rename to crates/starknet_committer/src/forest/original_skeleton_forest.rs index 8b0829c60b..6ae89fdefd 100644 --- a/crates/committer/src/patricia_merkle_tree/original_skeleton_tree/skeleton_forest.rs +++ b/crates/starknet_committer/src/forest/original_skeleton_forest.rs @@ -1,25 +1,23 @@ use std::collections::HashMap; +use committer::hash::hash_trait::HashOutput; +use committer::patricia_merkle_tree::node_data::leaf::LeafModifications; +use committer::patricia_merkle_tree::original_skeleton_tree::tree::{ + OriginalSkeletonTree, + OriginalSkeletonTreeImpl, +}; +use committer::patricia_merkle_tree::types::{NodeIndex, SortedLeafIndices}; +use committer::storage::storage_trait::Storage; + use crate::block_committer::input::{Config, ContractAddress, StarknetStorageValue}; -use crate::forest_errors::{ForestError, ForestResult}; -use crate::hash::hash_trait::HashOutput; -use crate::patricia_merkle_tree::filled_tree::node::CompiledClassHash; -use crate::patricia_merkle_tree::node_data::leaf::{ContractState, LeafModifications}; -use crate::patricia_merkle_tree::original_skeleton_tree::config::{ +use crate::forest::forest_errors::{ForestError, ForestResult}; +use crate::patricia_merkle_tree::leaf::leaf_impl::ContractState; +use crate::patricia_merkle_tree::tree::{ OriginalSkeletonClassesTrieConfig, OriginalSkeletonContractsTrieConfig, OriginalSkeletonStorageTrieConfig, }; -use crate::patricia_merkle_tree::original_skeleton_tree::tree::{ - OriginalSkeletonTree, - OriginalSkeletonTreeImpl, -}; -use crate::patricia_merkle_tree::types::{NodeIndex, SortedLeafIndices}; -use crate::storage::storage_trait::Storage; - -#[cfg(test)] -#[path = "skeleton_forest_test.rs"] -pub mod skeleton_forest_test; +use crate::patricia_merkle_tree::types::CompiledClassHash; #[derive(Debug, PartialEq)] pub(crate) struct OriginalSkeletonForest<'a> { diff --git a/crates/committer/src/patricia_merkle_tree/original_skeleton_tree/skeleton_forest_test.rs b/crates/starknet_committer/src/forest/skeleton_forest_test.rs similarity index 95% rename from crates/committer/src/patricia_merkle_tree/original_skeleton_tree/skeleton_forest_test.rs rename to crates/starknet_committer/src/forest/skeleton_forest_test.rs index 2b9dbaa0ea..cda9d04d1f 100644 --- a/crates/committer/src/patricia_merkle_tree/original_skeleton_tree/skeleton_forest_test.rs +++ b/crates/starknet_committer/src/forest/skeleton_forest_test.rs @@ -1,10 +1,26 @@ use std::collections::HashMap; +use committer::felt::Felt; +use committer::hash::hash_trait::HashOutput; +use committer::patricia_merkle_tree::external_test_utils::{ + create_32_bytes_entry, + create_binary_entry, + create_binary_skeleton_node, + create_edge_entry, + create_edge_skeleton_node, + create_expected_skeleton_nodes, + create_root_edge_entry, + create_unmodified_subtree_skeleton_node, +}; +use committer::patricia_merkle_tree::original_skeleton_tree::tree::OriginalSkeletonTreeImpl; +use committer::patricia_merkle_tree::types::{NodeIndex, SortedLeafIndices, SubTreeHeight}; +use committer::storage::db_object::DBObject; +use committer::storage::map_storage::MapStorage; +use committer::storage::storage_trait::{StorageKey, StorageValue}; use pretty_assertions::assert_eq; use rstest::rstest; use tracing::level_filters::LevelFilter; -use super::OriginalSkeletonForest; use crate::block_committer::commit::get_all_modified_indices; use crate::block_committer::input::{ ConfigImpl, @@ -14,26 +30,9 @@ use crate::block_committer::input::{ StarknetStorageValue, StateDiff, }; -use crate::felt::Felt; -use crate::hash::hash_trait::HashOutput; -use crate::patricia_merkle_tree::filled_tree::node::{ClassHash, CompiledClassHash, Nonce}; -use crate::patricia_merkle_tree::node_data::leaf::ContractState; -use crate::patricia_merkle_tree::original_skeleton_tree::create_tree::create_tree_test::{ - create_32_bytes_entry, - create_binary_entry, - create_binary_skeleton_node, - create_edge_entry, - create_edge_skeleton_node, - create_expected_skeleton_nodes, - create_root_edge_entry, - create_unmodified_subtree_skeleton_node, -}; -use crate::patricia_merkle_tree::original_skeleton_tree::skeleton_forest::ForestSortedIndices; -use crate::patricia_merkle_tree::original_skeleton_tree::tree::OriginalSkeletonTreeImpl; -use crate::patricia_merkle_tree::types::{NodeIndex, SortedLeafIndices, SubTreeHeight}; -use crate::storage::db_object::DBObject; -use crate::storage::map_storage::MapStorage; -use crate::storage::storage_trait::{StorageKey, StorageValue}; +use crate::forest::original_skeleton_forest::{ForestSortedIndices, OriginalSkeletonForest}; +use crate::patricia_merkle_tree::leaf::leaf_impl::ContractState; +use crate::patricia_merkle_tree::types::{ClassHash, CompiledClassHash, Nonce}; macro_rules! compare_skeleton_tree { ($actual_skeleton:expr, $expected_skeleton:expr, $expected_indices:expr) => {{ diff --git a/crates/committer/src/patricia_merkle_tree/updated_skeleton_tree/skeleton_forest.rs b/crates/starknet_committer/src/forest/updated_skeleton_forest.rs similarity index 87% rename from crates/committer/src/patricia_merkle_tree/updated_skeleton_tree/skeleton_forest.rs rename to crates/starknet_committer/src/forest/updated_skeleton_forest.rs index 0d6316fa08..c41e44f3c7 100644 --- a/crates/committer/src/patricia_merkle_tree/updated_skeleton_tree/skeleton_forest.rs +++ b/crates/starknet_committer/src/forest/updated_skeleton_forest.rs @@ -1,21 +1,19 @@ use std::collections::HashMap; -use crate::block_committer::input::ContractAddress; -use crate::felt::Felt; -use crate::forest_errors::{ForestError, ForestResult}; -use crate::patricia_merkle_tree::filled_tree::node::{ClassHash, Nonce}; -use crate::patricia_merkle_tree::node_data::leaf::{ - ContractState, - LeafModifications, - SkeletonLeaf, -}; -use crate::patricia_merkle_tree::original_skeleton_tree::skeleton_forest::OriginalSkeletonForest; -use crate::patricia_merkle_tree::types::NodeIndex; -use crate::patricia_merkle_tree::updated_skeleton_tree::tree::{ +use committer::felt::Felt; +use committer::patricia_merkle_tree::node_data::leaf::{LeafModifications, SkeletonLeaf}; +use committer::patricia_merkle_tree::types::NodeIndex; +use committer::patricia_merkle_tree::updated_skeleton_tree::tree::{ UpdatedSkeletonTree, UpdatedSkeletonTreeImpl, }; +use crate::block_committer::input::ContractAddress; +use crate::forest::forest_errors::{ForestError, ForestResult}; +use crate::forest::original_skeleton_forest::OriginalSkeletonForest; +use crate::patricia_merkle_tree::leaf::leaf_impl::ContractState; +use crate::patricia_merkle_tree::types::{ClassHash, Nonce}; + pub(crate) struct UpdatedSkeletonForest { pub(crate) classes_trie: UpdatedSkeletonTreeImpl, pub(crate) contracts_trie: UpdatedSkeletonTreeImpl, diff --git a/crates/starknet_committer/src/hash_function.rs b/crates/starknet_committer/src/hash_function.rs new file mode 100644 index 0000000000..a17e8f4aad --- /dev/null +++ b/crates/starknet_committer/src/hash_function.rs @@ -0,0 +1,3 @@ +pub mod hash; +#[cfg(test)] +pub mod hash_test; diff --git a/crates/starknet_committer/src/hash_function/hash.rs b/crates/starknet_committer/src/hash_function/hash.rs new file mode 100644 index 0000000000..953c5e4579 --- /dev/null +++ b/crates/starknet_committer/src/hash_function/hash.rs @@ -0,0 +1,108 @@ +use committer::felt::Felt; +use committer::hash::hash_trait::HashOutput; +use committer::patricia_merkle_tree::node_data::inner_node::NodeData; +use committer::patricia_merkle_tree::updated_skeleton_tree::hash_function::{ + HashFunction, + TreeHashFunction, +}; +use starknet_types_core::hash::{Pedersen, Poseidon, StarkHash}; + +use crate::block_committer::input::StarknetStorageValue; +use crate::patricia_merkle_tree::leaf::leaf_impl::ContractState; +use crate::patricia_merkle_tree::types::CompiledClassHash; + +/// Implementation of HashFunction for Pedersen hash function. +pub struct PedersenHashFunction; +impl HashFunction for PedersenHashFunction { + fn hash(left: &Felt, right: &Felt) -> HashOutput { + HashOutput(Felt(Pedersen::hash(&left.0, &right.0))) + } +} + +/// Implementation of HashFunction for Poseidon hash function. +pub struct PoseidonHashFunction; +impl HashFunction for PoseidonHashFunction { + fn hash(left: &Felt, right: &Felt) -> HashOutput { + HashOutput(Felt(Poseidon::hash(&left.0, &right.0))) + } +} + +pub struct TreeHashFunctionImpl; + +impl TreeHashFunctionImpl { + // TODO(Aner, 11/4/24): Verify the correctness of the implementation. + pub const CONTRACT_STATE_HASH_VERSION: Felt = Felt::ZERO; + + // The hex string corresponding to b'CONTRACT_CLASS_LEAF_V0' in big-endian. + pub const CONTRACT_CLASS_LEAF_V0: &'static str = + "0x434f4e54524143545f434c4153535f4c4541465f5630"; +} + +/// Implementation of TreeHashFunction for contracts trie. +/// The implementation is based on the following reference: +/// +impl TreeHashFunction for TreeHashFunctionImpl { + fn compute_leaf_hash(contract_state: &ContractState) -> HashOutput { + HashOutput( + Pedersen::hash( + &Pedersen::hash( + &Pedersen::hash( + &contract_state.class_hash.0.into(), + &contract_state.storage_root_hash.0.into(), + ), + &contract_state.nonce.0.into(), + ), + &Self::CONTRACT_STATE_HASH_VERSION.into(), + ) + .into(), + ) + } + fn compute_node_hash(node_data: &NodeData) -> HashOutput { + Self::compute_node_hash_with_inner_hash_function::(node_data) + } +} + +/// Implementation of TreeHashFunction for the classes trie. +/// The implementation is based on the following reference: +/// +impl TreeHashFunction for TreeHashFunctionImpl { + fn compute_leaf_hash(compiled_class_hash: &CompiledClassHash) -> HashOutput { + let contract_class_leaf_version: Felt = Felt::from_hex(Self::CONTRACT_CLASS_LEAF_V0) + .expect( + "could not parse hex string corresponding to b'CONTRACT_CLASS_LEAF_V0' to Felt", + ); + HashOutput( + Poseidon::hash(&contract_class_leaf_version.into(), &compiled_class_hash.0.into()) + .into(), + ) + } + fn compute_node_hash(node_data: &NodeData) -> HashOutput { + Self::compute_node_hash_with_inner_hash_function::(node_data) + } +} + +/// Implementation of TreeHashFunction for the storage trie. +/// The implementation is based on the following reference: +/// +impl TreeHashFunction for TreeHashFunctionImpl { + fn compute_leaf_hash(storage_value: &StarknetStorageValue) -> HashOutput { + HashOutput(storage_value.0) + } + fn compute_node_hash(node_data: &NodeData) -> HashOutput { + Self::compute_node_hash_with_inner_hash_function::(node_data) + } +} + +/// Combined trait for all specific implementations. +pub(crate) trait ForestHashFunction: + TreeHashFunction + + TreeHashFunction + + TreeHashFunction +{ +} +impl ForestHashFunction for T where + T: TreeHashFunction + + TreeHashFunction + + TreeHashFunction +{ +} diff --git a/crates/committer/src/patricia_merkle_tree/updated_skeleton_tree/hash_function_test.rs b/crates/starknet_committer/src/hash_function/hash_test.rs similarity index 90% rename from crates/committer/src/patricia_merkle_tree/updated_skeleton_tree/hash_function_test.rs rename to crates/starknet_committer/src/hash_function/hash_test.rs index a08b686d58..5fdb2ef741 100644 --- a/crates/committer/src/patricia_merkle_tree/updated_skeleton_tree/hash_function_test.rs +++ b/crates/starknet_committer/src/hash_function/hash_test.rs @@ -1,77 +1,21 @@ -use rstest::rstest; -use starknet_types_core::hash::{Pedersen, StarkHash}; - -use crate::block_committer::input::StarknetStorageValue; -use crate::felt::Felt; -use crate::hash::hash_trait::HashOutput; -use crate::patricia_merkle_tree::filled_tree::node::{ClassHash, CompiledClassHash, Nonce}; -use crate::patricia_merkle_tree::node_data::inner_node::{ +use committer::felt::Felt; +use committer::hash::hash_trait::HashOutput; +use committer::patricia_merkle_tree::node_data::inner_node::{ BinaryData, EdgeData, EdgePathLength, NodeData, PathToBottom, }; -use crate::patricia_merkle_tree::node_data::leaf::ContractState; -use crate::patricia_merkle_tree::updated_skeleton_tree::hash_function::{ - TreeHashFunction, - TreeHashFunctionImpl, -}; - -#[rstest] -#[case(Felt::ONE, Felt::TWO, Felt::from_hex("0x5bb9440e27889a364bcb678b1f679ecd1347acdedcbf36e83494f857cc58026").unwrap())] -#[case(Felt::from(0xBE_u128), Felt::from(0xA0BEE_u128), Felt::from_hex("0x4e8f149d7d5adb77a8c85b631a3acb6fb9aa5ecb06ea4ec105753629243e380").unwrap())] -#[case(Felt::from(0x1234_u128), Felt::from(0xABCD_u128), Felt::from_hex("0x615bb8d47888d2987ad0c63fc06e9e771930986a4dd8adc55617febfcf3639e").unwrap())] -fn test_tree_hash_function_impl_binary_node( - #[case] left_hash: Felt, - #[case] right_hash: Felt, - #[case] expected_hash: Felt, -) { - let hash_output = - TreeHashFunctionImpl::compute_node_hash(&NodeData::::Binary( - BinaryData { left_hash: HashOutput(left_hash), right_hash: HashOutput(right_hash) }, - )); - assert_eq!( - hash_output, - HashOutput(Pedersen::hash(&left_hash.into(), &right_hash.into()).into()) - ); - assert_eq!(hash_output, HashOutput(expected_hash)); -} - -#[rstest] -#[case(Felt::ONE, 2_u128, 3, Felt::from_hex("0x5bb9440e27889a364bcb678b1f679ecd1347acdedcbf36e83494f857cc58029").unwrap())] -#[case(Felt::from(0xBE_u128), 0xA0BEE_u128, 0xBB, Felt::from_hex("0x4e8f149d7d5adb77a8c85b631a3acb6fb9aa5ecb06ea4ec105753629243e43b").unwrap())] -#[case(Felt::from(0x1234ABCD_u128),42_u128,6, Felt::from_hex("0x1d937094c09b5f8e26a662d21911871e3cbc6858d55cc49af9848ea6fed4e9").unwrap())] -fn test_tree_hash_function_impl_edge_node( - #[case] bottom_hash: Felt, - #[case] edge_path: u128, - #[case] length: u8, - #[case] expected_hash: Felt, -) { - let hash_output = TreeHashFunctionImpl::compute_node_hash( - &NodeData::::Edge(EdgeData { - bottom_hash: HashOutput(bottom_hash), - path_to_bottom: PathToBottom::new( - edge_path.into(), - EdgePathLength::new(length).unwrap(), - ) - .unwrap(), - }), - ); - let direct_hash_computation = HashOutput( - Felt::from(Pedersen::hash(&bottom_hash.into(), &edge_path.into())) + length.into(), - ); - assert_eq!(hash_output, HashOutput(expected_hash)); - assert_eq!(hash_output, direct_hash_computation); -} +use committer::patricia_merkle_tree::updated_skeleton_tree::hash_function::TreeHashFunction; +use hex; +use rstest::rstest; +use starknet_types_core::hash::Pedersen; -#[rstest] -fn test_constant_contract_class_leaf_v0() { - assert_eq!( - hex::decode(TreeHashFunctionImpl::CONTRACT_CLASS_LEAF_V0.trim_start_matches("0x")).unwrap(), - b"CONTRACT_CLASS_LEAF_V0".as_slice() - ); -} +use crate::block_committer::input::StarknetStorageValue; +use crate::hash_function::hash::TreeHashFunctionImpl; +use crate::patricia_merkle_tree::leaf::leaf_impl::ContractState; +use crate::patricia_merkle_tree::types::{ClassHash, CompiledClassHash, Nonce}; #[rstest] // Random StateTreeTuples and the expected hash results were generated and computed elsewhere. @@ -137,3 +81,62 @@ fn test_tree_hash_function_storage_leaf( let hash_output = TreeHashFunctionImpl::compute_node_hash(&node_data); assert_eq!(hash_output, HashOutput(expected_hash)); } + +#[rstest] +#[case(Felt::ONE, Felt::TWO, Felt::from_hex("0x5bb9440e27889a364bcb678b1f679ecd1347acdedcbf36e83494f857cc58026").unwrap())] +#[case(Felt::from(0xBE_u128), Felt::from(0xA0BEE_u128), Felt::from_hex("0x4e8f149d7d5adb77a8c85b631a3acb6fb9aa5ecb06ea4ec105753629243e380").unwrap())] +#[case(Felt::from(0x1234_u128), Felt::from(0xABCD_u128), Felt::from_hex("0x615bb8d47888d2987ad0c63fc06e9e771930986a4dd8adc55617febfcf3639e").unwrap())] +fn test_tree_hash_function_impl_binary_node( + #[case] left_hash: Felt, + #[case] right_hash: Felt, + #[case] expected_hash: Felt, +) { + use starknet_types_core::hash::StarkHash; + + let hash_output = + TreeHashFunctionImpl::compute_node_hash(&NodeData::::Binary( + BinaryData { left_hash: HashOutput(left_hash), right_hash: HashOutput(right_hash) }, + )); + assert_eq!( + hash_output, + HashOutput(Pedersen::hash(&left_hash.into(), &right_hash.into()).into()) + ); + assert_eq!(hash_output, HashOutput(expected_hash)); +} + +#[rstest] +#[case(Felt::ONE, 2_u128, 3, Felt::from_hex("0x5bb9440e27889a364bcb678b1f679ecd1347acdedcbf36e83494f857cc58029").unwrap())] +#[case(Felt::from(0xBE_u128), 0xA0BEE_u128, 0xBB, Felt::from_hex("0x4e8f149d7d5adb77a8c85b631a3acb6fb9aa5ecb06ea4ec105753629243e43b").unwrap())] +#[case(Felt::from(0x1234ABCD_u128),42_u128,6, Felt::from_hex("0x1d937094c09b5f8e26a662d21911871e3cbc6858d55cc49af9848ea6fed4e9").unwrap())] +fn test_tree_hash_function_impl_edge_node( + #[case] bottom_hash: Felt, + #[case] edge_path: u128, + #[case] length: u8, + #[case] expected_hash: Felt, +) { + use starknet_types_core::hash::StarkHash; + + let hash_output = TreeHashFunctionImpl::compute_node_hash( + &NodeData::::Edge(EdgeData { + bottom_hash: HashOutput(bottom_hash), + path_to_bottom: PathToBottom::new( + edge_path.into(), + EdgePathLength::new(length).unwrap(), + ) + .unwrap(), + }), + ); + let direct_hash_computation = HashOutput( + Felt::from(Pedersen::hash(&bottom_hash.into(), &edge_path.into())) + length.into(), + ); + assert_eq!(hash_output, HashOutput(expected_hash)); + assert_eq!(hash_output, direct_hash_computation); +} + +#[rstest] +fn test_constant_contract_class_leaf_v0() { + assert_eq!( + hex::decode(TreeHashFunctionImpl::CONTRACT_CLASS_LEAF_V0.trim_start_matches("0x")).unwrap(), + b"CONTRACT_CLASS_LEAF_V0".as_slice() + ); +} diff --git a/crates/starknet_committer/src/lib.rs b/crates/starknet_committer/src/lib.rs new file mode 100644 index 0000000000..4e1afcd3ad --- /dev/null +++ b/crates/starknet_committer/src/lib.rs @@ -0,0 +1,4 @@ +pub mod block_committer; +pub mod forest; +pub mod hash_function; +pub mod patricia_merkle_tree; diff --git a/crates/starknet_committer/src/patricia_merkle_tree.rs b/crates/starknet_committer/src/patricia_merkle_tree.rs new file mode 100644 index 0000000000..ff442ba5d2 --- /dev/null +++ b/crates/starknet_committer/src/patricia_merkle_tree.rs @@ -0,0 +1,5 @@ +pub mod leaf; +pub mod tree; +pub mod types; +#[cfg(test)] +pub mod types_test; diff --git a/crates/starknet_committer/src/patricia_merkle_tree/leaf.rs b/crates/starknet_committer/src/patricia_merkle_tree/leaf.rs new file mode 100644 index 0000000000..f6cc127b54 --- /dev/null +++ b/crates/starknet_committer/src/patricia_merkle_tree/leaf.rs @@ -0,0 +1,4 @@ +pub mod leaf_impl; +pub mod leaf_serde; +#[cfg(test)] +pub mod leaf_serde_test; diff --git a/crates/starknet_committer/src/patricia_merkle_tree/leaf/leaf_impl.rs b/crates/starknet_committer/src/patricia_merkle_tree/leaf/leaf_impl.rs new file mode 100644 index 0000000000..f428d20544 --- /dev/null +++ b/crates/starknet_committer/src/patricia_merkle_tree/leaf/leaf_impl.rs @@ -0,0 +1,58 @@ +use std::sync::Arc; + +use committer::felt::Felt; +use committer::hash::hash_trait::HashOutput; +use committer::patricia_merkle_tree::node_data::errors::LeafResult; +use committer::patricia_merkle_tree::node_data::leaf::{Leaf, LeafModifications}; +use committer::patricia_merkle_tree::types::NodeIndex; + +use crate::block_committer::input::StarknetStorageValue; +use crate::patricia_merkle_tree::types::{ClassHash, CompiledClassHash, Nonce}; + +#[derive(Clone, Debug, Default, Eq, PartialEq)] +pub struct ContractState { + pub nonce: Nonce, + pub storage_root_hash: HashOutput, + pub class_hash: ClassHash, +} + +impl Leaf for StarknetStorageValue { + fn is_empty(&self) -> bool { + self.0 == Felt::ZERO + } + + async fn create( + index: &NodeIndex, + leaf_modifications: Arc>, + ) -> LeafResult { + Self::from_modifications(index, leaf_modifications) + } +} + +impl Leaf for CompiledClassHash { + fn is_empty(&self) -> bool { + self.0 == Felt::ZERO + } + + async fn create( + index: &NodeIndex, + leaf_modifications: Arc>, + ) -> LeafResult { + Self::from_modifications(index, leaf_modifications) + } +} + +impl Leaf for ContractState { + fn is_empty(&self) -> bool { + self.nonce.0 == Felt::ZERO + && self.class_hash.0 == Felt::ZERO + && self.storage_root_hash.0 == Felt::ZERO + } + + async fn create( + index: &NodeIndex, + leaf_modifications: Arc>, + ) -> LeafResult { + Self::from_modifications(index, leaf_modifications) + } +} diff --git a/crates/committer/src/patricia_merkle_tree/node_data/leaf_serde.rs b/crates/starknet_committer/src/patricia_merkle_tree/leaf/leaf_serde.rs similarity index 87% rename from crates/committer/src/patricia_merkle_tree/node_data/leaf_serde.rs rename to crates/starknet_committer/src/patricia_merkle_tree/leaf/leaf_serde.rs index 654a3a8944..9f7a711872 100644 --- a/crates/committer/src/patricia_merkle_tree/node_data/leaf_serde.rs +++ b/crates/starknet_committer/src/patricia_merkle_tree/leaf/leaf_serde.rs @@ -1,20 +1,16 @@ use std::collections::HashMap; +use committer::felt::Felt; +use committer::hash::hash_trait::HashOutput; +use committer::patricia_merkle_tree::types::SubTreeHeight; +use committer::storage::db_object::{DBObject, Deserializable}; +use committer::storage::errors::DeserializationError; +use committer::storage::storage_trait::{StarknetPrefix, StorageValue}; use serde_json::Value; use crate::block_committer::input::StarknetStorageValue; -use crate::felt::Felt; -use crate::hash::hash_trait::HashOutput; -use crate::patricia_merkle_tree::filled_tree::node::{ClassHash, CompiledClassHash, Nonce}; -use crate::patricia_merkle_tree::node_data::leaf::ContractState; -use crate::patricia_merkle_tree::types::SubTreeHeight; -use crate::storage::db_object::{DBObject, Deserializable}; -use crate::storage::errors::DeserializationError; -use crate::storage::storage_trait::{StarknetPrefix, StorageValue}; - -#[cfg(test)] -#[path = "leaf_serde_test.rs"] -pub mod leaf_serde_test; +use crate::patricia_merkle_tree::leaf::leaf_impl::ContractState; +use crate::patricia_merkle_tree::types::{ClassHash, CompiledClassHash, Nonce}; impl DBObject for StarknetStorageValue { /// Serializes the value into a 32-byte vector. diff --git a/crates/committer/src/patricia_merkle_tree/node_data/leaf_serde_test.rs b/crates/starknet_committer/src/patricia_merkle_tree/leaf/leaf_serde_test.rs similarity index 84% rename from crates/committer/src/patricia_merkle_tree/node_data/leaf_serde_test.rs rename to crates/starknet_committer/src/patricia_merkle_tree/leaf/leaf_serde_test.rs index 446bc0aa0e..491c691dbc 100644 --- a/crates/committer/src/patricia_merkle_tree/node_data/leaf_serde_test.rs +++ b/crates/starknet_committer/src/patricia_merkle_tree/leaf/leaf_serde_test.rs @@ -1,12 +1,13 @@ use std::fmt::Debug; +use committer::felt::Felt; +use committer::hash::hash_trait::HashOutput; +use committer::patricia_merkle_tree::node_data::leaf::Leaf; use rstest::rstest; use crate::block_committer::input::StarknetStorageValue; -use crate::felt::Felt; -use crate::hash::hash_trait::HashOutput; -use crate::patricia_merkle_tree::filled_tree::node::{ClassHash, CompiledClassHash, Nonce}; -use crate::patricia_merkle_tree::node_data::leaf::{ContractState, Leaf}; +use crate::patricia_merkle_tree::leaf::leaf_impl::ContractState; +use crate::patricia_merkle_tree::types::{ClassHash, CompiledClassHash, Nonce}; #[rstest] #[case::zero_storage_leaf(StarknetStorageValue(Felt::ZERO))] diff --git a/crates/starknet_committer/src/patricia_merkle_tree/tree.rs b/crates/starknet_committer/src/patricia_merkle_tree/tree.rs new file mode 100644 index 0000000000..ce45569f53 --- /dev/null +++ b/crates/starknet_committer/src/patricia_merkle_tree/tree.rs @@ -0,0 +1,35 @@ +use committer::generate_trie_config; +use committer::patricia_merkle_tree::original_skeleton_tree::config::OriginalSkeletonTreeConfig; +use committer::patricia_merkle_tree::original_skeleton_tree::errors::OriginalSkeletonTreeError; +use committer::patricia_merkle_tree::original_skeleton_tree::tree::OriginalSkeletonTreeResult; +use committer::patricia_merkle_tree::types::NodeIndex; + +use crate::block_committer::input::StarknetStorageValue; +use crate::patricia_merkle_tree::leaf::leaf_impl::ContractState; +use crate::patricia_merkle_tree::types::CompiledClassHash; + +generate_trie_config!(OriginalSkeletonStorageTrieConfig, StarknetStorageValue); + +generate_trie_config!(OriginalSkeletonClassesTrieConfig, CompiledClassHash); + +pub(crate) struct OriginalSkeletonContractsTrieConfig; + +impl OriginalSkeletonTreeConfig for OriginalSkeletonContractsTrieConfig { + fn compare_modified_leaves(&self) -> bool { + false + } + + fn compare_leaf( + &self, + _index: &NodeIndex, + _previous_leaf: &ContractState, + ) -> OriginalSkeletonTreeResult { + Ok(false) + } +} + +impl OriginalSkeletonContractsTrieConfig { + pub(crate) fn new() -> Self { + Self + } +} diff --git a/crates/starknet_committer/src/patricia_merkle_tree/types.rs b/crates/starknet_committer/src/patricia_merkle_tree/types.rs new file mode 100644 index 0000000000..0b0a1c0c7f --- /dev/null +++ b/crates/starknet_committer/src/patricia_merkle_tree/types.rs @@ -0,0 +1,41 @@ +use std::collections::HashMap; + +use committer::felt::Felt; +use committer::impl_from_hex_for_felt_wrapper; +use committer::patricia_merkle_tree::filled_tree::errors::FilledTreeError; +use committer::patricia_merkle_tree::filled_tree::tree::FilledTreeImpl; +use committer::patricia_merkle_tree::types::NodeIndex; +use starknet_types_core::felt::FromStrError; + +use crate::block_committer::input::{ContractAddress, StarknetStorageValue}; +use crate::patricia_merkle_tree::leaf::leaf_impl::ContractState; + +// TODO(Nimrod, 1/6/2024): Use the ClassHash defined in starknet-types-core when available. +#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Hash)] +pub struct ClassHash(pub Felt); + +impl From<&ClassHash> for NodeIndex { + fn from(val: &ClassHash) -> Self { + NodeIndex::from_leaf_felt(&val.0) + } +} + +impl_from_hex_for_felt_wrapper!(ClassHash); +#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Hash)] +pub struct Nonce(pub Felt); + +impl_from_hex_for_felt_wrapper!(Nonce); + +#[derive(Clone, Copy, Debug, Default, Eq, PartialEq)] +pub struct CompiledClassHash(pub Felt); + +impl_from_hex_for_felt_wrapper!(CompiledClassHash); + +pub type StorageTrie = FilledTreeImpl; +pub type ClassesTrie = FilledTreeImpl; +pub type ContractsTrie = FilledTreeImpl; +pub type StorageTrieMap = HashMap; + +pub type StorageTrieError = FilledTreeError; +pub type ClassesTrieError = FilledTreeError; +pub type ContractsTrieError = FilledTreeError; diff --git a/crates/starknet_committer/src/patricia_merkle_tree/types_test.rs b/crates/starknet_committer/src/patricia_merkle_tree/types_test.rs new file mode 100644 index 0000000000..1d6a2a0fb6 --- /dev/null +++ b/crates/starknet_committer/src/patricia_merkle_tree/types_test.rs @@ -0,0 +1,19 @@ +use committer::felt::Felt; +use committer::patricia_merkle_tree::types::NodeIndex; +use rstest::rstest; + +use crate::block_committer::input::{ContractAddress, StarknetStorageKey}; + +#[rstest] +fn test_cast_to_node_index( + #[values(0, 15, 0xDEADBEEF)] leaf_index: u128, + #[values(true, false)] bool_from_contract_address: bool, +) { + let expected_node_index = NodeIndex::FIRST_LEAF + leaf_index; + let actual: NodeIndex = if bool_from_contract_address { + (&ContractAddress(Felt::from(leaf_index))).into() + } else { + (&StarknetStorageKey(Felt::from(leaf_index))).into() + }; + assert_eq!(actual, expected_node_index); +}