Skip to content

Commit ee606a2

Browse files
committed
starknet_committer,starknet_patricia: add subtree trait
1 parent 47514f7 commit ee606a2

File tree

7 files changed

+148
-79
lines changed

7 files changed

+148
-79
lines changed

crates/starknet_committer/src/db/facts_db/create_facts_tree.rs

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -18,12 +18,13 @@ use starknet_patricia::patricia_merkle_tree::original_skeleton_tree::tree::{
1818
OriginalSkeletonTreeImpl,
1919
OriginalSkeletonTreeResult,
2020
};
21-
use starknet_patricia::patricia_merkle_tree::traversal::SubTree;
21+
use starknet_patricia::patricia_merkle_tree::traversal::SubTreeTrait;
2222
use starknet_patricia::patricia_merkle_tree::types::{NodeIndex, SortedLeafIndices};
2323
use starknet_patricia_storage::storage_trait::Storage;
2424
use tracing::warn;
2525

2626
use crate::db::facts_db::traversal::calculate_subtrees_roots;
27+
use crate::db::facts_db::types::FactsSubTree;
2728

2829
#[cfg(test)]
2930
#[path = "create_facts_tree_test.rs"]
@@ -42,7 +43,7 @@ macro_rules! log_trivial_modification {
4243
/// encountering a trivial modification. Fills the previous leaf values if it is not none.
4344
async fn fetch_nodes<'a, L: Leaf>(
4445
skeleton_tree: &mut OriginalSkeletonTreeImpl<'a>,
45-
subtrees: Vec<SubTree<'a>>,
46+
subtrees: Vec<FactsSubTree<'a>>,
4647
storage: &mut impl Storage,
4748
leaf_modifications: &LeafModifications<L>,
4849
config: &impl OriginalSkeletonTreeConfig<L>,
@@ -101,7 +102,7 @@ async fn fetch_nodes<'a, L: Leaf>(
101102
leaves.extend(
102103
previously_empty_leaves_indices
103104
.iter()
104-
.map(|idx| (**idx, L::default()))
105+
.map(|idx| (*idx, L::default()))
105106
.collect::<HashMap<NodeIndex, L>>(),
106107
);
107108
}
@@ -161,7 +162,7 @@ pub async fn create_original_skeleton_tree<'a, L: Leaf>(
161162
)?;
162163
return Ok(OriginalSkeletonTreeImpl::create_empty(sorted_leaf_indices));
163164
}
164-
let main_subtree = SubTree { sorted_leaf_indices, root_index: NodeIndex::ROOT, root_hash };
165+
let main_subtree = FactsSubTree { sorted_leaf_indices, root_index: NodeIndex::ROOT, root_hash };
165166
let mut skeleton_tree = OriginalSkeletonTreeImpl { nodes: HashMap::new(), sorted_leaf_indices };
166167
fetch_nodes::<L>(
167168
&mut skeleton_tree,
@@ -192,7 +193,7 @@ pub async fn create_original_skeleton_tree_and_get_previous_leaves<'a, L: Leaf>(
192193
sorted_leaf_indices.get_indices().iter().map(|idx| (*idx, L::default())).collect(),
193194
));
194195
}
195-
let main_subtree = SubTree { sorted_leaf_indices, root_index: NodeIndex::ROOT, root_hash };
196+
let main_subtree = FactsSubTree { sorted_leaf_indices, root_index: NodeIndex::ROOT, root_hash };
196197
let mut skeleton_tree = OriginalSkeletonTreeImpl { nodes: HashMap::new(), sorted_leaf_indices };
197198
let mut leaves = HashMap::new();
198199
fetch_nodes::<L>(
@@ -229,8 +230,8 @@ pub async fn get_leaves<'a, L: Leaf>(
229230
/// referred subtree or not.
230231
fn handle_subtree<'a>(
231232
skeleton_tree: &mut OriginalSkeletonTreeImpl<'a>,
232-
next_subtrees: &mut Vec<SubTree<'a>>,
233-
subtree: SubTree<'a>,
233+
next_subtrees: &mut Vec<FactsSubTree<'a>>,
234+
subtree: FactsSubTree<'a>,
234235
should_fetch_modified_leaves: bool,
235236
) {
236237
if !subtree.is_leaf() || (should_fetch_modified_leaves && !subtree.is_unmodified()) {

crates/starknet_committer/src/db/facts_db/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,3 +2,4 @@ pub mod create_facts_tree;
22
// TODO(Ariel): Move db.rs to this module and avoid db::fact_db::db path..
33
pub mod db;
44
pub mod traversal;
5+
pub mod types;

crates/starknet_committer/src/db/facts_db/traversal.rs

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -8,18 +8,20 @@ use starknet_patricia::patricia_merkle_tree::node_data::inner_node::{
88
PreimageMap,
99
};
1010
use starknet_patricia::patricia_merkle_tree::node_data::leaf::Leaf;
11-
use starknet_patricia::patricia_merkle_tree::traversal::{SubTree, TraversalResult};
11+
use starknet_patricia::patricia_merkle_tree::traversal::{SubTreeTrait, TraversalResult};
1212
use starknet_patricia::patricia_merkle_tree::types::{NodeIndex, SortedLeafIndices};
1313
use starknet_patricia_storage::errors::StorageError;
1414
use starknet_patricia_storage::storage_trait::{create_db_key, DbKey, Storage};
1515

16+
use crate::db::facts_db::types::FactsSubTree;
17+
1618
#[cfg(test)]
1719
#[path = "traversal_test.rs"]
1820
pub mod traversal_test;
1921

2022
// TODO(Aviv, 17/07/2024): Split between storage prefix implementation and function logic.
2123
pub async fn calculate_subtrees_roots<'a, L: Leaf>(
22-
subtrees: &[SubTree<'a>],
24+
subtrees: &[FactsSubTree<'a>],
2325
storage: &mut impl Storage,
2426
) -> TraversalResult<Vec<FilledNode<L>>> {
2527
let mut subtrees_roots = vec![];
@@ -54,7 +56,7 @@ pub async fn fetch_patricia_paths<L: Leaf>(
5456
return Ok(witnesses);
5557
}
5658

57-
let main_subtree = SubTree { sorted_leaf_indices, root_index: NodeIndex::ROOT, root_hash };
59+
let main_subtree = FactsSubTree { sorted_leaf_indices, root_index: NodeIndex::ROOT, root_hash };
5860

5961
fetch_patricia_paths_inner::<L>(storage, vec![main_subtree], &mut witnesses, leaves).await?;
6062
Ok(witnesses)
@@ -67,9 +69,9 @@ pub async fn fetch_patricia_paths<L: Leaf>(
6769
/// inner nodes in their paths.
6870
/// If `leaves` is not `None`, it also fetches the modified leaves and inserts them into the
6971
/// provided map.
70-
async fn fetch_patricia_paths_inner<'a, L: Leaf>(
72+
pub(crate) async fn fetch_patricia_paths_inner<'a, L: Leaf>(
7173
storage: &mut impl Storage,
72-
subtrees: Vec<SubTree<'a>>,
74+
subtrees: Vec<FactsSubTree<'a>>,
7375
witnesses: &mut PreimageMap,
7476
mut leaves: Option<&mut HashMap<NodeIndex, L>>,
7577
) -> TraversalResult<()> {
@@ -103,7 +105,7 @@ async fn fetch_patricia_paths_inner<'a, L: Leaf>(
103105
// Insert empty leaves descendent of the current subtree, that are not
104106
// descendents of the bottom node.
105107
for index in empty_leaves_indices {
106-
leaves_map.insert(*index, L::default());
108+
leaves_map.insert(index, L::default());
107109
}
108110
}
109111
next_subtrees.push(bottom_subtree);

crates/starknet_committer/src/db/facts_db/traversal_test.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,14 +25,15 @@ use starknet_patricia::patricia_merkle_tree::node_data::inner_node::{
2525
Preimage,
2626
PreimageMap,
2727
};
28-
use starknet_patricia::patricia_merkle_tree::traversal::SubTree;
28+
use starknet_patricia::patricia_merkle_tree::traversal::SubTreeTrait;
2929
use starknet_patricia::patricia_merkle_tree::types::{SortedLeafIndices, SubTreeHeight};
3030
use starknet_patricia_storage::map_storage::MapStorage;
3131
use starknet_patricia_storage::storage_trait::{DbHashMap, DbKey, DbValue};
3232
use starknet_types_core::felt::Felt;
3333
use starknet_types_core::hash::Pedersen;
3434

3535
use crate::db::facts_db::traversal::fetch_patricia_paths_inner;
36+
use crate::db::facts_db::types::FactsSubTree;
3637

3738
fn to_preimage_map(raw_preimages: HashMap<u32, Vec<u32>>) -> PreimageMap {
3839
raw_preimages
@@ -73,7 +74,7 @@ async fn test_fetch_patricia_paths_inner_impl(
7374
.iter()
7475
.map(|&idx| small_tree_index_to_full(U256::from(idx), height))
7576
.collect::<Vec<_>>();
76-
let main_subtree = SubTree {
77+
let main_subtree = FactsSubTree {
7778
sorted_leaf_indices: SortedLeafIndices::new(&mut leaf_indices),
7879
root_index: small_tree_index_to_full(U256::ONE, height),
7980
root_hash,
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
use starknet_api::hash::HashOutput;
2+
use starknet_patricia::patricia_merkle_tree::filled_tree::node_serde::PatriciaPrefix;
3+
use starknet_patricia::patricia_merkle_tree::node_data::leaf::Leaf;
4+
use starknet_patricia::patricia_merkle_tree::traversal::SubTreeTrait;
5+
use starknet_patricia::patricia_merkle_tree::types::{NodeIndex, SortedLeafIndices};
6+
7+
#[derive(Debug, PartialEq)]
8+
pub struct FactsSubTree<'a> {
9+
pub sorted_leaf_indices: SortedLeafIndices<'a>,
10+
pub root_index: NodeIndex,
11+
pub root_hash: HashOutput,
12+
}
13+
14+
impl<'a> SubTreeTrait<'a> for FactsSubTree<'a> {
15+
type ChildData = HashOutput;
16+
17+
fn create_child(
18+
sorted_leaf_indices: SortedLeafIndices<'a>,
19+
root_index: NodeIndex,
20+
child_data: Self::ChildData,
21+
) -> Self {
22+
Self { sorted_leaf_indices, root_index, root_hash: child_data }
23+
}
24+
25+
fn get_root_index(&self) -> NodeIndex {
26+
self.root_index
27+
}
28+
29+
fn get_sorted_leaf_indices(&self) -> &SortedLeafIndices<'a> {
30+
&self.sorted_leaf_indices
31+
}
32+
33+
fn should_traverse_unmodified_children() -> bool {
34+
false
35+
}
36+
}
37+
38+
impl<'a> FactsSubTree<'a> {
39+
pub fn get_root_prefix<L: Leaf>(&self) -> PatriciaPrefix {
40+
if self.is_leaf() {
41+
PatriciaPrefix::Leaf(L::get_static_prefix())
42+
} else {
43+
PatriciaPrefix::InnerNode
44+
}
45+
}
46+
}
Lines changed: 46 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,8 @@
1-
use starknet_api::hash::HashOutput;
21
use starknet_patricia_storage::errors::{DeserializationError, StorageError};
32
use starknet_patricia_storage::storage_trait::PatriciaStorageError;
43
use thiserror::Error;
54

6-
use crate::patricia_merkle_tree::filled_tree::node_serde::PatriciaPrefix;
75
use crate::patricia_merkle_tree::node_data::inner_node::PathToBottom;
8-
use crate::patricia_merkle_tree::node_data::leaf::Leaf;
96
use crate::patricia_merkle_tree::original_skeleton_tree::utils::split_leaves;
107
use crate::patricia_merkle_tree::types::{NodeIndex, SortedLeafIndices, SubTreeHeight};
118

@@ -25,88 +22,83 @@ pub enum TraversalError {
2522

2623
pub type TraversalResult<T> = Result<T, TraversalError>;
2724

28-
#[derive(Debug, PartialEq)]
29-
pub struct SubTree<'a> {
30-
pub sorted_leaf_indices: SortedLeafIndices<'a>,
31-
pub root_index: NodeIndex,
32-
pub root_hash: HashOutput,
33-
}
25+
// The SubTreeTrait allows traversing a trie without knowledge of the concrete node types and data.
26+
pub trait SubTreeTrait<'a>: Sized {
27+
// A node can carry data about its children (e.g. their hashes).
28+
type ChildData: Copy;
3429

35-
impl<'a> SubTree<'a> {
36-
pub(crate) fn get_height(&self) -> SubTreeHeight {
37-
SubTreeHeight::new(SubTreeHeight::ACTUAL_HEIGHT.0 - (self.root_index.bit_length() - 1))
38-
}
30+
// Creates a concrete child node given its index and data.
31+
fn create_child(
32+
sorted_leaf_indices: SortedLeafIndices<'a>,
33+
root_index: NodeIndex,
34+
child_data: Self::ChildData,
35+
) -> Self;
36+
37+
fn get_root_index(&self) -> NodeIndex;
3938

40-
pub(crate) fn split_leaves(&self) -> [SortedLeafIndices<'a>; 2] {
41-
split_leaves(&self.root_index, &self.sorted_leaf_indices)
39+
fn get_sorted_leaf_indices(&self) -> &SortedLeafIndices<'a>;
40+
41+
fn get_height(&self) -> SubTreeHeight {
42+
SubTreeHeight::new(
43+
SubTreeHeight::ACTUAL_HEIGHT.0 - (self.get_root_index().bit_length() - 1),
44+
)
4245
}
4346

44-
pub fn is_unmodified(&self) -> bool {
45-
self.sorted_leaf_indices.is_empty()
47+
fn split_leaves(&self) -> [SortedLeafIndices<'a>; 2] {
48+
split_leaves(&self.get_root_index(), self.get_sorted_leaf_indices())
4649
}
4750

48-
pub fn get_root_prefix<L: Leaf>(&self) -> PatriciaPrefix {
49-
if self.is_leaf() {
50-
PatriciaPrefix::Leaf(L::get_static_prefix())
51-
} else {
52-
PatriciaPrefix::InnerNode
53-
}
51+
fn is_unmodified(&self) -> bool {
52+
self.get_sorted_leaf_indices().is_empty()
5453
}
5554

5655
/// Returns the bottom subtree which is referred from `self` by the given path. When creating
5756
/// the bottom subtree some indices that were modified under `self` are not modified under the
5857
/// bottom subtree (leaves that were previously empty). These indices are returned as well.
59-
pub fn get_bottom_subtree(
58+
fn get_bottom_subtree(
6059
&self,
6160
path_to_bottom: &PathToBottom,
62-
bottom_hash: HashOutput,
63-
) -> (Self, Vec<&NodeIndex>) {
64-
let bottom_index = path_to_bottom.bottom_index(self.root_index);
61+
bottom_data: Self::ChildData,
62+
) -> (Self, Vec<NodeIndex>) {
63+
let sorted_leaf_indices = self.get_sorted_leaf_indices();
64+
let bottom_index = path_to_bottom.bottom_index(self.get_root_index());
6565
let bottom_height = self.get_height() - SubTreeHeight::new(path_to_bottom.length.into());
6666
let leftmost_in_subtree = bottom_index << bottom_height.into();
6767
let rightmost_in_subtree =
6868
leftmost_in_subtree - NodeIndex::ROOT + (NodeIndex::ROOT << bottom_height.into());
69-
let leftmost_index = self.sorted_leaf_indices.bisect_left(&leftmost_in_subtree);
70-
let rightmost_index = self.sorted_leaf_indices.bisect_right(&rightmost_in_subtree);
71-
let bottom_leaves = self.sorted_leaf_indices.subslice(leftmost_index, rightmost_index);
72-
let previously_empty_leaf_indices = self.sorted_leaf_indices.get_indices()
73-
[..leftmost_index]
69+
let leftmost_index = sorted_leaf_indices.bisect_left(&leftmost_in_subtree);
70+
let rightmost_index = sorted_leaf_indices.bisect_right(&rightmost_in_subtree);
71+
let bottom_leaves = sorted_leaf_indices.subslice(leftmost_index, rightmost_index);
72+
let previously_empty_leaf_indices = sorted_leaf_indices.get_indices()[..leftmost_index]
7473
.iter()
75-
.chain(self.sorted_leaf_indices.get_indices()[rightmost_index..].iter())
74+
.chain(sorted_leaf_indices.get_indices()[rightmost_index..].iter())
75+
.cloned()
7676
.collect();
7777

7878
(
79-
Self {
80-
sorted_leaf_indices: bottom_leaves,
81-
root_index: bottom_index,
82-
root_hash: bottom_hash,
83-
},
79+
Self::create_child(bottom_leaves, bottom_index, bottom_data),
8480
previously_empty_leaf_indices,
8581
)
8682
}
8783

88-
pub fn get_children_subtrees(
84+
fn get_children_subtrees(
8985
&self,
90-
left_hash: HashOutput,
91-
right_hash: HashOutput,
86+
left_data: Self::ChildData,
87+
right_data: Self::ChildData,
9288
) -> (Self, Self) {
9389
let [left_leaves, right_leaves] = self.split_leaves();
94-
let left_root_index = self.root_index * 2.into();
90+
let left_root_index = self.get_root_index() * 2.into();
9591
(
96-
SubTree {
97-
sorted_leaf_indices: left_leaves,
98-
root_index: left_root_index,
99-
root_hash: left_hash,
100-
},
101-
SubTree {
102-
sorted_leaf_indices: right_leaves,
103-
root_index: left_root_index + NodeIndex::ROOT,
104-
root_hash: right_hash,
105-
},
92+
Self::create_child(left_leaves, left_root_index, left_data),
93+
Self::create_child(right_leaves, left_root_index + NodeIndex::ROOT, right_data),
10694
)
10795
}
10896

109-
pub fn is_leaf(&self) -> bool {
110-
self.root_index.is_leaf()
97+
fn is_leaf(&self) -> bool {
98+
self.get_root_index().is_leaf()
11199
}
100+
101+
// Indicates whether unmodified children should be traversed during the construction of the
102+
// skeleton tree.
103+
fn should_traverse_unmodified_children() -> bool;
112104
}

0 commit comments

Comments
 (0)