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 } ;
23- use starknet_patricia_storage:: db_object:: HasStaticPrefix ;
11+ use starknet_patricia_storage:: db_object:: { EmptyKeyContext , 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,188 +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 < SubTree > ,
52- storage : & mut impl Storage ,
53- leaf_modifications : & LeafModifications < L > ,
54- config : & impl OriginalSkeletonTreeConfig < L > ,
55- mut previous_leaves : Option < & mut HashMap < NodeIndex , L > > ,
56- key_context : & <L as HasStaticPrefix >:: KeyContext ,
57- ) -> OriginalSkeletonTreeResult < ( ) >
58- where
59- L : Leaf ,
60- Layout : NodeLayout < L > ,
61- SubTree : SubTreeTrait < ' a , NodeData = Layout :: ChildData , NodeContext = Layout :: DeserializationContext > ,
62- {
63- let mut current_subtrees = subtrees;
64- let mut next_subtrees = Vec :: new ( ) ;
65- while !current_subtrees. is_empty ( ) {
66- let should_fetch_modified_leaves =
67- config. compare_modified_leaves ( ) || previous_leaves. is_some ( ) ;
68- let filled_roots =
69- get_roots_from_storage :: < L , Layout > ( & current_subtrees, storage, key_context) . await ?;
70- for ( filled_root, subtree) in filled_roots. into_iter ( ) . zip ( current_subtrees. iter ( ) ) {
71- match filled_root. data {
72- // Binary node.
73- NodeData :: Binary ( BinaryData { left_data, right_data } ) => {
74- if subtree. is_unmodified ( ) {
75- skeleton_tree. nodes . insert (
76- subtree. get_root_index ( ) ,
77- OriginalSkeletonNode :: UnmodifiedSubTree ( filled_root. hash ) ,
78- ) ;
79- continue ;
80- }
81- skeleton_tree
82- . nodes
83- . insert ( subtree. get_root_index ( ) , OriginalSkeletonNode :: Binary ) ;
84- let ( left_subtree, right_subtree) =
85- subtree. get_children_subtrees ( left_data, right_data) ;
86-
87- handle_subtree (
88- skeleton_tree,
89- & mut next_subtrees,
90- left_subtree,
91- left_data,
92- should_fetch_modified_leaves,
93- ) ;
94- handle_subtree (
95- skeleton_tree,
96- & mut next_subtrees,
97- right_subtree,
98- right_data,
99- should_fetch_modified_leaves,
100- )
101- }
102- // Edge node.
103- NodeData :: Edge ( EdgeData { bottom_data, path_to_bottom } ) => {
104- skeleton_tree. nodes . insert (
105- subtree. get_root_index ( ) ,
106- OriginalSkeletonNode :: Edge ( path_to_bottom) ,
107- ) ;
108-
109- // Parse bottom.
110- let ( bottom_subtree, previously_empty_leaves_indices) =
111- subtree. get_bottom_subtree ( & path_to_bottom, bottom_data) ;
112-
113- if subtree. is_unmodified ( ) {
114- if !SubTree :: should_traverse_unmodified_children ( ) {
115- skeleton_tree. nodes . insert (
116- path_to_bottom. bottom_index ( subtree. get_root_index ( ) ) ,
117- OriginalSkeletonNode :: UnmodifiedSubTree (
118- SubTree :: unmodified_child_hash ( bottom_data) . unwrap ( ) ,
119- ) ,
120- ) ;
121- } else {
122- // With index layout we need to traverse an unmodified bottom node.
123- next_subtrees. push ( bottom_subtree)
124- }
125- continue ;
126- }
127-
128- if let Some ( ref mut leaves) = previous_leaves {
129- leaves. extend (
130- previously_empty_leaves_indices
131- . iter ( )
132- . map ( |idx| ( * idx, L :: default ( ) ) )
133- . collect :: < HashMap < NodeIndex , L > > ( ) ,
134- ) ;
135- }
136- log_warning_for_empty_leaves (
137- & previously_empty_leaves_indices,
138- leaf_modifications,
139- config,
140- ) ?;
141-
142- handle_subtree (
143- skeleton_tree,
144- & mut next_subtrees,
145- bottom_subtree,
146- bottom_data,
147- should_fetch_modified_leaves,
148- ) ;
149- }
150- // Leaf node.
151- NodeData :: Leaf ( previous_leaf) => {
152- if subtree. is_unmodified ( ) {
153- skeleton_tree. nodes . insert (
154- subtree. get_root_index ( ) ,
155- OriginalSkeletonNode :: UnmodifiedSubTree ( filled_root. hash ) ,
156- ) ;
157- } else {
158- let root_index = subtree. get_root_index ( ) ;
159- // Modified leaf.
160- if config. compare_modified_leaves ( )
161- && L :: compare ( leaf_modifications, & root_index, & previous_leaf) ?
162- {
163- log_trivial_modification ! ( root_index, previous_leaf) ;
164- }
165- // If previous values of modified leaves are requested, add this leaf.
166- if let Some ( ref mut leaves) = previous_leaves {
167- leaves. insert ( root_index, previous_leaf) ;
168- }
169- }
170- }
171- }
172- }
173- current_subtrees = next_subtrees;
174- next_subtrees = Vec :: new ( ) ;
175- }
176- Ok ( ( ) )
177- }
178-
179- pub async fn create_original_skeleton_tree < ' a , L : Leaf > (
180- storage : & mut impl Storage ,
181- root_hash : HashOutput ,
182- sorted_leaf_indices : SortedLeafIndices < ' a > ,
183- config : & impl OriginalSkeletonTreeConfig < L > ,
184- leaf_modifications : & LeafModifications < L > ,
185- key_context : & <L as HasStaticPrefix >:: KeyContext ,
186- ) -> OriginalSkeletonTreeResult < OriginalSkeletonTreeImpl < ' a > > {
187- if sorted_leaf_indices. is_empty ( ) {
188- return Ok ( OriginalSkeletonTreeImpl :: create_unmodified ( root_hash) ) ;
189- }
190- if root_hash == HashOutput :: ROOT_OF_EMPTY_TREE {
191- log_warning_for_empty_leaves (
192- sorted_leaf_indices. get_indices ( ) ,
193- leaf_modifications,
194- config,
195- ) ?;
196- return Ok ( OriginalSkeletonTreeImpl :: create_empty ( sorted_leaf_indices) ) ;
197- }
198- let main_subtree = FactsSubTree { sorted_leaf_indices, root_index : NodeIndex :: ROOT , root_hash } ;
199- let mut skeleton_tree = OriginalSkeletonTreeImpl { nodes : HashMap :: new ( ) , sorted_leaf_indices } ;
200- fetch_nodes :: < L , FactsNodeLayout , FactsSubTree < ' a > > (
201- & mut skeleton_tree,
202- vec ! [ main_subtree] ,
203- storage,
204- leaf_modifications,
205- config,
206- None ,
207- key_context,
208- )
209- . await ?;
210- Ok ( skeleton_tree)
211- }
212-
213- 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 = EmptyKeyContext > ,
26+ > (
21427 storage : & mut impl Storage ,
21528 root_hash : HashOutput ,
21629 sorted_leaf_indices : SortedLeafIndices < ' a > ,
21730 leaf_modifications : & LeafModifications < L > ,
218- config : & impl OriginalSkeletonTreeConfig < L > ,
219- key_context : & <L as HasStaticPrefix >:: KeyContext ,
31+ config : & impl OriginalSkeletonTreeConfig ,
22032) -> OriginalSkeletonTreeResult < ( OriginalSkeletonTreeImpl < ' a > , HashMap < NodeIndex , L > ) > {
22133 if sorted_leaf_indices. is_empty ( ) {
22234 let unmodified = OriginalSkeletonTreeImpl :: create_unmodified ( root_hash) ;
@@ -231,94 +43,33 @@ pub async fn create_original_skeleton_tree_and_get_previous_leaves<'a, L: Leaf>(
23143 let main_subtree = FactsSubTree { sorted_leaf_indices, root_index : NodeIndex :: ROOT , root_hash } ;
23244 let mut skeleton_tree = OriginalSkeletonTreeImpl { nodes : HashMap :: new ( ) , sorted_leaf_indices } ;
23345 let mut leaves = HashMap :: new ( ) ;
234- fetch_nodes :: < L , FactsNodeLayout , FactsSubTree < ' a > > (
46+ fetch_nodes :: < L , FactsNodeLayout > (
23547 & mut skeleton_tree,
23648 vec ! [ main_subtree] ,
23749 storage,
23850 leaf_modifications,
23951 config,
24052 Some ( & mut leaves) ,
241- key_context ,
53+ & EmptyKeyContext ,
24254 )
24355 . await ?;
24456 Ok ( ( skeleton_tree, leaves) )
24557}
24658
247- pub async fn get_leaves < ' a , L : Leaf > (
59+ pub async fn get_leaves < ' a , L : Leaf + HasStaticPrefix < KeyContext = EmptyKeyContext > > (
24860 storage : & mut impl Storage ,
24961 root_hash : HashOutput ,
25062 sorted_leaf_indices : SortedLeafIndices < ' a > ,
251- key_context : & <L as HasStaticPrefix >:: KeyContext ,
25263) -> OriginalSkeletonTreeResult < HashMap < NodeIndex , L > > {
253- let config = NoCompareOriginalSkeletonTrieConfig :: default ( ) ;
64+ let config = OriginalSkeletonTrieDontCompareConfig ;
25465 let leaf_modifications = LeafModifications :: new ( ) ;
25566 let ( _, previous_leaves) = create_original_skeleton_tree_and_get_previous_leaves (
25667 storage,
25768 root_hash,
25869 sorted_leaf_indices,
25970 & leaf_modifications,
26071 & config,
261- key_context,
26272 )
26373 . await ?;
26474 Ok ( previous_leaves)
26575}
266-
267- /// Handles a subtree referred by an edge or a binary node. Decides whether we deserialize the
268- /// referred subtree or not.
269- fn handle_subtree < ' a , SubTree : SubTreeTrait < ' a > > (
270- skeleton_tree : & mut OriginalSkeletonTreeImpl < ' a > ,
271- next_subtrees : & mut Vec < SubTree > ,
272- subtree : SubTree ,
273- subtree_data : SubTree :: NodeData ,
274- should_fetch_modified_leaves : bool ,
275- ) {
276- let is_leaf = subtree. is_leaf ( ) ;
277- let is_unmodified = subtree. is_unmodified ( ) ;
278-
279- // 1. Internal node → always traverse.
280- if !is_leaf {
281- next_subtrees. push ( subtree) ;
282- return ;
283- }
284-
285- // 2. Modified leaf.
286- if !is_unmodified {
287- if should_fetch_modified_leaves {
288- next_subtrees. push ( subtree) ;
289- }
290- return ;
291- }
292-
293- // 3. Unmodified leaf sibling.
294- if !SubTree :: should_traverse_unmodified_children ( ) {
295- skeleton_tree. nodes . insert (
296- subtree. get_root_index ( ) ,
297- OriginalSkeletonNode :: UnmodifiedSubTree (
298- SubTree :: unmodified_child_hash ( subtree_data) . unwrap ( ) ,
299- ) ,
300- ) ;
301- } else {
302- next_subtrees. push ( subtree) ;
303- }
304- }
305-
306- /// Given leaf indices that were previously empty leaves, logs out a warning for trivial
307- /// modification if a leaf is modified to an empty leaf.
308- /// If this check is suppressed by configuration, does nothing.
309- fn log_warning_for_empty_leaves < L : Leaf , T : Borrow < NodeIndex > + Debug > (
310- leaf_indices : & [ T ] ,
311- leaf_modifications : & LeafModifications < L > ,
312- config : & impl OriginalSkeletonTreeConfig < L > ,
313- ) -> OriginalSkeletonTreeResult < ( ) > {
314- if !config. compare_modified_leaves ( ) {
315- return Ok ( ( ) ) ;
316- }
317- let empty_leaf = L :: default ( ) ;
318- for leaf_index in leaf_indices {
319- if L :: compare ( leaf_modifications, leaf_index. borrow ( ) , & empty_leaf) ? {
320- log_trivial_modification ! ( leaf_index, empty_leaf) ;
321- }
322- }
323- Ok ( ( ) )
324- }
0 commit comments