From 72f6809d4b6172d4f5511e94a1dbef64d02fc7ee Mon Sep 17 00:00:00 2001 From: Ariel Elperin Date: Mon, 1 Jun 2026 11:17:53 +0300 Subject: [PATCH] starknet_committer: define fetch_contract_storage_paths_concurrently --- .../src/db/trie_traversal.rs | 124 +++++++++++++++++- .../src/patricia_merkle_tree/tree.rs | 17 +-- 2 files changed, 126 insertions(+), 15 deletions(-) diff --git a/crates/starknet_committer/src/db/trie_traversal.rs b/crates/starknet_committer/src/db/trie_traversal.rs index 63828030ab7..3443e12590c 100644 --- a/crates/starknet_committer/src/db/trie_traversal.rs +++ b/crates/starknet_committer/src/db/trie_traversal.rs @@ -45,6 +45,7 @@ use tracing::warn; use crate::block_committer::input::{ contract_address_into_node_index, + try_node_index_into_contract_address, ReaderConfig, StarknetStorageValue, }; @@ -851,7 +852,6 @@ where } /// Storage task for fetching Patricia paths in a single storage trie. -#[expect(dead_code)] struct StoragePathsReadTask<'indices, Layout: NodeLayoutFor> { address: ContractAddress, storage_root_hash: HashOutput, @@ -925,6 +925,128 @@ where storage.gather(tasks).await.into_iter().collect() } +/// Fetches Patricia proofs for the storage tries. If the storage has a [GatherableStorage] version, +/// then the paths are fetched concurrently. Otherwise, they are fetched sequentially. +#[allow(dead_code)] +pub(crate) async fn fetch_contract_storage_paths( + storage: &mut impl ReadOnlyStorage, + contract_storage_sorted_leaf_indices: &HashMap>, + contract_leaves: &HashMap, +) -> TraversalResult> +where + StorageLayout: NodeLayoutFor + Send + 'static, + >::DbLeaf: + HasStaticPrefix, + ContractLeaf: AsRef, +{ + if let Some(gatherable_storage) = storage.as_gatherable_storage() { + return fetch_contract_storage_paths_concurrently::<_, StorageLayout, ContractLeaf>( + gatherable_storage, + contract_storage_sorted_leaf_indices, + contract_leaves, + ) + .await; + } + fetch_contract_storage_paths_sequentially::( + storage, + contract_storage_sorted_leaf_indices, + contract_leaves, + ) + .await +} + +/// Returns the contract address and storage root hash for the given leaf index, if the contract +/// exists in the contracts trie. +/// +/// The contract address might not exist in the contracts trie in the following cases: +/// 1. We are looking at the previous tree and the contract is new. +/// 2. We are looking at the new tree and the contract is deleted (revert). +/// +/// In either case, the storage trie of this contract is empty, so there is nothing to +/// prove regarding the contract storage. +pub(crate) fn get_address_and_storage_root>( + idx: &NodeIndex, + contract_leaves: &HashMap, +) -> Option<(ContractAddress, HashOutput)> { + let contract_address = try_node_index_into_contract_address(idx).unwrap_or_else(|_| { + panic!( + "Converting leaf NodeIndex to ContractAddress should succeed; failed to convert \ + {idx:?}." + ) + }); + let storage_root_hash = contract_leaves.get(idx).map(|leaf| leaf.as_ref().storage_root_hash)?; + Some((contract_address, storage_root_hash)) +} + +/// Sequentially fetches Patricia proofs for the storage tries. +#[allow(dead_code)] +async fn fetch_contract_storage_paths_sequentially( + storage: &mut impl ReadOnlyStorage, + contract_storage_sorted_leaf_indices: &HashMap>, + contract_leaves: &HashMap, +) -> TraversalResult> +where + StorageLayout: NodeLayoutFor + Send + 'static, + >::DbLeaf: + HasStaticPrefix, + ContractLeaf: AsRef, +{ + let mut contracts_trie_storage_proofs = + HashMap::with_capacity(contract_storage_sorted_leaf_indices.len()); + + for (idx, sorted_leaf_indices) in contract_storage_sorted_leaf_indices { + let Some((contract_address, storage_root_hash)) = + get_address_and_storage_root(idx, contract_leaves) + else { + continue; + }; + + let leaves = None; + let proof = fetch_patricia_paths::( + storage, + storage_root_hash, + *sorted_leaf_indices, + leaves, + &contract_address, + ) + .await?; + contracts_trie_storage_proofs.insert(contract_address, proof); + } + + Ok(contracts_trie_storage_proofs) +} + +/// Concurrently fetches Patricia proofs for the storage tries. +#[allow(dead_code)] +async fn fetch_contract_storage_paths_concurrently( + storage: &mut S, + contract_storage_sorted_leaf_indices: &HashMap>, + contract_leaves: &HashMap, +) -> TraversalResult> +where + S: GatherableStorage, + StorageLayout: NodeLayoutFor + Send + 'static, + >::DbLeaf: + HasStaticPrefix, + ContractLeaf: AsRef, +{ + let mut tasks = Vec::new(); + for (idx, sorted_leaf_indices) in contract_storage_sorted_leaf_indices { + let Some((contract_address, storage_root_hash)) = + get_address_and_storage_root(idx, contract_leaves) + else { + continue; + }; + tasks.push(StoragePathsReadTask:: { + address: contract_address, + storage_root_hash, + sorted_leaf_indices: *sorted_leaf_indices, + _layout: PhantomData, + }); + } + storage.gather(tasks).await.into_iter().collect() +} + /// Helper function to create a storage trie for a single contract. async fn create_storage_trie<'a, Layout: NodeLayoutFor>( storage: &mut impl ReadOnlyStorage, diff --git a/crates/starknet_committer/src/patricia_merkle_tree/tree.rs b/crates/starknet_committer/src/patricia_merkle_tree/tree.rs index 838a32c2fbe..b8370e1f026 100644 --- a/crates/starknet_committer/src/patricia_merkle_tree/tree.rs +++ b/crates/starknet_committer/src/patricia_merkle_tree/tree.rs @@ -17,7 +17,7 @@ use crate::block_committer::input::{ }; use crate::db::db_layout::DbLayout; use crate::db::facts_db::FactsNodeLayout; -use crate::db::trie_traversal::fetch_patricia_paths; +use crate::db::trie_traversal::{fetch_patricia_paths, get_address_and_storage_root}; use crate::patricia_merkle_tree::leaf::leaf_impl::ContractState; use crate::patricia_merkle_tree::types::{ class_hash_into_node_index, @@ -181,19 +181,8 @@ where HashMap::with_capacity(contract_storage_sorted_leaf_indices.len()); for (idx, sorted_leaf_indices) in contract_storage_sorted_leaf_indices { - let contract_address = try_node_index_into_contract_address(idx).unwrap_or_else(|_| { - panic!( - "Converting leaf NodeIndex to ContractAddress should succeed; failed to convert \ - {idx:?}." - ) - }); - - // The contract address might not exist in the contracts trie in the following cases: - // 1. We are looking at the previous tree and the contract is new. - // 2. We are looking at the new tree and the contract is deleted (revert). - // In either case, the storage trie of this contract is empty, so there is nothing to - // prove regarding the contract storage. - let Some(storage_root_hash) = leaves.get(idx).map(|leaf| leaf.as_ref().storage_root_hash) + let Some((contract_address, storage_root_hash)) = + get_address_and_storage_root(idx, &leaves) else { continue; };