@@ -2,8 +2,10 @@ use std::collections::HashMap;
22
33use pretty_assertions::assert_eq;
44use rstest::rstest;
5+ use rstest_reuse::{apply, template};
56use starknet_api::core::{ClassHash, ContractAddress, Nonce};
67use starknet_api::hash::{HashOutput, StateRoots};
8+ use starknet_patricia::db_layout::TrieType;
79use starknet_patricia::patricia_merkle_tree::external_test_utils::{
810 create_32_bytes_entry,
911 create_binary_entry_from_u128,
@@ -21,11 +23,14 @@ use starknet_patricia_storage::db_object::{DBObject, EmptyKeyContext};
2123use starknet_patricia_storage::map_storage::MapStorage;
2224use starknet_patricia_storage::storage_trait::{DbHashMap, DbKey, DbValue};
2325use starknet_types_core::felt::Felt;
26+ use starknet_types_core::hash::StarkHash;
2427
2528use crate::block_committer::commit::get_all_modified_indices;
2629use crate::block_committer::input::{
2730 contract_address_into_node_index,
31+ try_node_index_into_contract_address,
2832 Input,
33+ InputContext,
2934 ReaderConfig,
3035 StarknetStorageKey,
3136 StarknetStorageValue,
@@ -34,6 +39,13 @@ use crate::block_committer::input::{
3439use crate::db::facts_db::db::FactsDb;
3540use crate::db::facts_db::types::FactsDbInitialRead;
3641use crate::db::forest_trait::ForestReader;
42+ use crate::db::index_db::create_index_tree_test::convert_facts_db_to_index_db;
43+ use crate::db::index_db::db::IndexDb;
44+ use crate::db::index_db::leaves::{
45+ IndexLayoutCompiledClassHash,
46+ IndexLayoutContractState,
47+ IndexLayoutStarknetStorageValue,
48+ };
3749use crate::forest::original_skeleton_forest::{ForestSortedIndices, OriginalSkeletonForest};
3850use crate::patricia_merkle_tree::leaf::leaf_impl::ContractState;
3951use crate::patricia_merkle_tree::types::CompiledClassHash;
@@ -58,14 +70,24 @@ pub(crate) fn create_compiled_class_leaf_entry(val: u128) -> (DbKey, DbValue) {
5870 (leaf.get_db_key(&EmptyKeyContext, &leaf.0.to_bytes_be()), leaf.serialize().unwrap())
5971}
6072
61- pub(crate) fn create_contract_state_leaf_entry(val: u128) -> (DbKey, DbValue) {
62- let felt = Felt::from(val);
73+ pub(crate) fn create_contract_state_leaf_entry(
74+ nonce: u128,
75+ storage_root: u128,
76+ class_hash: u128,
77+ hash: Option<u128>,
78+ ) -> (DbKey, DbValue) {
79+ let (nonce, storage_root, class_hash) =
80+ (Felt::from(nonce), Felt::from(storage_root), Felt::from(class_hash));
6381 let leaf = ContractState {
64- nonce: Nonce(felt ),
65- storage_root_hash: HashOutput(felt ),
66- class_hash: ClassHash(felt ),
82+ nonce: Nonce(nonce ),
83+ storage_root_hash: HashOutput(storage_root ),
84+ class_hash: ClassHash(class_hash ),
6785 };
68- (leaf.get_db_key(&EmptyKeyContext, &felt.to_bytes_be()), leaf.serialize().unwrap())
86+ let mut hash = hash.map(Felt::from);
87+ if hash.is_none() {
88+ hash = Some(AdditionHash::hash_array(&[class_hash, storage_root, nonce]));
89+ }
90+ (leaf.get_db_key(&EmptyKeyContext, &hash.unwrap().to_bytes_be()), leaf.serialize().unwrap())
6991}
7092
7193// This test uses addition hash for simplicity (i.e hash(a,b) = a + b).
@@ -130,7 +152,7 @@ pub(crate) fn create_contract_state_leaf_entry(val: u128) -> (DbKey, DbValue) {
130152/// / \ \ \ / \ \ \
131153/// NZ 2 NZ NZ NZ 9 16 15
132154
133- #[tokio::test ]
155+ #[template ]
134156#[rstest]
135157#[case(
136158 Input {
@@ -162,9 +184,11 @@ pub(crate) fn create_contract_state_leaf_entry(val: u128) -> (DbKey, DbValue) {
162184 create_edge_entry_from_u128::<AdditionHash>(554, 1, 1),
163185 create_binary_entry_from_u128::<AdditionHash>(305, 556),
164186 // Contracts trie leaves.
165- create_contract_state_leaf_entry(277),
166- create_contract_state_leaf_entry(303),
167- create_contract_state_leaf_entry(1),
187+ // TODO(Ariel): Why both layouts pass when we lie about the hash?
188+ // probably becaues the original skeleton doesn't care about these hashes (there were modifications).
189+ create_contract_state_leaf_entry(277, 277, 277, Some(277)),
190+ create_contract_state_leaf_entry(303, 303, 303, Some(303)),
191+ create_contract_state_leaf_entry(0, 0, 1, None),
168192 // Classes trie inner nodes.
169193 create_binary_entry_from_u128::<AdditionHash>(33, 47),
170194 create_edge_entry_from_u128::<AdditionHash>(72, 1, 1),
@@ -295,17 +319,85 @@ pub(crate) fn create_contract_state_leaf_entry(val: u128) -> (DbKey, DbValue) {
295319 vec![6, 7, 0],
296320 vec![7, 6, 0],
297321)]
298- async fn test_create_original_skeleton_forest(
322+ fn create_original_skeleton_forest_cases(
323+ #[case] input: Input<FactsDbInitialRead>,
324+ #[case] storage: MapStorage,
325+ #[case] expected_forest: OriginalSkeletonForest<'_>,
326+ #[case] expected_original_contracts_trie_leaves: HashMap<ContractAddress, ContractState>,
327+ #[case] expected_storage_tries_sorted_indices: HashMap<u128, Vec<u128>>,
328+ #[case] expected_contracts_trie_sorted_indices: Vec<u128>,
329+ #[case] expected_classes_trie_sorted_indices: Vec<u128>,
330+ ) {
331+ }
332+
333+ #[apply(create_original_skeleton_forest_cases)]
334+ #[rstest]
335+ #[tokio::test]
336+ async fn test_create_original_skeleton_forest_facts_layout(
299337 #[case] input: Input<FactsDbInitialRead>,
300338 #[case] storage: MapStorage,
301339 #[case] expected_forest: OriginalSkeletonForest<'_>,
302340 #[case] expected_original_contracts_trie_leaves: HashMap<ContractAddress, ContractState>,
303341 #[case] expected_storage_tries_sorted_indices: HashMap<u128, Vec<u128>>,
304342 #[case] expected_contracts_trie_sorted_indices: Vec<u128>,
305343 #[case] expected_classes_trie_sorted_indices: Vec<u128>,
344+ ) {
345+ test_create_original_skeleton_forest::<FactsDbInitialRead, FactsDb<MapStorage>>(
346+ input,
347+ storage,
348+ expected_forest,
349+ expected_original_contracts_trie_leaves,
350+ expected_storage_tries_sorted_indices,
351+ expected_contracts_trie_sorted_indices,
352+ expected_classes_trie_sorted_indices,
353+ |storage| FactsDb::new(storage),
354+ )
355+ .await;
356+ }
357+
358+ #[apply(create_original_skeleton_forest_cases)]
359+ #[rstest]
360+ #[tokio::test]
361+ async fn test_create_original_skeleton_forest_index_layout(
362+ #[case] input: Input<FactsDbInitialRead>,
363+ #[case] mut storage: MapStorage,
364+ #[case] expected_forest: OriginalSkeletonForest<'_>,
365+ #[case] expected_original_contracts_trie_leaves: HashMap<ContractAddress, ContractState>,
366+ #[case] expected_storage_tries_sorted_indices: HashMap<u128, Vec<u128>>,
367+ #[case] expected_contracts_trie_sorted_indices: Vec<u128>,
368+ #[case] expected_classes_trie_sorted_indices: Vec<u128>,
369+ ) {
370+ let index_storage =
371+ convert_facts_forest_db_to_index_db(&mut storage, input.initial_read_context.0).await;
372+ test_create_original_skeleton_forest::<FactsDbInitialRead, IndexDb<MapStorage>>(
373+ input,
374+ index_storage,
375+ expected_forest,
376+ expected_original_contracts_trie_leaves,
377+ expected_storage_tries_sorted_indices,
378+ expected_contracts_trie_sorted_indices,
379+ expected_classes_trie_sorted_indices,
380+ |storage| IndexDb::new(storage),
381+ )
382+ .await;
383+ }
384+
385+ async fn test_create_original_skeleton_forest<
386+ ReaderInputContext: InputContext,
387+ Reader: ForestReader<ReaderInputContext>,
388+ >(
389+ input: Input<ReaderInputContext>,
390+ storage: MapStorage,
391+ expected_forest: OriginalSkeletonForest<'_>,
392+ expected_original_contracts_trie_leaves: HashMap<ContractAddress, ContractState>,
393+ expected_storage_tries_sorted_indices: HashMap<u128, Vec<u128>>,
394+ expected_contracts_trie_sorted_indices: Vec<u128>,
395+ expected_classes_trie_sorted_indices: Vec<u128>,
396+ reader_generator: impl FnOnce(MapStorage) -> Reader,
306397) {
307398 let (mut storage_tries_indices, mut contracts_trie_indices, mut classes_trie_indices) =
308399 get_all_modified_indices(&input.state_diff);
400+
309401 let forest_sorted_indices = ForestSortedIndices {
310402 storage_tries_sorted_indices: storage_tries_indices
311403 .iter_mut()
@@ -317,7 +409,8 @@ async fn test_create_original_skeleton_forest(
317409
318410 let actual_storage_updates = input.state_diff.actual_storage_updates();
319411 let actual_classes_updates = input.state_diff.actual_classes_updates();
320- let (actual_forest, original_contracts_trie_leaves) = FactsDb::new(storage)
412+ let mut reader = reader_generator(storage);
413+ let (actual_forest, original_contracts_trie_leaves) = reader
321414 .read(
322415 input.initial_read_context,
323416 &actual_storage_updates,
@@ -355,6 +448,49 @@ async fn test_create_original_skeleton_forest(
355448 }
356449}
357450
451+ async fn convert_facts_forest_db_to_index_db(
452+ storage: &mut MapStorage,
453+ roots: StateRoots,
454+ ) -> MapStorage {
455+ let mut contract_leaves: Option<Vec<(NodeIndex, ContractState)>> = Some(Vec::new());
456+ let mut index_storage =
457+ convert_facts_db_to_index_db::<ContractState, IndexLayoutContractState>(
458+ storage,
459+ roots.contracts_trie_root_hash,
460+ Some(TrieType::ContractsTrie),
461+ &mut contract_leaves,
462+ )
463+ .await
464+ .0;
465+
466+ for (index, contract_leaf) in contract_leaves.unwrap() {
467+ println!("storage tries conversion");
468+ let contract_address = try_node_index_into_contract_address(&index).unwrap();
469+ let storage_root = contract_leaf.storage_root_hash;
470+ let contract_storage_entries =
471+ convert_facts_db_to_index_db::<StarknetStorageValue, IndexLayoutStarknetStorageValue>(
472+ storage,
473+ storage_root,
474+ Some(TrieType::StorageTrie(contract_address)),
475+ &mut None,
476+ )
477+ .await;
478+ index_storage.extend(contract_storage_entries.0);
479+ }
480+
481+ let classes_storage =
482+ convert_facts_db_to_index_db::<CompiledClassHash, IndexLayoutCompiledClassHash>(
483+ storage,
484+ roots.classes_trie_root_hash,
485+ Some(TrieType::ClassesTrie),
486+ &mut None,
487+ )
488+ .await;
489+ index_storage.extend(classes_storage.0);
490+
491+ MapStorage(index_storage)
492+ }
493+
358494fn create_contract_leaves(leaves: &[(u128, u128)]) -> HashMap<ContractAddress, ContractState> {
359495 leaves
360496 .iter()
0 commit comments