@@ -3,6 +3,7 @@ use std::collections::HashMap;
33use std:: fmt:: Debug ;
44
55use starknet_api:: hash:: HashOutput ;
6+ use starknet_patricia:: patricia_merkle_tree:: filled_tree:: node:: FilledNode ;
67use starknet_patricia:: patricia_merkle_tree:: node_data:: inner_node:: {
78 BinaryData ,
89 EdgeData ,
@@ -18,13 +19,15 @@ use starknet_patricia::patricia_merkle_tree::original_skeleton_tree::tree::{
1819 OriginalSkeletonTreeImpl ,
1920 OriginalSkeletonTreeResult ,
2021} ;
21- use starknet_patricia:: patricia_merkle_tree:: traversal:: SubTreeTrait ;
22+ use starknet_patricia:: patricia_merkle_tree:: traversal:: { SubTreeTrait , UnmodifiedChildTraversal } ;
2223use starknet_patricia:: patricia_merkle_tree:: types:: { NodeIndex , SortedLeafIndices } ;
23- use starknet_patricia_storage:: db_object:: HasStaticPrefix ;
24+ use starknet_patricia_storage:: db_object:: { DBObject , HasStaticPrefix } ;
2425use starknet_patricia_storage:: storage_trait:: Storage ;
2526use tracing:: warn;
2627
27- use crate :: db:: facts_db:: traversal:: calculate_subtrees_roots;
28+ use crate :: db:: db_layout:: NodeLayout ;
29+ use crate :: db:: facts_db:: db:: FactsNodeLayout ;
30+ use crate :: db:: facts_db:: traversal:: get_roots_from_storage;
2831use crate :: db:: facts_db:: types:: FactsSubTree ;
2932
3033#[ cfg( test) ]
@@ -39,68 +42,90 @@ macro_rules! log_trivial_modification {
3942}
4043
4144/// Fetches the Patricia witnesses, required to build the original skeleton tree from storage.
45+ ///
4246/// Given a list of subtrees, traverses towards their leaves and fetches all non-empty,
4347/// unmodified nodes. If `compare_modified_leaves` is set, function logs out a warning when
4448/// encountering a trivial modification. Fills the previous leaf values if it is not none.
45- async fn fetch_nodes < ' a , L : Leaf > (
49+ ///
50+ /// The function is generic over the DB layout (`Layout`), which controls the concrete node data
51+ /// (`Layout::NodeData`) and traversal strategy (via `Layout::SubTree`).
52+ async fn fetch_nodes < ' a , L , Layout > (
4653 skeleton_tree : & mut OriginalSkeletonTreeImpl < ' a > ,
47- subtrees : Vec < FactsSubTree < ' a > > ,
54+ subtrees : Vec < Layout :: SubTree > ,
4855 storage : & mut impl Storage ,
4956 leaf_modifications : & LeafModifications < L > ,
5057 config : & impl OriginalSkeletonTreeConfig < L > ,
5158 mut previous_leaves : Option < & mut HashMap < NodeIndex , L > > ,
5259 key_context : & <L as HasStaticPrefix >:: KeyContext ,
53- ) -> OriginalSkeletonTreeResult < ( ) > {
60+ ) -> OriginalSkeletonTreeResult < ( ) >
61+ where
62+ L : Leaf ,
63+ Layout : NodeLayout < ' a , L > ,
64+ FilledNode < L , Layout :: NodeData > : DBObject < DeserializeContext = Layout :: DeserializationContext > ,
65+ {
5466 let mut current_subtrees = subtrees;
5567 let mut next_subtrees = Vec :: new ( ) ;
5668 while !current_subtrees. is_empty ( ) {
5769 let should_fetch_modified_leaves =
5870 config. compare_modified_leaves ( ) || previous_leaves. is_some ( ) ;
5971 let filled_roots =
60- calculate_subtrees_roots :: < L > ( & current_subtrees, storage, key_context) . await ?;
72+ get_roots_from_storage :: < L , Layout > ( & current_subtrees, storage, key_context) . await ?;
6173 for ( filled_root, subtree) in filled_roots. into_iter ( ) . zip ( current_subtrees. iter ( ) ) {
74+ let root_index = subtree. get_root_index ( ) ;
6275 match filled_root. data {
6376 // Binary node.
6477 NodeData :: Binary ( BinaryData { left_data, right_data } ) => {
6578 if subtree. is_unmodified ( ) {
6679 skeleton_tree. nodes . insert (
67- subtree . root_index ,
80+ root_index,
6881 OriginalSkeletonNode :: UnmodifiedSubTree ( filled_root. hash ) ,
6982 ) ;
7083 continue ;
7184 }
72- skeleton_tree. nodes . insert ( subtree . root_index , OriginalSkeletonNode :: Binary ) ;
85+ skeleton_tree. nodes . insert ( root_index, OriginalSkeletonNode :: Binary ) ;
7386 let ( left_subtree, right_subtree) =
7487 subtree. get_children_subtrees ( left_data, right_data) ;
7588
7689 handle_subtree (
7790 skeleton_tree,
7891 & mut next_subtrees,
7992 left_subtree,
93+ left_data,
8094 should_fetch_modified_leaves,
8195 ) ;
8296 handle_subtree (
8397 skeleton_tree,
8498 & mut next_subtrees,
8599 right_subtree,
100+ right_data,
86101 should_fetch_modified_leaves,
87102 )
88103 }
89104 // Edge node.
90105 NodeData :: Edge ( EdgeData { bottom_data, path_to_bottom } ) => {
91106 skeleton_tree
92107 . nodes
93- . insert ( subtree. root_index , OriginalSkeletonNode :: Edge ( path_to_bottom) ) ;
94- if subtree. is_unmodified ( ) {
95- skeleton_tree. nodes . insert (
96- path_to_bottom. bottom_index ( subtree. root_index ) ,
97- OriginalSkeletonNode :: UnmodifiedSubTree ( bottom_data) ,
98- ) ;
99- continue ;
100- }
108+ . insert ( root_index, OriginalSkeletonNode :: Edge ( path_to_bottom) ) ;
109+
101110 // Parse bottom.
102111 let ( bottom_subtree, previously_empty_leaves_indices) =
103112 subtree. get_bottom_subtree ( & path_to_bottom, bottom_data) ;
113+
114+ if subtree. is_unmodified ( ) {
115+ match Layout :: SubTree :: should_traverse_unmodified_child ( bottom_data) {
116+ UnmodifiedChildTraversal :: Traverse => {
117+ next_subtrees. push ( bottom_subtree) ;
118+ }
119+ UnmodifiedChildTraversal :: Skip ( unmodified_child_hash) => {
120+ skeleton_tree. nodes . insert (
121+ path_to_bottom. bottom_index ( root_index) ,
122+ OriginalSkeletonNode :: UnmodifiedSubTree ( unmodified_child_hash) ,
123+ ) ;
124+ }
125+ }
126+ continue ;
127+ }
128+
104129 if let Some ( ref mut leaves) = previous_leaves {
105130 leaves. extend (
106131 previously_empty_leaves_indices
@@ -119,23 +144,27 @@ async fn fetch_nodes<'a, L: Leaf>(
119144 skeleton_tree,
120145 & mut next_subtrees,
121146 bottom_subtree,
147+ bottom_data,
122148 should_fetch_modified_leaves,
123149 ) ;
124150 }
125151 // Leaf node.
126152 NodeData :: Leaf ( previous_leaf) => {
127153 if subtree. is_unmodified ( ) {
128- warn ! ( "Unexpectedly deserialized leaf sibling." )
154+ skeleton_tree. nodes . insert (
155+ root_index,
156+ OriginalSkeletonNode :: UnmodifiedSubTree ( filled_root. hash ) ,
157+ ) ;
129158 } else {
130159 // Modified leaf.
131160 if config. compare_modified_leaves ( )
132- && L :: compare ( leaf_modifications, & subtree . root_index , & previous_leaf) ?
161+ && L :: compare ( leaf_modifications, & root_index, & previous_leaf) ?
133162 {
134- log_trivial_modification ! ( subtree . root_index, previous_leaf) ;
163+ log_trivial_modification ! ( root_index, previous_leaf) ;
135164 }
136165 // If previous values of modified leaves are requested, add this leaf.
137166 if let Some ( ref mut leaves) = previous_leaves {
138- leaves. insert ( subtree . root_index , previous_leaf) ;
167+ leaves. insert ( root_index, previous_leaf) ;
139168 }
140169 }
141170 }
@@ -168,7 +197,7 @@ pub async fn create_original_skeleton_tree<'a, L: Leaf>(
168197 }
169198 let main_subtree = FactsSubTree :: create ( sorted_leaf_indices, NodeIndex :: ROOT , root_hash) ;
170199 let mut skeleton_tree = OriginalSkeletonTreeImpl { nodes : HashMap :: new ( ) , sorted_leaf_indices } ;
171- fetch_nodes :: < L > (
200+ fetch_nodes :: < L , FactsNodeLayout > (
172201 & mut skeleton_tree,
173202 vec ! [ main_subtree] ,
174203 storage,
@@ -202,7 +231,7 @@ pub async fn create_original_skeleton_tree_and_get_previous_leaves<'a, L: Leaf>(
202231 let main_subtree = FactsSubTree :: create ( sorted_leaf_indices, NodeIndex :: ROOT , root_hash) ;
203232 let mut skeleton_tree = OriginalSkeletonTreeImpl { nodes : HashMap :: new ( ) , sorted_leaf_indices } ;
204233 let mut leaves = HashMap :: new ( ) ;
205- fetch_nodes :: < L > (
234+ fetch_nodes :: < L , FactsNodeLayout > (
206235 & mut skeleton_tree,
207236 vec ! [ main_subtree] ,
208237 storage,
@@ -240,19 +269,41 @@ pub async fn get_leaves<'a, L: Leaf>(
240269
241270/// Handles a subtree referred by an edge or a binary node. Decides whether we deserialize the
242271/// referred subtree or not.
243- fn handle_subtree < ' a > (
272+ fn handle_subtree < ' a , SubTree : SubTreeTrait < ' a > > (
244273 skeleton_tree : & mut OriginalSkeletonTreeImpl < ' a > ,
245- next_subtrees : & mut Vec < FactsSubTree < ' a > > ,
246- subtree : FactsSubTree < ' a > ,
274+ next_subtrees : & mut Vec < SubTree > ,
275+ subtree : SubTree ,
276+ subtree_data : SubTree :: NodeData ,
247277 should_fetch_modified_leaves : bool ,
248278) {
249- if !subtree. is_leaf ( ) || ( should_fetch_modified_leaves && !subtree. is_unmodified ( ) ) {
279+ let is_leaf = subtree. is_leaf ( ) ;
280+ let is_modified = !subtree. is_unmodified ( ) ;
281+
282+ // Internal node → always traverse.
283+ if !is_leaf {
250284 next_subtrees. push ( subtree) ;
251- } else if subtree. is_unmodified ( ) {
252- // Leaf sibling.
253- skeleton_tree
254- . nodes
255- . insert ( subtree. root_index , OriginalSkeletonNode :: UnmodifiedSubTree ( subtree. root_hash ) ) ;
285+ return ;
286+ }
287+
288+ // Modified leaf.
289+ if is_modified {
290+ if should_fetch_modified_leaves {
291+ next_subtrees. push ( subtree) ;
292+ }
293+ return ;
294+ }
295+
296+ // Unmodified leaf sibling.
297+ match SubTree :: should_traverse_unmodified_child ( subtree_data) {
298+ UnmodifiedChildTraversal :: Traverse => {
299+ next_subtrees. push ( subtree) ;
300+ }
301+ UnmodifiedChildTraversal :: Skip ( unmodified_child_hash) => {
302+ skeleton_tree. nodes . insert (
303+ subtree. get_root_index ( ) ,
304+ OriginalSkeletonNode :: UnmodifiedSubTree ( unmodified_child_hash) ,
305+ ) ;
306+ }
256307 }
257308}
258309
0 commit comments