@@ -45,6 +45,7 @@ use tracing::warn;
4545
4646use crate :: block_committer:: input:: {
4747 contract_address_into_node_index,
48+ try_node_index_into_contract_address,
4849 ReaderConfig ,
4950 StarknetStorageValue ,
5051} ;
@@ -924,6 +925,120 @@ where
924925 storage. gather ( tasks) . await . into_iter ( ) . collect ( )
925926}
926927
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+ pub ( crate ) async fn fetch_contract_storage_paths < StorageLayout , ContractLeaf > (
931+ storage : & mut impl ReadOnlyStorage ,
932+ contract_storage_sorted_leaf_indices : & HashMap < NodeIndex , SortedLeafIndices < ' _ > > ,
933+ contract_leaves : & HashMap < NodeIndex , ContractLeaf > ,
934+ ) -> TraversalResult < HashMap < ContractAddress , PreimageMap > >
935+ where
936+ StorageLayout : NodeLayoutFor < StarknetStorageValue > + Send + ' static ,
937+ <StorageLayout as NodeLayoutFor < StarknetStorageValue > >:: DbLeaf :
938+ HasStaticPrefix < KeyContext = ContractAddress > ,
939+ ContractLeaf : AsRef < ContractState > ,
940+ {
941+ if let Some ( gatherable_storage) = storage. as_gatherable_storage ( ) {
942+ return fetch_contract_storage_paths_concurrently :: < _ , StorageLayout , ContractLeaf > (
943+ gatherable_storage,
944+ contract_storage_sorted_leaf_indices,
945+ contract_leaves,
946+ )
947+ . await ;
948+ }
949+ fetch_contract_storage_paths_sequentially :: < StorageLayout , ContractLeaf > (
950+ storage,
951+ contract_storage_sorted_leaf_indices,
952+ contract_leaves,
953+ )
954+ . await
955+ }
956+
957+ /// Sequentially fetches Patricia proofs for the storage tries.
958+ async fn fetch_contract_storage_paths_sequentially < StorageLayout , ContractLeaf > (
959+ storage : & mut impl ReadOnlyStorage ,
960+ contract_storage_sorted_leaf_indices : & HashMap < NodeIndex , SortedLeafIndices < ' _ > > ,
961+ contract_leaves : & HashMap < NodeIndex , ContractLeaf > ,
962+ ) -> TraversalResult < HashMap < ContractAddress , PreimageMap > >
963+ where
964+ StorageLayout : NodeLayoutFor < StarknetStorageValue > + Send + ' static ,
965+ <StorageLayout as NodeLayoutFor < StarknetStorageValue > >:: DbLeaf :
966+ HasStaticPrefix < KeyContext = ContractAddress > ,
967+ ContractLeaf : AsRef < ContractState > ,
968+ {
969+ let mut contracts_trie_storage_proofs =
970+ HashMap :: with_capacity ( contract_storage_sorted_leaf_indices. len ( ) ) ;
971+
972+ for ( idx, sorted_leaf_indices) in contract_storage_sorted_leaf_indices {
973+ let contract_address = try_node_index_into_contract_address ( idx) . unwrap_or_else ( |_| {
974+ panic ! (
975+ "Converting leaf NodeIndex to ContractAddress should succeed; failed to convert \
976+ {idx:?}."
977+ )
978+ } ) ;
979+
980+ // The contract address might not exist in the contracts trie in the following cases:
981+ // 1. We are looking at the previous tree and the contract is new.
982+ // 2. We are looking at the new tree and the contract is deleted (revert).
983+ // In either case, the storage trie of this contract is empty, so there is nothing to
984+ // prove regarding the contract storage.
985+ let Some ( storage_root_hash) =
986+ contract_leaves. get ( idx) . map ( |leaf| leaf. as_ref ( ) . storage_root_hash )
987+ else {
988+ continue ;
989+ } ;
990+
991+ let leaves = None ;
992+ let proof = fetch_patricia_paths :: < StorageLayout :: DbLeaf , StorageLayout > (
993+ storage,
994+ storage_root_hash,
995+ * sorted_leaf_indices,
996+ leaves,
997+ & contract_address,
998+ )
999+ . await ?;
1000+ contracts_trie_storage_proofs. insert ( contract_address, proof) ;
1001+ }
1002+
1003+ Ok ( contracts_trie_storage_proofs)
1004+ }
1005+
1006+ /// Concurrently fetches Patricia proofs for the storage tries.
1007+ async fn fetch_contract_storage_paths_concurrently < S , StorageLayout , ContractLeaf > (
1008+ storage : & mut S ,
1009+ contract_storage_sorted_leaf_indices : & HashMap < NodeIndex , SortedLeafIndices < ' _ > > ,
1010+ contract_leaves : & HashMap < NodeIndex , ContractLeaf > ,
1011+ ) -> TraversalResult < HashMap < ContractAddress , PreimageMap > >
1012+ where
1013+ S : GatherableStorage ,
1014+ StorageLayout : NodeLayoutFor < StarknetStorageValue > + Send + ' static ,
1015+ <StorageLayout as NodeLayoutFor < StarknetStorageValue > >:: DbLeaf :
1016+ HasStaticPrefix < KeyContext = ContractAddress > ,
1017+ ContractLeaf : AsRef < ContractState > ,
1018+ {
1019+ let mut tasks = Vec :: new ( ) ;
1020+ for ( idx, sorted_leaf_indices) in contract_storage_sorted_leaf_indices {
1021+ let contract_address = try_node_index_into_contract_address ( idx) . unwrap_or_else ( |_| {
1022+ panic ! (
1023+ "Converting leaf NodeIndex to ContractAddress should succeed; failed to convert \
1024+ {idx:?}."
1025+ )
1026+ } ) ;
1027+ let Some ( storage_root_hash) =
1028+ contract_leaves. get ( idx) . map ( |leaf| leaf. as_ref ( ) . storage_root_hash )
1029+ else {
1030+ continue ;
1031+ } ;
1032+ tasks. push ( StoragePathsReadTask :: < StorageLayout > {
1033+ address : contract_address,
1034+ storage_root_hash,
1035+ sorted_leaf_indices : * sorted_leaf_indices,
1036+ _layout : PhantomData ,
1037+ } ) ;
1038+ }
1039+ storage. gather ( tasks) . await . into_iter ( ) . collect ( )
1040+ }
1041+
9271042/// Helper function to create a storage trie for a single contract.
9281043async fn create_storage_trie < ' a , Layout : NodeLayoutFor < StarknetStorageValue > > (
9291044 storage : & mut impl ReadOnlyStorage ,
0 commit comments