Skip to content

Commit 3cbe5fb

Browse files
committed
starknet_committer: define fetch_contract_storage_paths_concurrently
1 parent e0b7076 commit 3cbe5fb

2 files changed

Lines changed: 125 additions & 15 deletions

File tree

crates/starknet_committer/src/db/trie_traversal.rs

Lines changed: 122 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,127 @@ 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+
/// In either case, the storage trie of this contract is empty, so there is nothing to
965+
/// prove regarding the contract storage.
966+
pub(crate) fn get_address_and_storage_root<ContractLeaf: AsRef<ContractState>>(
967+
idx: &NodeIndex,
968+
contract_leaves: &HashMap<NodeIndex, ContractLeaf>,
969+
) -> Option<(ContractAddress, HashOutput)> {
970+
let contract_address = try_node_index_into_contract_address(idx).unwrap_or_else(|_| {
971+
panic!(
972+
"Converting leaf NodeIndex to ContractAddress should succeed; failed to convert \
973+
{idx:?}."
974+
)
975+
});
976+
let storage_root_hash = contract_leaves.get(idx).map(|leaf| leaf.as_ref().storage_root_hash)?;
977+
Some((contract_address, storage_root_hash))
978+
}
979+
980+
/// Sequentially fetches Patricia proofs for the storage tries.
981+
#[allow(dead_code)]
982+
async fn fetch_contract_storage_paths_sequentially<StorageLayout, ContractLeaf>(
983+
storage: &mut impl ReadOnlyStorage,
984+
contract_storage_sorted_leaf_indices: &HashMap<NodeIndex, SortedLeafIndices<'_>>,
985+
contract_leaves: &HashMap<NodeIndex, ContractLeaf>,
986+
) -> TraversalResult<HashMap<ContractAddress, PreimageMap>>
987+
where
988+
StorageLayout: NodeLayoutFor<StarknetStorageValue> + Send + 'static,
989+
<StorageLayout as NodeLayoutFor<StarknetStorageValue>>::DbLeaf:
990+
HasStaticPrefix<KeyContext = ContractAddress>,
991+
ContractLeaf: AsRef<ContractState>,
992+
{
993+
let mut contracts_trie_storage_proofs =
994+
HashMap::with_capacity(contract_storage_sorted_leaf_indices.len());
995+
996+
for (idx, sorted_leaf_indices) in contract_storage_sorted_leaf_indices {
997+
let Some((contract_address, storage_root_hash)) =
998+
get_address_and_storage_root(idx, contract_leaves)
999+
else {
1000+
continue;
1001+
};
1002+
1003+
let leaves = None;
1004+
let proof = fetch_patricia_paths::<StorageLayout::DbLeaf, StorageLayout>(
1005+
storage,
1006+
storage_root_hash,
1007+
*sorted_leaf_indices,
1008+
leaves,
1009+
&contract_address,
1010+
)
1011+
.await?;
1012+
contracts_trie_storage_proofs.insert(contract_address, proof);
1013+
}
1014+
1015+
Ok(contracts_trie_storage_proofs)
1016+
}
1017+
1018+
/// Concurrently fetches Patricia proofs for the storage tries.
1019+
#[allow(dead_code)]
1020+
async fn fetch_contract_storage_paths_concurrently<S, StorageLayout, ContractLeaf>(
1021+
storage: &mut S,
1022+
contract_storage_sorted_leaf_indices: &HashMap<NodeIndex, SortedLeafIndices<'_>>,
1023+
contract_leaves: &HashMap<NodeIndex, ContractLeaf>,
1024+
) -> TraversalResult<HashMap<ContractAddress, PreimageMap>>
1025+
where
1026+
S: GatherableStorage,
1027+
StorageLayout: NodeLayoutFor<StarknetStorageValue> + Send + 'static,
1028+
<StorageLayout as NodeLayoutFor<StarknetStorageValue>>::DbLeaf:
1029+
HasStaticPrefix<KeyContext = ContractAddress>,
1030+
ContractLeaf: AsRef<ContractState>,
1031+
{
1032+
let mut tasks = Vec::new();
1033+
for (idx, sorted_leaf_indices) in contract_storage_sorted_leaf_indices {
1034+
let Some((contract_address, storage_root_hash)) =
1035+
get_address_and_storage_root(idx, contract_leaves)
1036+
else {
1037+
continue;
1038+
};
1039+
tasks.push(StoragePathsReadTask::<StorageLayout> {
1040+
address: contract_address,
1041+
storage_root_hash,
1042+
sorted_leaf_indices: *sorted_leaf_indices,
1043+
_layout: PhantomData,
1044+
});
1045+
}
1046+
storage.gather(tasks).await.into_iter().collect()
1047+
}
1048+
9281049
/// Helper function to create a storage trie for a single contract.
9291050
async fn create_storage_trie<'a, Layout: NodeLayoutFor<StarknetStorageValue>>(
9301051
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)