Skip to content

Commit b05aac9

Browse files
committed
starknet_committer: add original tree creation test templates
1 parent 4e2cfa8 commit b05aac9

File tree

5 files changed

+307
-233
lines changed

5 files changed

+307
-233
lines changed

Cargo.lock

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

crates/starknet_committer/Cargo.toml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,6 @@ hex.workspace = true
1919
pretty_assertions.workspace = true
2020
rand.workspace = true
2121
rand_distr.workspace = true
22-
rstest.workspace = true
2322
serde = { workspace = true, features = ["derive"] }
2423
serde_json.workspace = true
2524
starknet-types-core = { workspace = true, features = ["hash", "papyrus-serialization"] }
@@ -32,6 +31,8 @@ tokio = { workspace = true, features = ["rt"] }
3231
tracing.workspace = true
3332

3433
[dev-dependencies]
34+
rstest.workspace = true
35+
rstest_reuse.workspace = true
3536
starknet_api = { workspace = true, features = ["testing"] }
3637
starknet_patricia = { workspace = true, features = ["testing"] }
3738

crates/starknet_committer/src/db.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
#[cfg(test)]
2+
pub mod create_original_skeleton_tests;
13
pub mod db_layout;
24
#[cfg(any(feature = "testing", test))]
35
pub mod external_test_utils;
Lines changed: 283 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,283 @@
1+
use std::collections::HashMap;
2+
3+
use rstest_reuse::template;
4+
use starknet_api::hash::HashOutput;
5+
use starknet_patricia::db_layout::NodeLayout;
6+
use starknet_patricia::patricia_merkle_tree::external_test_utils::{
7+
create_binary_entry_from_u128,
8+
create_binary_skeleton_node,
9+
create_edge_entry_from_u128,
10+
create_edge_skeleton_node,
11+
create_expected_skeleton_nodes,
12+
create_root_edge_entry,
13+
create_unmodified_subtree_skeleton_node,
14+
AdditionHash,
15+
MockLeaf,
16+
};
17+
use starknet_patricia::patricia_merkle_tree::node_data::leaf::{Leaf, LeafModifications};
18+
use starknet_patricia::patricia_merkle_tree::original_skeleton_tree::node::OriginalSkeletonNode;
19+
use starknet_patricia::patricia_merkle_tree::types::{NodeIndex, SortedLeafIndices, SubTreeHeight};
20+
use starknet_patricia_storage::db_object::{DBObject, EmptyKeyContext, HasStaticPrefix};
21+
use starknet_patricia_storage::map_storage::MapStorage;
22+
use starknet_patricia_storage::storage_trait::{DbHashMap, DbKey, DbValue};
23+
use starknet_types_core::felt::Felt;
24+
25+
use crate::db::trie_traversal::create_original_skeleton_tree;
26+
use crate::patricia_merkle_tree::tree::OriginalSkeletonTrieConfig;
27+
28+
pub(crate) fn create_mock_leaf_entry(val: u128) -> (DbKey, DbValue) {
29+
let leaf = MockLeaf(Felt::from(val));
30+
(leaf.get_db_key(&EmptyKeyContext, &leaf.0.to_bytes_be()), leaf.serialize().unwrap())
31+
}
32+
33+
fn create_mock_leaf_modifications(
34+
leaf_modifications: Vec<(u128, u128)>,
35+
) -> LeafModifications<MockLeaf> {
36+
leaf_modifications
37+
.into_iter()
38+
.map(|(idx, val)| (NodeIndex::from(idx), MockLeaf(Felt::from(val))))
39+
.collect()
40+
}
41+
42+
pub(crate) struct CreateTreeCase {
43+
pub storage: MapStorage,
44+
pub leaf_modifications: LeafModifications<MockLeaf>,
45+
pub root_hash: HashOutput,
46+
pub expected_skeleton_nodes: HashMap<NodeIndex, OriginalSkeletonNode>,
47+
pub subtree_height: SubTreeHeight,
48+
}
49+
50+
pub(crate) fn simple_tree_of_height_3() -> CreateTreeCase {
51+
CreateTreeCase {
52+
storage: MapStorage(DbHashMap::from([
53+
create_root_edge_entry(50, SubTreeHeight::new(3)),
54+
create_binary_entry_from_u128::<AdditionHash>(8, 9),
55+
create_edge_entry_from_u128::<AdditionHash>(11, 1, 1),
56+
create_binary_entry_from_u128::<AdditionHash>(17, 13),
57+
create_edge_entry_from_u128::<AdditionHash>(15, 3, 2),
58+
create_binary_entry_from_u128::<AdditionHash>(30, 20),
59+
create_mock_leaf_entry(8),
60+
create_mock_leaf_entry(9),
61+
create_mock_leaf_entry(11),
62+
create_mock_leaf_entry(15),
63+
])),
64+
leaf_modifications: create_mock_leaf_modifications(vec![(8, 8), (10, 3), (13, 2)]),
65+
root_hash: HashOutput(Felt::from(50_u128 + 248_u128)),
66+
expected_skeleton_nodes: create_expected_skeleton_nodes(
67+
vec![
68+
create_binary_skeleton_node(1),
69+
create_binary_skeleton_node(2),
70+
create_edge_skeleton_node(3, 3, 2),
71+
create_binary_skeleton_node(4),
72+
create_edge_skeleton_node(5, 1, 1),
73+
create_unmodified_subtree_skeleton_node(9, 9),
74+
create_unmodified_subtree_skeleton_node(15, 15),
75+
create_unmodified_subtree_skeleton_node(11, 11),
76+
],
77+
3,
78+
),
79+
subtree_height: SubTreeHeight::new(3),
80+
}
81+
}
82+
83+
pub(crate) fn another_simple_tree_of_height_3() -> CreateTreeCase {
84+
CreateTreeCase {
85+
storage: MapStorage(DbHashMap::from([
86+
create_root_edge_entry(29, SubTreeHeight::new(3)),
87+
create_binary_entry_from_u128::<AdditionHash>(10, 2),
88+
create_edge_entry_from_u128::<AdditionHash>(3, 1, 1),
89+
create_binary_entry_from_u128::<AdditionHash>(4, 7),
90+
create_edge_entry_from_u128::<AdditionHash>(12, 0, 1),
91+
create_binary_entry_from_u128::<AdditionHash>(5, 11),
92+
create_binary_entry_from_u128::<AdditionHash>(13, 16),
93+
create_mock_leaf_entry(10),
94+
create_mock_leaf_entry(2),
95+
create_mock_leaf_entry(3),
96+
create_mock_leaf_entry(4),
97+
create_mock_leaf_entry(7),
98+
])),
99+
leaf_modifications: create_mock_leaf_modifications(vec![(8, 5), (11, 1), (13, 3)]),
100+
root_hash: HashOutput(Felt::from(29_u128 + 248_u128)),
101+
expected_skeleton_nodes: create_expected_skeleton_nodes(
102+
vec![
103+
create_binary_skeleton_node(1),
104+
create_edge_skeleton_node(2, 0, 1),
105+
create_binary_skeleton_node(3),
106+
create_binary_skeleton_node(4),
107+
create_edge_skeleton_node(6, 1, 1),
108+
create_unmodified_subtree_skeleton_node(7, 11),
109+
create_unmodified_subtree_skeleton_node(9, 2),
110+
],
111+
3,
112+
),
113+
subtree_height: SubTreeHeight::new(3),
114+
}
115+
}
116+
117+
pub(crate) fn tree_of_height_4_with_long_edge() -> CreateTreeCase {
118+
CreateTreeCase {
119+
storage: MapStorage(DbHashMap::from([
120+
create_root_edge_entry(116, SubTreeHeight::new(4)),
121+
create_binary_entry_from_u128::<AdditionHash>(11, 13),
122+
create_edge_entry_from_u128::<AdditionHash>(5, 0, 1),
123+
create_binary_entry_from_u128::<AdditionHash>(19, 40),
124+
create_edge_entry_from_u128::<AdditionHash>(20, 3, 2),
125+
create_binary_entry_from_u128::<AdditionHash>(6, 59),
126+
create_edge_entry_from_u128::<AdditionHash>(24, 0, 2),
127+
create_binary_entry_from_u128::<AdditionHash>(25, 65),
128+
create_binary_entry_from_u128::<AdditionHash>(26, 90),
129+
create_mock_leaf_entry(11),
130+
create_mock_leaf_entry(13),
131+
create_mock_leaf_entry(20),
132+
create_mock_leaf_entry(5),
133+
create_mock_leaf_entry(19),
134+
create_mock_leaf_entry(40),
135+
])),
136+
leaf_modifications: create_mock_leaf_modifications(vec![
137+
(18, 5),
138+
(25, 1),
139+
(29, 15),
140+
(30, 19),
141+
]),
142+
root_hash: HashOutput(Felt::from(116_u128 + 247_u128)),
143+
expected_skeleton_nodes: create_expected_skeleton_nodes(
144+
vec![
145+
create_binary_skeleton_node(1),
146+
create_edge_skeleton_node(2, 0, 2),
147+
create_binary_skeleton_node(3),
148+
create_edge_skeleton_node(6, 3, 2),
149+
create_binary_skeleton_node(7),
150+
create_unmodified_subtree_skeleton_node(8, 24),
151+
create_edge_skeleton_node(14, 0, 1),
152+
create_binary_skeleton_node(15),
153+
create_unmodified_subtree_skeleton_node(27, 20),
154+
create_unmodified_subtree_skeleton_node(28, 5),
155+
create_unmodified_subtree_skeleton_node(31, 40),
156+
],
157+
4,
158+
),
159+
subtree_height: SubTreeHeight::new(4),
160+
}
161+
}
162+
163+
pub(crate) async fn test_create_original_skeleton<L, Layout>(
164+
storage: &mut MapStorage,
165+
leaf_modifications: &LeafModifications<L>,
166+
root_hash: HashOutput,
167+
expected_skeleton_nodes: &HashMap<NodeIndex, OriginalSkeletonNode>,
168+
subtree_height: SubTreeHeight,
169+
compare_modified_leaves: bool,
170+
) where
171+
L: Leaf + HasStaticPrefix<KeyContext = EmptyKeyContext>,
172+
Layout: for<'a> NodeLayout<'a, L>,
173+
{
174+
let leaf_modifications: LeafModifications<L> = leaf_modifications
175+
.iter()
176+
.map(|(idx, leaf)| (NodeIndex::from_subtree_index(*idx, subtree_height), leaf.clone()))
177+
.collect();
178+
179+
let config = OriginalSkeletonTrieConfig::new_for_tests(compare_modified_leaves);
180+
181+
let mut sorted_leaf_indices: Vec<NodeIndex> = leaf_modifications.keys().copied().collect();
182+
let sorted_leaf_indices = SortedLeafIndices::new(&mut sorted_leaf_indices);
183+
184+
let skeleton_tree = create_original_skeleton_tree::<L, Layout>(
185+
storage,
186+
root_hash,
187+
sorted_leaf_indices,
188+
&config,
189+
&leaf_modifications,
190+
None,
191+
&EmptyKeyContext,
192+
)
193+
.await
194+
.unwrap();
195+
196+
assert_eq!(&skeleton_tree.nodes, expected_skeleton_nodes);
197+
}
198+
199+
#[template]
200+
#[rstest]
201+
// This test uses addition hash for simplicity (i.e hash(a,b) = a + b).
202+
/// Old tree structure:
203+
///
204+
/// 50
205+
/// / \
206+
/// 30 20
207+
/// / \ \
208+
/// 17 13 *
209+
/// / \ \ \
210+
/// 8 9 11 15
211+
///
212+
/// Modified leaves indices: [8, 10, 13]
213+
///
214+
/// Expected skeleton:
215+
///
216+
/// B
217+
/// / \
218+
/// B E
219+
/// / \ \
220+
/// B E *
221+
/// / \ \ \
222+
/// NZ 9 11 15
223+
224+
#[case::simple_tree_of_height_3(
225+
crate::db::create_original_skeleton_tests::simple_tree_of_height_3()
226+
)]
227+
/// Old tree structure:
228+
///
229+
/// 29
230+
/// / \
231+
/// 13 16
232+
/// / / \
233+
/// 12 5 11
234+
/// / \ \ / \
235+
/// 10 2 3 4 7
236+
///
237+
/// Modified leaves indices: [8, 11, 13]
238+
///
239+
/// Expected skeleton:
240+
///
241+
/// B
242+
/// / \
243+
/// E B
244+
/// / / \
245+
/// B E E
246+
/// / \ \ \
247+
/// NZ 2 NZ NZ
248+
#[case::another_simple_tree_of_height_3(
249+
crate::db::create_original_skeleton_tests::another_simple_tree_of_height_3()
250+
)]
251+
/// Old tree structure:
252+
///
253+
/// 116
254+
/// / \
255+
/// 26 90
256+
/// / / \
257+
/// / 25 65
258+
/// / \ / \
259+
/// 24 \ 6 59
260+
/// / \ \ / / \
261+
/// 11 13 20 5 19 40
262+
///
263+
/// Modified leaves indices: [18, 25, 29, 30]
264+
///
265+
/// Expected skeleton:
266+
///
267+
/// B
268+
/// / \
269+
/// E B
270+
/// / / \
271+
/// / E B
272+
/// / \ / \
273+
/// 24 \ E B
274+
/// \ / \
275+
/// 20 5 40
276+
#[case::tree_of_height_4_with_long_edge(
277+
crate::db::create_original_skeleton_tests::tree_of_height_4_with_long_edge()
278+
)]
279+
pub fn create_tree_cases(
280+
#[case] mut case: CreateTreeCase,
281+
#[values(true, false)] compare_modified_leaves: bool,
282+
) {
283+
}

0 commit comments

Comments
 (0)