diff --git a/Cargo.lock b/Cargo.lock index 1f6bd33c..79e6cf0d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -135,6 +135,7 @@ version = "0.1.0-rc.0" dependencies = [ "derive_more", "pretty_assertions", + "rayon", "rstest", "starknet-types-core", ] @@ -162,6 +163,31 @@ dependencies = [ "libc", ] +[[package]] +name = "crossbeam-deque" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "613f8cc01fe9cf1a3eb3d7f488fd2fa8388403e97039e2f73692932e291a770d" +dependencies = [ + "crossbeam-epoch", + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-epoch" +version = "0.9.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e" +dependencies = [ + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-utils" +version = "0.8.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "248e3bacc7dc6baa3b21e405ee045c3047101a49145e7e9eca583ab4c2ca5345" + [[package]] name = "crypto-common" version = "0.1.6" @@ -201,6 +227,12 @@ dependencies = [ "crypto-common", ] +[[package]] +name = "either" +version = "1.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "11157ac094ffbdde99aa67b23417ebdd801842852b500e395a45a9c0aac03e4a" + [[package]] name = "funty" version = "2.0.0" @@ -451,6 +483,26 @@ version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dc33ff2d4973d518d823d61aa239014831e521c75da58e3df4840d3f47749d09" +[[package]] +name = "rayon" +version = "1.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b418a60154510ca1a002a752ca9714984e21e4241e804d32555251faf8b78ffa" +dependencies = [ + "either", + "rayon-core", +] + +[[package]] +name = "rayon-core" +version = "1.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1465873a3dfdaa8ae7cb14b4383657caab0b3e8a0aa9ae8e04b044854c8dfce2" +dependencies = [ + "crossbeam-deque", + "crossbeam-utils", +] + [[package]] name = "rstest" version = "0.17.0" diff --git a/Cargo.toml b/Cargo.toml index 172cfd78..f2a1505f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -16,6 +16,7 @@ license-file = "LICENSE" clap = { version = "4.5.4", features = ["cargo", "derive"] } derive_more = "0.99.17" pretty_assertions = "1.2.1" +rayon = "1.10.0" rstest = "0.17.0" starknet-types-core = { version = "0.0.11", features = ["hash"] } diff --git a/crates/committer/Cargo.toml b/crates/committer/Cargo.toml index 4e0faa63..2b012ab8 100644 --- a/crates/committer/Cargo.toml +++ b/crates/committer/Cargo.toml @@ -15,4 +15,6 @@ rstest.workspace = true [dependencies] derive_more.workspace = true +rayon.workspace = true starknet-types-core.workspace = true + diff --git a/crates/committer/src/hash/hash_trait.rs b/crates/committer/src/hash/hash_trait.rs index 3b65ebcf..250a87ba 100644 --- a/crates/committer/src/hash/hash_trait.rs +++ b/crates/committer/src/hash/hash_trait.rs @@ -2,7 +2,7 @@ use crate::types::Felt; pub(crate) struct HashInputPair(pub Felt, pub Felt); -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] +#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Hash)] pub(crate) struct HashOutput(pub Felt); #[allow(dead_code)] diff --git a/crates/committer/src/patricia_merkle_tree/errors.rs b/crates/committer/src/patricia_merkle_tree/errors.rs index 63e3ccd3..c5045bac 100644 --- a/crates/committer/src/patricia_merkle_tree/errors.rs +++ b/crates/committer/src/patricia_merkle_tree/errors.rs @@ -3,8 +3,11 @@ pub(crate) enum OriginalSkeletonTreeError {} #[derive(Debug)] +#[allow(dead_code)] pub(crate) enum UpdatedSkeletonTreeError { MissingNode, + PoisonedLock(String), + NonDroppedPointer(String), } #[derive(Debug)] 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 6f997f6d..ba4f6b4e 100644 --- a/crates/committer/src/patricia_merkle_tree/updated_skeleton_tree.rs +++ b/crates/committer/src/patricia_merkle_tree/updated_skeleton_tree.rs @@ -1,5 +1,5 @@ use std::collections::HashMap; -use std::sync::Mutex; +use std::sync::{Arc, Mutex, RwLock}; use crate::hash::hash_trait::{HashFunction, HashOutput}; use crate::patricia_merkle_tree::errors::UpdatedSkeletonTreeError; @@ -31,7 +31,10 @@ struct UpdatedSkeletonTreeImpl { skeleton_tree: HashMap>, } -impl UpdatedSkeletonTreeImpl { +#[allow(dead_code)] +impl + UpdatedSkeletonTreeImpl +{ fn get_node( &self, index: NodeIndex, @@ -45,7 +48,7 @@ impl UpdatedSkeletonTreeImpl { fn compute_filled_tree_rec>( &self, index: NodeIndex, - output_map: &mut HashMap>>, + output_map: Arc>>>>, ) -> Result { let node = self.get_node(index)?; match node { @@ -53,15 +56,33 @@ impl UpdatedSkeletonTreeImpl { let left_index = NodeIndex(index.0 * Felt::TWO); let right_index = NodeIndex(left_index.0 + Felt::ONE); - let left_hash = self.compute_filled_tree_rec::(left_index, output_map)?; - let right_hash = self.compute_filled_tree_rec::(right_index, output_map)?; + let mut left_hash = Ok(Default::default()); + let mut right_hash = Ok(Default::default()); + + rayon::join( + || { + left_hash = self + .compute_filled_tree_rec::(left_index, Arc::clone(&output_map)); + }, + || { + right_hash = self + .compute_filled_tree_rec::(right_index, Arc::clone(&output_map)); + }, + ); + + let left_hash = left_hash?; + let right_hash = right_hash?; let data = NodeData::Binary(BinaryData { left_hash, right_hash, }); let hash_value = TH::compute_node_hash(&data); - output_map.insert( + // TODO (Aner, 15/4/21): Change to use interior mutability. + let mut write_locked_map = output_map.write().map_err(|_| { + UpdatedSkeletonTreeError::PoisonedLock("Cannot write to output map.".to_owned()) + })?; + write_locked_map.insert( index, Mutex::new(FilledNode { hash: hash_value, @@ -72,14 +93,18 @@ impl UpdatedSkeletonTreeImpl { } UpdatedSkeletonNode::Edge { path_to_bottom } => { let bottom_node_index = NodeIndex::compute_bottom_index(index, *path_to_bottom); - let bottom_hash = - self.compute_filled_tree_rec::(bottom_node_index, output_map)?; + let bottom_hash = self + .compute_filled_tree_rec::(bottom_node_index, Arc::clone(&output_map))?; let data = NodeData::Edge(EdgeData { path_to_bottom: *path_to_bottom, bottom_hash, }); let hash_value = TH::compute_node_hash(&data); - output_map.insert( + // TODO (Aner, 15/4/21): Change to use interior mutability. + let mut write_locked_map = output_map.write().map_err(|_| { + UpdatedSkeletonTreeError::PoisonedLock("Cannot write to output map.".to_owned()) + })?; + write_locked_map.insert( index, Mutex::new(FilledNode { hash: hash_value, @@ -91,7 +116,11 @@ impl UpdatedSkeletonTreeImpl { UpdatedSkeletonNode::Sibling(hash_result) => Ok(*hash_result), UpdatedSkeletonNode::Leaf(node_data) => { let hash_value = TH::compute_node_hash(&NodeData::Leaf(node_data.clone())); - output_map.insert( + // TODO (Aner, 15/4/21): Change to use interior mutability. + let mut write_locked_map = output_map.write().map_err(|_| { + UpdatedSkeletonTreeError::PoisonedLock("Cannot write to output map.".to_owned()) + })?; + write_locked_map.insert( index, Mutex::new(FilledNode { hash: hash_value, @@ -104,15 +133,34 @@ impl UpdatedSkeletonTreeImpl { } } -impl UpdatedSkeletonTree for UpdatedSkeletonTreeImpl { +impl + UpdatedSkeletonTree for UpdatedSkeletonTreeImpl +{ fn compute_filled_tree>( &self, ) -> Result, UpdatedSkeletonTreeError> { // 1. Create a new hashmap for the filled tree. - let mut filled_tree_map = HashMap::new(); + // TODO (Aner, 15/4/21): Change to use interior mutability. + let filled_tree_map = Arc::new(RwLock::new(HashMap::new())); // 2. Compute the filled tree hashmap from the skeleton_tree. - self.compute_filled_tree_rec::(NodeIndex::root_index(), &mut filled_tree_map)?; - // 3. Create a new FilledTreeImpl from the hashmap. - Ok(FilledTreeImpl::new(filled_tree_map)) + self.compute_filled_tree_rec::( + NodeIndex::root_index(), + Arc::clone(&filled_tree_map), + )?; + // 3. Create and return a new FilledTreeImpl from the hashmap. + Ok(FilledTreeImpl::new( + Arc::try_unwrap(filled_tree_map) + .map_err(|_| { + UpdatedSkeletonTreeError::NonDroppedPointer( + "Unable to unwrap the arc of the filled_tree_map".to_owned(), + ) + })? + .into_inner() + .map_err(|_| { + UpdatedSkeletonTreeError::PoisonedLock( + "Cannot take filled tree map.".to_owned(), + ) + })?, + )) } }