|
| 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