1- use std:: borrow:: Borrow ;
21use std:: collections:: HashMap ;
3- use std:: fmt:: Debug ;
42
53use starknet_api:: hash:: HashOutput ;
6- use starknet_patricia:: patricia_merkle_tree:: node_data:: inner_node:: {
7- BinaryData ,
8- EdgeData ,
9- NodeData ,
10- } ;
114use starknet_patricia:: patricia_merkle_tree:: node_data:: leaf:: { Leaf , LeafModifications } ;
12- use starknet_patricia:: patricia_merkle_tree:: original_skeleton_tree:: config:: {
13- NoCompareOriginalSkeletonTrieConfig ,
14- OriginalSkeletonTreeConfig ,
15- } ;
16- use starknet_patricia:: patricia_merkle_tree:: original_skeleton_tree:: node:: OriginalSkeletonNode ;
5+ use starknet_patricia:: patricia_merkle_tree:: original_skeleton_tree:: config:: OriginalSkeletonTreeConfig ;
176use starknet_patricia:: patricia_merkle_tree:: original_skeleton_tree:: tree:: {
187 OriginalSkeletonTreeImpl ,
198 OriginalSkeletonTreeResult ,
209} ;
21- use starknet_patricia:: patricia_merkle_tree:: traversal:: SubTreeTrait ;
2210use starknet_patricia:: patricia_merkle_tree:: types:: { NodeIndex , SortedLeafIndices } ;
2311use starknet_patricia_storage:: db_object:: HasStaticPrefix ;
2412use starknet_patricia_storage:: storage_trait:: Storage ;
25- use tracing:: warn;
2613
27- use crate :: db:: db_layout:: NodeLayout ;
2814use crate :: db:: facts_db:: db:: FactsNodeLayout ;
29- use crate :: db:: facts_db:: traversal:: get_roots_from_storage;
3015use crate :: db:: facts_db:: types:: FactsSubTree ;
3116use crate :: db:: trie_traversal:: fetch_nodes;
3217use crate :: patricia_merkle_tree:: tree:: OriginalSkeletonTrieDontCompareConfig ;
@@ -35,198 +20,15 @@ use crate::patricia_merkle_tree::tree::OriginalSkeletonTrieDontCompareConfig;
3520#[ path = "create_facts_tree_test.rs" ]
3621pub mod create_facts_tree_test;
3722
38- /// Logs out a warning of a trivial modification.
39- macro_rules! log_trivial_modification {
40- ( $index: expr, $value: expr) => {
41- warn!( "Encountered a trivial modification at index {:?}, with value {:?}" , $index, $value) ;
42- } ;
43- }
44-
45- /// Fetches the Patricia witnesses, required to build the original skeleton tree from storage.
46- /// Given a list of subtrees, traverses towards their leaves and fetches all non-empty,
47- /// unmodified nodes. If `compare_modified_leaves` is set, function logs out a warning when
48- /// encountering a trivial modification. Fills the previous leaf values if it is not none.
49- async fn fetch_nodes < ' a , L , Layout , SubTree > (
50- skeleton_tree : & mut OriginalSkeletonTreeImpl < ' a > ,
51- subtrees : Vec <
52- impl SubTreeTrait <
53- ' a ,
54- ChildData = Layout :: ChildData ,
55- NodeContext = Layout :: DeserializationContext ,
56- > ,
57- > ,
58- storage : & mut impl Storage ,
59- leaf_modifications : & LeafModifications < L > ,
60- config : & impl OriginalSkeletonTreeConfig < L > ,
61- mut previous_leaves : Option < & mut HashMap < NodeIndex , L > > ,
62- key_context : & <L as HasStaticPrefix >:: KeyContext ,
63- ) -> OriginalSkeletonTreeResult < ( ) >
64- where
65- L : Leaf ,
66- Layout : NodeLayout < L > ,
67- SubTree : SubTreeTrait <
68- ' a ,
69- ChildData = Layout :: ChildData ,
70- NodeContext = Layout :: DeserializationContext ,
71- > ,
72- {
73- let mut current_subtrees = subtrees;
74- let mut next_subtrees = Vec :: new ( ) ;
75- while !current_subtrees. is_empty ( ) {
76- let should_fetch_modified_leaves =
77- config. compare_modified_leaves ( ) || previous_leaves. is_some ( ) ;
78- let filled_roots =
79- get_roots_from_storage :: < L , Layout > ( & current_subtrees, storage, key_context) . await ?;
80- for ( filled_root, subtree) in filled_roots. into_iter ( ) . zip ( current_subtrees. iter ( ) ) {
81- match filled_root. data {
82- // Binary node.
83- NodeData :: Binary ( BinaryData { left_data, right_data } ) => {
84- if subtree. is_unmodified ( ) {
85- skeleton_tree. nodes . insert (
86- subtree. get_root_index ( ) ,
87- OriginalSkeletonNode :: UnmodifiedSubTree ( filled_root. hash ) ,
88- ) ;
89- continue ;
90- }
91- skeleton_tree
92- . nodes
93- . insert ( subtree. get_root_index ( ) , OriginalSkeletonNode :: Binary ) ;
94- let ( left_subtree, right_subtree) =
95- subtree. get_children_subtrees ( left_data, right_data) ;
96-
97- handle_subtree (
98- skeleton_tree,
99- & mut next_subtrees,
100- left_subtree,
101- left_data,
102- should_fetch_modified_leaves,
103- ) ;
104- handle_subtree (
105- skeleton_tree,
106- & mut next_subtrees,
107- right_subtree,
108- right_data,
109- should_fetch_modified_leaves,
110- )
111- }
112- // Edge node.
113- NodeData :: Edge ( EdgeData { bottom_data, path_to_bottom } ) => {
114- skeleton_tree. nodes . insert (
115- subtree. get_root_index ( ) ,
116- OriginalSkeletonNode :: Edge ( path_to_bottom) ,
117- ) ;
118-
119- // Parse bottom.
120- let ( bottom_subtree, previously_empty_leaves_indices) =
121- subtree. get_bottom_subtree ( & path_to_bottom, bottom_data) ;
122-
123- if subtree. is_unmodified ( ) {
124- if !SubTree :: should_traverse_unmodified_children ( ) {
125- skeleton_tree. nodes . insert (
126- path_to_bottom. bottom_index ( subtree. get_root_index ( ) ) ,
127- OriginalSkeletonNode :: UnmodifiedSubTree (
128- SubTree :: unmodified_child_hash ( bottom_data) . unwrap ( ) ,
129- ) ,
130- ) ;
131- } else {
132- // With index layout we need to traverse an unmodified bottom node.
133- next_subtrees. push ( bottom_subtree)
134- }
135- continue ;
136- }
137-
138- if let Some ( ref mut leaves) = previous_leaves {
139- leaves. extend (
140- previously_empty_leaves_indices
141- . iter ( )
142- . map ( |idx| ( * idx, L :: default ( ) ) )
143- . collect :: < HashMap < NodeIndex , L > > ( ) ,
144- ) ;
145- }
146- log_warning_for_empty_leaves (
147- & previously_empty_leaves_indices,
148- leaf_modifications,
149- config,
150- ) ?;
151-
152- handle_subtree (
153- skeleton_tree,
154- & mut next_subtrees,
155- bottom_subtree,
156- bottom_data,
157- should_fetch_modified_leaves,
158- ) ;
159- }
160- // Leaf node.
161- NodeData :: Leaf ( previous_leaf) => {
162- if subtree. is_unmodified ( ) {
163- skeleton_tree. nodes . insert (
164- subtree. get_root_index ( ) ,
165- OriginalSkeletonNode :: UnmodifiedSubTree ( filled_root. hash ) ,
166- ) ;
167- } else {
168- let root_index = subtree. get_root_index ( ) ;
169- // Modified leaf.
170- if config. compare_modified_leaves ( )
171- && L :: compare ( leaf_modifications, & root_index, & previous_leaf) ?
172- {
173- log_trivial_modification ! ( root_index, previous_leaf) ;
174- }
175- // If previous values of modified leaves are requested, add this leaf.
176- if let Some ( ref mut leaves) = previous_leaves {
177- leaves. insert ( root_index, previous_leaf) ;
178- }
179- }
180- }
181- }
182- }
183- current_subtrees = next_subtrees;
184- next_subtrees = Vec :: new ( ) ;
185- }
186- Ok ( ( ) )
187- }
188-
189- pub async fn create_original_skeleton_tree < ' a , L : Leaf > (
190- storage : & mut impl Storage ,
191- root_hash : HashOutput ,
192- sorted_leaf_indices : SortedLeafIndices < ' a > ,
193- config : & impl OriginalSkeletonTreeConfig < L > ,
194- leaf_modifications : & LeafModifications < L > ,
195- key_context : & <L as HasStaticPrefix >:: KeyContext ,
196- ) -> OriginalSkeletonTreeResult < OriginalSkeletonTreeImpl < ' a > > {
197- if sorted_leaf_indices. is_empty ( ) {
198- return Ok ( OriginalSkeletonTreeImpl :: create_unmodified ( root_hash) ) ;
199- }
200- if root_hash == HashOutput :: ROOT_OF_EMPTY_TREE {
201- log_warning_for_empty_leaves (
202- sorted_leaf_indices. get_indices ( ) ,
203- leaf_modifications,
204- config,
205- ) ?;
206- return Ok ( OriginalSkeletonTreeImpl :: create_empty ( sorted_leaf_indices) ) ;
207- }
208- let main_subtree = FactsSubTree { sorted_leaf_indices, root_index : NodeIndex :: ROOT , root_hash } ;
209- let mut skeleton_tree = OriginalSkeletonTreeImpl { nodes : HashMap :: new ( ) , sorted_leaf_indices } ;
210- fetch_nodes :: < L , FactsNodeLayout , FactsSubTree < ' a > > (
211- & mut skeleton_tree,
212- vec ! [ main_subtree] ,
213- storage,
214- leaf_modifications,
215- config,
216- None ,
217- key_context,
218- )
219- . await ?;
220- Ok ( skeleton_tree)
221- }
222-
223- pub async fn create_original_skeleton_tree_and_get_previous_leaves < ' a , L : Leaf > (
23+ pub async fn create_original_skeleton_tree_and_get_previous_leaves <
24+ ' a ,
25+ L : Leaf + HasStaticPrefix < KeyContext = ( ) > ,
26+ > (
22427 storage : & mut impl Storage ,
22528 root_hash : HashOutput ,
22629 sorted_leaf_indices : SortedLeafIndices < ' a > ,
22730 leaf_modifications : & LeafModifications < L > ,
228- config : & impl OriginalSkeletonTreeConfig < L > ,
229- key_context : & <L as HasStaticPrefix >:: KeyContext ,
31+ config : & impl OriginalSkeletonTreeConfig ,
23032) -> OriginalSkeletonTreeResult < ( OriginalSkeletonTreeImpl < ' a > , HashMap < NodeIndex , L > ) > {
23133 if sorted_leaf_indices. is_empty ( ) {
23234 let unmodified = OriginalSkeletonTreeImpl :: create_unmodified ( root_hash) ;
@@ -241,94 +43,33 @@ pub async fn create_original_skeleton_tree_and_get_previous_leaves<'a, L: Leaf>(
24143 let main_subtree = FactsSubTree { sorted_leaf_indices, root_index : NodeIndex :: ROOT , root_hash } ;
24244 let mut skeleton_tree = OriginalSkeletonTreeImpl { nodes : HashMap :: new ( ) , sorted_leaf_indices } ;
24345 let mut leaves = HashMap :: new ( ) ;
244- fetch_nodes :: < L , FactsNodeLayout , FactsSubTree < ' a > > (
46+ fetch_nodes :: < L , FactsNodeLayout > (
24547 & mut skeleton_tree,
24648 vec ! [ main_subtree] ,
24749 storage,
24850 leaf_modifications,
24951 config,
25052 Some ( & mut leaves) ,
251- key_context ,
53+ & ( ) ,
25254 )
25355 . await ?;
25456 Ok ( ( skeleton_tree, leaves) )
25557}
25658
257- pub async fn get_leaves < ' a , L : Leaf > (
59+ pub async fn get_leaves < ' a , L : Leaf + HasStaticPrefix < KeyContext = ( ) > > (
25860 storage : & mut impl Storage ,
25961 root_hash : HashOutput ,
26062 sorted_leaf_indices : SortedLeafIndices < ' a > ,
261- key_context : & <L as HasStaticPrefix >:: KeyContext ,
26263) -> OriginalSkeletonTreeResult < HashMap < NodeIndex , L > > {
263- let config = NoCompareOriginalSkeletonTrieConfig :: default ( ) ;
64+ let config = OriginalSkeletonTrieDontCompareConfig ;
26465 let leaf_modifications = LeafModifications :: new ( ) ;
26566 let ( _, previous_leaves) = create_original_skeleton_tree_and_get_previous_leaves (
26667 storage,
26768 root_hash,
26869 sorted_leaf_indices,
26970 & leaf_modifications,
27071 & config,
271- key_context,
27272 )
27373 . await ?;
27474 Ok ( previous_leaves)
27575}
276-
277- /// Handles a subtree referred by an edge or a binary node. Decides whether we deserialize the
278- /// referred subtree or not.
279- fn handle_subtree < ' a , SubTree : SubTreeTrait < ' a > > (
280- skeleton_tree : & mut OriginalSkeletonTreeImpl < ' a > ,
281- next_subtrees : & mut Vec < SubTree > ,
282- subtree : SubTree ,
283- subtree_data : SubTree :: ChildData ,
284- should_fetch_modified_leaves : bool ,
285- ) {
286- let is_leaf = subtree. is_leaf ( ) ;
287- let is_unmodified = subtree. is_unmodified ( ) ;
288-
289- // 1. Internal node → always traverse.
290- if !is_leaf {
291- next_subtrees. push ( subtree) ;
292- return ;
293- }
294-
295- // 2. Modified leaf.
296- if !is_unmodified {
297- if should_fetch_modified_leaves {
298- next_subtrees. push ( subtree) ;
299- }
300- return ;
301- }
302-
303- // 3. Unmodified leaf sibling.
304- if !SubTree :: should_traverse_unmodified_children ( ) {
305- skeleton_tree. nodes . insert (
306- subtree. get_root_index ( ) ,
307- OriginalSkeletonNode :: UnmodifiedSubTree (
308- SubTree :: unmodified_child_hash ( subtree_data) . unwrap ( ) ,
309- ) ,
310- ) ;
311- } else {
312- next_subtrees. push ( subtree) ;
313- }
314- }
315-
316- /// Given leaf indices that were previously empty leaves, logs out a warning for trivial
317- /// modification if a leaf is modified to an empty leaf.
318- /// If this check is suppressed by configuration, does nothing.
319- fn log_warning_for_empty_leaves < L : Leaf , T : Borrow < NodeIndex > + Debug > (
320- leaf_indices : & [ T ] ,
321- leaf_modifications : & LeafModifications < L > ,
322- config : & impl OriginalSkeletonTreeConfig < L > ,
323- ) -> OriginalSkeletonTreeResult < ( ) > {
324- if !config. compare_modified_leaves ( ) {
325- return Ok ( ( ) ) ;
326- }
327- let empty_leaf = L :: default ( ) ;
328- for leaf_index in leaf_indices {
329- if L :: compare ( leaf_modifications, leaf_index. borrow ( ) , & empty_leaf) ? {
330- log_trivial_modification ! ( leaf_index, empty_leaf) ;
331- }
332- }
333- Ok ( ( ) )
334- }
0 commit comments