@@ -24,7 +24,9 @@ use starknet_patricia_storage::db_object::HasStaticPrefix;
2424use starknet_patricia_storage:: storage_trait:: Storage ;
2525use tracing:: warn;
2626
27- use crate :: db:: facts_db:: traversal:: calculate_subtrees_roots;
27+ use crate :: db:: db_layout:: NodeLayout ;
28+ use crate :: db:: facts_db:: db:: FactsNodeLayout ;
29+ use crate :: db:: facts_db:: traversal:: get_roots_from_storage;
2830use crate :: db:: facts_db:: types:: FactsSubTree ;
2931
3032#[ cfg( test) ]
@@ -42,65 +44,85 @@ macro_rules! log_trivial_modification {
4244/// Given a list of subtrees, traverses towards their leaves and fetches all non-empty,
4345/// unmodified nodes. If `compare_modified_leaves` is set, function logs out a warning when
4446/// encountering a trivial modification. Fills the previous leaf values if it is not none.
45- async fn fetch_nodes < ' a , L : Leaf > (
47+ async fn fetch_nodes < ' a , L , Layout , SubTree > (
4648 skeleton_tree : & mut OriginalSkeletonTreeImpl < ' a > ,
47- subtrees : Vec < FactsSubTree < ' a > > ,
49+ subtrees : Vec < SubTree > ,
4850 storage : & mut impl Storage ,
4951 leaf_modifications : & LeafModifications < L > ,
5052 config : & impl OriginalSkeletonTreeConfig < L > ,
5153 mut previous_leaves : Option < & mut HashMap < NodeIndex , L > > ,
5254 key_context : & <L as HasStaticPrefix >:: KeyContext ,
53- ) -> OriginalSkeletonTreeResult < ( ) > {
55+ ) -> OriginalSkeletonTreeResult < ( ) >
56+ where
57+ L : Leaf ,
58+ Layout : NodeLayout < L > ,
59+ SubTree : SubTreeTrait < ' a , NodeData = Layout :: ChildData , NodeContext = Layout :: DeserializationContext > ,
60+ {
5461 let mut current_subtrees = subtrees;
5562 let mut next_subtrees = Vec :: new ( ) ;
5663 while !current_subtrees. is_empty ( ) {
5764 let should_fetch_modified_leaves =
5865 config. compare_modified_leaves ( ) || previous_leaves. is_some ( ) ;
5966 let filled_roots =
60- calculate_subtrees_roots :: < L > ( & current_subtrees, storage, key_context) . await ?;
67+ get_roots_from_storage :: < L , Layout > ( & current_subtrees, storage, key_context) . await ?;
6168 for ( filled_root, subtree) in filled_roots. into_iter ( ) . zip ( current_subtrees. iter ( ) ) {
6269 match filled_root. data {
6370 // Binary node.
64- NodeData :: Binary ( BinaryData { left_hash , right_hash } ) => {
71+ NodeData :: Binary ( BinaryData { left_data , right_data } ) => {
6572 if subtree. is_unmodified ( ) {
6673 skeleton_tree. nodes . insert (
67- subtree. root_index ,
74+ subtree. get_root_index ( ) ,
6875 OriginalSkeletonNode :: UnmodifiedSubTree ( filled_root. hash ) ,
6976 ) ;
7077 continue ;
7178 }
72- skeleton_tree. nodes . insert ( subtree. root_index , OriginalSkeletonNode :: Binary ) ;
79+ skeleton_tree
80+ . nodes
81+ . insert ( subtree. get_root_index ( ) , OriginalSkeletonNode :: Binary ) ;
7382 let ( left_subtree, right_subtree) =
74- subtree. get_children_subtrees ( left_hash , right_hash ) ;
83+ subtree. get_children_subtrees ( left_data , right_data ) ;
7584
7685 handle_subtree (
7786 skeleton_tree,
7887 & mut next_subtrees,
7988 left_subtree,
89+ left_data,
8090 should_fetch_modified_leaves,
8191 ) ;
8292 handle_subtree (
8393 skeleton_tree,
8494 & mut next_subtrees,
8595 right_subtree,
96+ right_data,
8697 should_fetch_modified_leaves,
8798 )
8899 }
89100 // Edge node.
90- NodeData :: Edge ( EdgeData { bottom_hash, path_to_bottom } ) => {
91- skeleton_tree
92- . nodes
93- . insert ( subtree. root_index , OriginalSkeletonNode :: Edge ( path_to_bottom) ) ;
101+ NodeData :: Edge ( EdgeData { bottom_data, path_to_bottom } ) => {
102+ skeleton_tree. nodes . insert (
103+ subtree. get_root_index ( ) ,
104+ OriginalSkeletonNode :: Edge ( path_to_bottom) ,
105+ ) ;
106+
107+ // Parse bottom.
108+ let ( bottom_subtree, previously_empty_leaves_indices) =
109+ subtree. get_bottom_subtree ( & path_to_bottom, bottom_data) ;
110+
94111 if subtree. is_unmodified ( ) {
95- skeleton_tree. nodes . insert (
96- path_to_bottom. bottom_index ( subtree. root_index ) ,
97- OriginalSkeletonNode :: UnmodifiedSubTree ( bottom_hash) ,
98- ) ;
112+ if !SubTree :: should_traverse_unmodified_children ( ) {
113+ skeleton_tree. nodes . insert (
114+ path_to_bottom. bottom_index ( subtree. get_root_index ( ) ) ,
115+ OriginalSkeletonNode :: UnmodifiedSubTree (
116+ SubTree :: unmodified_child_hash ( bottom_data) . unwrap ( ) ,
117+ ) ,
118+ ) ;
119+ } else {
120+ // With index layout we need to traverse an unmodified bottom node.
121+ next_subtrees. push ( bottom_subtree)
122+ }
99123 continue ;
100124 }
101- // Parse bottom.
102- let ( bottom_subtree, previously_empty_leaves_indices) =
103- subtree. get_bottom_subtree ( & path_to_bottom, bottom_hash) ;
125+
104126 if let Some ( ref mut leaves) = previous_leaves {
105127 leaves. extend (
106128 previously_empty_leaves_indices
@@ -119,23 +141,28 @@ async fn fetch_nodes<'a, L: Leaf>(
119141 skeleton_tree,
120142 & mut next_subtrees,
121143 bottom_subtree,
144+ bottom_data,
122145 should_fetch_modified_leaves,
123146 ) ;
124147 }
125148 // Leaf node.
126149 NodeData :: Leaf ( previous_leaf) => {
127150 if subtree. is_unmodified ( ) {
128- warn ! ( "Unexpectedly deserialized leaf sibling." )
151+ skeleton_tree. nodes . insert (
152+ subtree. get_root_index ( ) ,
153+ OriginalSkeletonNode :: UnmodifiedSubTree ( filled_root. hash ) ,
154+ ) ;
129155 } else {
156+ let root_index = subtree. get_root_index ( ) ;
130157 // Modified leaf.
131158 if config. compare_modified_leaves ( )
132- && L :: compare ( leaf_modifications, & subtree . root_index , & previous_leaf) ?
159+ && L :: compare ( leaf_modifications, & root_index, & previous_leaf) ?
133160 {
134- log_trivial_modification ! ( subtree . root_index, previous_leaf) ;
161+ log_trivial_modification ! ( root_index, previous_leaf) ;
135162 }
136163 // If previous values of modified leaves are requested, add this leaf.
137164 if let Some ( ref mut leaves) = previous_leaves {
138- leaves. insert ( subtree . root_index , previous_leaf) ;
165+ leaves. insert ( root_index, previous_leaf) ;
139166 }
140167 }
141168 }
@@ -166,9 +193,9 @@ pub async fn create_original_skeleton_tree<'a, L: Leaf>(
166193 ) ?;
167194 return Ok ( OriginalSkeletonTreeImpl :: create_empty ( sorted_leaf_indices) ) ;
168195 }
169- let main_subtree = FactsSubTree :: create ( sorted_leaf_indices, NodeIndex :: ROOT , root_hash) ;
196+ let main_subtree = FactsSubTree { sorted_leaf_indices, root_index : NodeIndex :: ROOT , root_hash } ;
170197 let mut skeleton_tree = OriginalSkeletonTreeImpl { nodes : HashMap :: new ( ) , sorted_leaf_indices } ;
171- fetch_nodes :: < L > (
198+ fetch_nodes :: < L , FactsNodeLayout , FactsSubTree < ' a > > (
172199 & mut skeleton_tree,
173200 vec ! [ main_subtree] ,
174201 storage,
@@ -202,7 +229,7 @@ pub async fn create_original_skeleton_tree_and_get_previous_leaves<'a, L: Leaf>(
202229 let main_subtree = FactsSubTree { sorted_leaf_indices, root_index : NodeIndex :: ROOT , root_hash } ;
203230 let mut skeleton_tree = OriginalSkeletonTreeImpl { nodes : HashMap :: new ( ) , sorted_leaf_indices } ;
204231 let mut leaves = HashMap :: new ( ) ;
205- fetch_nodes :: < L > (
232+ fetch_nodes :: < L , FactsNodeLayout , FactsSubTree < ' a > > (
206233 & mut skeleton_tree,
207234 vec ! [ main_subtree] ,
208235 storage,
@@ -237,19 +264,40 @@ pub async fn get_leaves<'a, L: Leaf>(
237264
238265/// Handles a subtree referred by an edge or a binary node. Decides whether we deserialize the
239266/// referred subtree or not.
240- fn handle_subtree < ' a > (
267+ fn handle_subtree < ' a , SubTree : SubTreeTrait < ' a > > (
241268 skeleton_tree : & mut OriginalSkeletonTreeImpl < ' a > ,
242- next_subtrees : & mut Vec < FactsSubTree < ' a > > ,
243- subtree : FactsSubTree < ' a > ,
269+ next_subtrees : & mut Vec < SubTree > ,
270+ subtree : SubTree ,
271+ subtree_data : SubTree :: NodeData ,
244272 should_fetch_modified_leaves : bool ,
245273) {
246- if !subtree. is_leaf ( ) || ( should_fetch_modified_leaves && !subtree. is_unmodified ( ) ) {
274+ let is_leaf = subtree. is_leaf ( ) ;
275+ let is_unmodified = subtree. is_unmodified ( ) ;
276+
277+ // 1. Internal node → always traverse.
278+ if !is_leaf {
279+ next_subtrees. push ( subtree) ;
280+ return ;
281+ }
282+
283+ // 2. Modified leaf.
284+ if !is_unmodified {
285+ if should_fetch_modified_leaves {
286+ next_subtrees. push ( subtree) ;
287+ }
288+ return ;
289+ }
290+
291+ // 3. Unmodified leaf sibling.
292+ if !SubTree :: should_traverse_unmodified_children ( ) {
293+ skeleton_tree. nodes . insert (
294+ subtree. get_root_index ( ) ,
295+ OriginalSkeletonNode :: UnmodifiedSubTree (
296+ SubTree :: unmodified_child_hash ( subtree_data) . unwrap ( ) ,
297+ ) ,
298+ ) ;
299+ } else {
247300 next_subtrees. push ( subtree) ;
248- } else if subtree. is_unmodified ( ) {
249- // Leaf sibling.
250- skeleton_tree
251- . nodes
252- . insert ( subtree. root_index , OriginalSkeletonNode :: UnmodifiedSubTree ( subtree. root_hash ) ) ;
253301 }
254302}
255303
0 commit comments