Skip to content

Commit 248c834

Browse files
committed
index layout forest creation tests
1 parent 5a9ce35 commit 248c834

File tree

3 files changed

+194
-18
lines changed

3 files changed

+194
-18
lines changed

crates/starknet_committer/src/db/index_db/create_index_tree_test.rs

Lines changed: 21 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ pub async fn convert_facts_db_to_index_db<FactsLeaf, IndexLeaf>(
3535
storage: &mut MapStorage,
3636
root_hash: HashOutput,
3737
trie_type: Option<TrieType>,
38+
current_leaves: &mut Option<Vec<(NodeIndex, FactsLeaf)>>,
3839
) -> MapStorage
3940
where
4041
FactsLeaf: Leaf + Into<IndexLeaf> + HasStaticPrefix<KeyContext = EmptyKeyContext>,
@@ -49,6 +50,7 @@ where
4950
NodeIndex::ROOT,
5051
root_hash,
5152
&trie_type,
53+
current_leaves,
5254
)
5355
.await;
5456
index_layout_storage
@@ -61,11 +63,16 @@ async fn convert_facts_to_index_layout_inner<FactsLeaf, IndexLeaf>(
6163
current_root_index: NodeIndex,
6264
current_root_hash: HashOutput,
6365
trie_type: &TrieType,
66+
current_leaves: &mut Option<Vec<(NodeIndex, FactsLeaf)>>,
6467
) where
6568
FactsLeaf: Leaf + Into<IndexLeaf> + HasStaticPrefix<KeyContext = EmptyKeyContext>,
6669
IndexLeaf: Leaf + HasStaticPrefix<KeyContext = TrieType>,
6770
TreeHashFunctionImpl: TreeHashFunction<IndexLeaf>,
6871
{
72+
println!("index: {:?}, hash: {:?}", current_root_index, current_root_hash);
73+
if current_root_hash == HashOutput::ROOT_OF_EMPTY_TREE {
74+
return;
75+
}
6976
let db_prefix = if current_root_index.is_leaf() {
7077
FactsLeaf::get_static_prefix(&EmptyKeyContext)
7178
} else {
@@ -92,6 +99,7 @@ async fn convert_facts_to_index_layout_inner<FactsLeaf, IndexLeaf>(
9299
children_indices[0],
93100
binary_data.left_data,
94101
trie_type,
102+
current_leaves,
95103
)
96104
.await;
97105
convert_facts_to_index_layout_inner::<FactsLeaf, IndexLeaf>(
@@ -100,6 +108,7 @@ async fn convert_facts_to_index_layout_inner<FactsLeaf, IndexLeaf>(
100108
children_indices[1],
101109
binary_data.right_data,
102110
trie_type,
111+
current_leaves,
103112
)
104113
.await;
105114
IndexFilledNode(FilledNode {
@@ -116,6 +125,7 @@ async fn convert_facts_to_index_layout_inner<FactsLeaf, IndexLeaf>(
116125
bottom_index,
117126
edge_data.bottom_data,
118127
trie_type,
128+
current_leaves,
119129
)
120130
.await;
121131
IndexFilledNode(FilledNode {
@@ -126,10 +136,16 @@ async fn convert_facts_to_index_layout_inner<FactsLeaf, IndexLeaf>(
126136
}),
127137
})
128138
}
129-
NodeData::Leaf(leaf) => IndexFilledNode(FilledNode {
130-
hash: current_root_hash,
131-
data: NodeData::Leaf(leaf.into()),
132-
}),
139+
NodeData::Leaf(leaf) => {
140+
if let Some(leaves) = current_leaves {
141+
leaves.push((current_root_index, leaf.clone()));
142+
}
143+
144+
IndexFilledNode(FilledNode {
145+
hash: current_root_hash,
146+
data: NodeData::Leaf(leaf.into()),
147+
})
148+
}
133149
};
134150

135151
let index_db_key =
@@ -158,6 +174,7 @@ async fn test_create_tree_index_layout(
158174
&mut case.storage,
159175
case.root_hash,
160176
Some(TrieType::StorageTrie(ContractAddress::from(0_u128))),
177+
&mut None,
161178
)
162179
.await;
163180

crates/starknet_committer/src/forest/skeleton_forest_test.rs

Lines changed: 148 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,10 @@ use std::collections::HashMap;
22

33
use pretty_assertions::assert_eq;
44
use rstest::rstest;
5+
use rstest_reuse::{apply, template};
56
use starknet_api::core::{ClassHash, ContractAddress, Nonce};
67
use starknet_api::hash::{HashOutput, StateRoots};
8+
use starknet_patricia::db_layout::TrieType;
79
use 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};
2123
use starknet_patricia_storage::map_storage::MapStorage;
2224
use starknet_patricia_storage::storage_trait::{DbHashMap, DbKey, DbValue};
2325
use starknet_types_core::felt::Felt;
26+
use starknet_types_core::hash::StarkHash;
2427

2528
use crate::block_committer::commit::get_all_modified_indices;
2629
use 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::{
3439
use crate::db::facts_db::db::FactsDb;
3540
use crate::db::facts_db::types::FactsDbInitialRead;
3641
use 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+
};
3749
use crate::forest::original_skeleton_forest::{ForestSortedIndices, OriginalSkeletonForest};
3850
use crate::patricia_merkle_tree::leaf::leaf_impl::ContractState;
3951
use 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+
358494
fn create_contract_leaves(leaves: &[(u128, u128)]) -> HashMap<ContractAddress, ContractState> {
359495
leaves
360496
.iter()

crates/starknet_committer/src/hash_function/hash.rs

Lines changed: 25 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,22 @@ impl TreeHashFunction<ContractState> for TreeHashFunctionImpl {
5656

5757
impl TreeHashFunction<IndexLayoutContractState> for TreeHashFunctionImpl {
5858
fn compute_leaf_hash(contract_state: &IndexLayoutContractState) -> HashOutput {
59-
compute_contract_state_leaf_hash(contract_state)
59+
#[cfg(not(test))]
60+
{
61+
compute_contract_state_leaf_hash(contract_state)
62+
}
63+
#[cfg(test)]
64+
{
65+
use starknet_patricia::patricia_merkle_tree::external_test_utils::AdditionHash;
66+
HashOutput(AdditionHash::hash_array(
67+
vec![
68+
contract_state.0.class_hash.0,
69+
contract_state.0.storage_root_hash.0,
70+
contract_state.0.nonce.0,
71+
]
72+
.as_slice(),
73+
))
74+
}
6075
}
6176
fn compute_node_hash(node_data: &NodeData<IndexLayoutContractState, HashOutput>) -> HashOutput {
6277
Self::compute_node_hash_with_inner_hash_function::<PedersenHashFunction>(node_data)
@@ -90,7 +105,15 @@ impl TreeHashFunction<CompiledClassHash> for TreeHashFunctionImpl {
90105

91106
impl TreeHashFunction<IndexLayoutCompiledClassHash> for TreeHashFunctionImpl {
92107
fn compute_leaf_hash(compiled_class_hash: &IndexLayoutCompiledClassHash) -> HashOutput {
93-
compute_compiled_class_leaf_hash(compiled_class_hash)
108+
#[cfg(not(test))]
109+
{
110+
compute_compiled_class_leaf_hash(compiled_class_hash)
111+
}
112+
#[cfg(test)]
113+
{
114+
use starknet_patricia::patricia_merkle_tree::external_test_utils::AdditionHash;
115+
HashOutput(AdditionHash::hash_array(vec![compiled_class_hash.0.0].as_slice()))
116+
}
94117
}
95118
fn compute_node_hash(
96119
node_data: &NodeData<IndexLayoutCompiledClassHash, HashOutput>,

0 commit comments

Comments
 (0)