Skip to content

Commit 72f6809

Browse files
committed
starknet_committer: define fetch_contract_storage_paths_concurrently
1 parent e0b7076 commit 72f6809

2 files changed

Lines changed: 126 additions & 15 deletions

File tree

crates/starknet_committer/src/db/trie_traversal.rs

Lines changed: 123 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ use tracing::warn;
4545

4646
use crate::block_committer::input::{
4747
contract_address_into_node_index,
48+
try_node_index_into_contract_address,
4849
ReaderConfig,
4950
StarknetStorageValue,
5051
};
@@ -851,7 +852,6 @@ where
851852
}
852853

853854
/// Storage task for fetching Patricia paths in a single storage trie.
854-
#[expect(dead_code)]
855855
struct StoragePathsReadTask<'indices, Layout: NodeLayoutFor<StarknetStorageValue>> {
856856
address: ContractAddress,
857857
storage_root_hash: HashOutput,
@@ -925,6 +925,128 @@ where
925925
storage.gather(tasks).await.into_iter().collect()
926926
}
927927

928+
/// Fetches Patricia proofs for the storage tries. If the storage has a [GatherableStorage] version,
929+
/// then the paths are fetched concurrently. Otherwise, they are fetched sequentially.
930+
#[allow(dead_code)]
931+
pub(crate) async fn fetch_contract_storage_paths<StorageLayout, ContractLeaf>(
932+
storage: &mut impl ReadOnlyStorage,
933+
contract_storage_sorted_leaf_indices: &HashMap<NodeIndex, SortedLeafIndices<'_>>,
934+
contract_leaves: &HashMap<NodeIndex, ContractLeaf>,
935+
) -> TraversalResult<HashMap<ContractAddress, PreimageMap>>
936+
where
937+
StorageLayout: NodeLayoutFor<StarknetStorageValue> + Send + 'static,
938+
<StorageLayout as NodeLayoutFor<StarknetStorageValue>>::DbLeaf:
939+
HasStaticPrefix<KeyContext = ContractAddress>,
940+
ContractLeaf: AsRef<ContractState>,
941+
{
942+
if let Some(gatherable_storage) = storage.as_gatherable_storage() {
943+
return fetch_contract_storage_paths_concurrently::<_, StorageLayout, ContractLeaf>(
944+
gatherable_storage,
945+
contract_storage_sorted_leaf_indices,
946+
contract_leaves,
947+
)
948+
.await;
949+
}
950+
fetch_contract_storage_paths_sequentially::<StorageLayout, ContractLeaf>(
951+
storage,
952+
contract_storage_sorted_leaf_indices,
953+
contract_leaves,
954+
)
955+
.await
956+
}
957+
958+
/// Returns the contract address and storage root hash for the given leaf index, if the contract
959+
/// exists in the contracts trie.
960+
///
961+
/// The contract address might not exist in the contracts trie in the following cases:
962+
/// 1. We are looking at the previous tree and the contract is new.
963+
/// 2. We are looking at the new tree and the contract is deleted (revert).
964+
///
965+
/// In either case, the storage trie of this contract is empty, so there is nothing to
966+
/// prove regarding the contract storage.
967+
pub(crate) fn get_address_and_storage_root<ContractLeaf: AsRef<ContractState>>(
968+
idx: &NodeIndex,
969+
contract_leaves: &HashMap<NodeIndex, ContractLeaf>,
970+
) -> Option<(ContractAddress, HashOutput)> {
971+
let contract_address = try_node_index_into_contract_address(idx).unwrap_or_else(|_| {
972+
panic!(
973+
"Converting leaf NodeIndex to ContractAddress should succeed; failed to convert \
974+
{idx:?}."
975+
)
976+
});
977+
let storage_root_hash = contract_leaves.get(idx).map(|leaf| leaf.as_ref().storage_root_hash)?;
978+
Some((contract_address, storage_root_hash))
979+
}
980+
981+
/// Sequentially fetches Patricia proofs for the storage tries.
982+
#[allow(dead_code)]
983+
async fn fetch_contract_storage_paths_sequentially<StorageLayout, ContractLeaf>(
984+
storage: &mut impl ReadOnlyStorage,
985+
contract_storage_sorted_leaf_indices: &HashMap<NodeIndex, SortedLeafIndices<'_>>,
986+
contract_leaves: &HashMap<NodeIndex, ContractLeaf>,
987+
) -> TraversalResult<HashMap<ContractAddress, PreimageMap>>
988+
where
989+
StorageLayout: NodeLayoutFor<StarknetStorageValue> + Send + 'static,
990+
<StorageLayout as NodeLayoutFor<StarknetStorageValue>>::DbLeaf:
991+
HasStaticPrefix<KeyContext = ContractAddress>,
992+
ContractLeaf: AsRef<ContractState>,
993+
{
994+
let mut contracts_trie_storage_proofs =
995+
HashMap::with_capacity(contract_storage_sorted_leaf_indices.len());
996+
997+
for (idx, sorted_leaf_indices) in contract_storage_sorted_leaf_indices {
998+
let Some((contract_address, storage_root_hash)) =
999+
get_address_and_storage_root(idx, contract_leaves)
1000+
else {
1001+
continue;
1002+
};
1003+
1004+
let leaves = None;
1005+
let proof = fetch_patricia_paths::<StorageLayout::DbLeaf, StorageLayout>(
1006+
storage,
1007+
storage_root_hash,
1008+
*sorted_leaf_indices,
1009+
leaves,
1010+
&contract_address,
1011+
)
1012+
.await?;
1013+
contracts_trie_storage_proofs.insert(contract_address, proof);
1014+
}
1015+
1016+
Ok(contracts_trie_storage_proofs)
1017+
}
1018+
1019+
/// Concurrently fetches Patricia proofs for the storage tries.
1020+
#[allow(dead_code)]
1021+
async fn fetch_contract_storage_paths_concurrently<S, StorageLayout, ContractLeaf>(
1022+
storage: &mut S,
1023+
contract_storage_sorted_leaf_indices: &HashMap<NodeIndex, SortedLeafIndices<'_>>,
1024+
contract_leaves: &HashMap<NodeIndex, ContractLeaf>,
1025+
) -> TraversalResult<HashMap<ContractAddress, PreimageMap>>
1026+
where
1027+
S: GatherableStorage,
1028+
StorageLayout: NodeLayoutFor<StarknetStorageValue> + Send + 'static,
1029+
<StorageLayout as NodeLayoutFor<StarknetStorageValue>>::DbLeaf:
1030+
HasStaticPrefix<KeyContext = ContractAddress>,
1031+
ContractLeaf: AsRef<ContractState>,
1032+
{
1033+
let mut tasks = Vec::new();
1034+
for (idx, sorted_leaf_indices) in contract_storage_sorted_leaf_indices {
1035+
let Some((contract_address, storage_root_hash)) =
1036+
get_address_and_storage_root(idx, contract_leaves)
1037+
else {
1038+
continue;
1039+
};
1040+
tasks.push(StoragePathsReadTask::<StorageLayout> {
1041+
address: contract_address,
1042+
storage_root_hash,
1043+
sorted_leaf_indices: *sorted_leaf_indices,
1044+
_layout: PhantomData,
1045+
});
1046+
}
1047+
storage.gather(tasks).await.into_iter().collect()
1048+
}
1049+
9281050
/// Helper function to create a storage trie for a single contract.
9291051
async fn create_storage_trie<'a, Layout: NodeLayoutFor<StarknetStorageValue>>(
9301052
storage: &mut impl ReadOnlyStorage,

crates/starknet_committer/src/patricia_merkle_tree/tree.rs

Lines changed: 3 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ use crate::block_committer::input::{
1717
};
1818
use crate::db::db_layout::DbLayout;
1919
use crate::db::facts_db::FactsNodeLayout;
20-
use crate::db::trie_traversal::fetch_patricia_paths;
20+
use crate::db::trie_traversal::{fetch_patricia_paths, get_address_and_storage_root};
2121
use crate::patricia_merkle_tree::leaf::leaf_impl::ContractState;
2222
use crate::patricia_merkle_tree::types::{
2323
class_hash_into_node_index,
@@ -181,19 +181,8 @@ where
181181
HashMap::with_capacity(contract_storage_sorted_leaf_indices.len());
182182

183183
for (idx, sorted_leaf_indices) in contract_storage_sorted_leaf_indices {
184-
let contract_address = try_node_index_into_contract_address(idx).unwrap_or_else(|_| {
185-
panic!(
186-
"Converting leaf NodeIndex to ContractAddress should succeed; failed to convert \
187-
{idx:?}."
188-
)
189-
});
190-
191-
// The contract address might not exist in the contracts trie in the following cases:
192-
// 1. We are looking at the previous tree and the contract is new.
193-
// 2. We are looking at the new tree and the contract is deleted (revert).
194-
// In either case, the storage trie of this contract is empty, so there is nothing to
195-
// prove regarding the contract storage.
196-
let Some(storage_root_hash) = leaves.get(idx).map(|leaf| leaf.as_ref().storage_root_hash)
184+
let Some((contract_address, storage_root_hash)) =
185+
get_address_and_storage_root(idx, &leaves)
197186
else {
198187
continue;
199188
};

0 commit comments

Comments
 (0)