Skip to content

Commit 758fa5e

Browse files
committed
starknet_committer: abstract original tree creation
1 parent 38f3023 commit 758fa5e

File tree

5 files changed

+81
-45
lines changed

5 files changed

+81
-45
lines changed

crates/starknet_committer/src/db/db_layout.rs

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,7 @@ use starknet_patricia_storage::db_object::{DBObject, HasStaticPrefix};
77
use crate::db::index_db::leaves::TrieType;
88

99
/// Specifies the trie db layout.
10-
pub trait NodeLayout<'a, L: Leaf>
11-
where
12-
FilledNode<L, Self::NodeData>: DBObject<DeserializeContext = Self::DeserializationContext>,
13-
{
10+
pub trait NodeLayout<'a, L: Leaf> {
1411
/// Additional data that a node stores about its children.
1512
type NodeData: Clone + From<HashOutput>;
1613

crates/starknet_committer/src/db/external_test_utils.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ use starknet_patricia::patricia_merkle_tree::updated_skeleton_tree::tree::{
1818
use starknet_patricia_storage::db_object::{EmptyKeyContext, HasStaticPrefix};
1919
use starknet_patricia_storage::map_storage::MapStorage;
2020

21+
use crate::db::facts_db::db::FactsNodeLayout;
2122
use crate::db::trie_traversal::create_original_skeleton_tree;
2223

2324
// TODO(Ariel, 14/12/2025): make this generic over the layout.
@@ -33,7 +34,7 @@ where
3334
{
3435
let mut sorted_leaf_indices: Vec<NodeIndex> = leaf_modifications.keys().copied().collect();
3536
let sorted_leaf_indices = SortedLeafIndices::new(&mut sorted_leaf_indices);
36-
let mut original_skeleton = create_original_skeleton_tree(
37+
let mut original_skeleton = create_original_skeleton_tree::<L, FactsNodeLayout>(
3738
storage,
3839
root_hash,
3940
sorted_leaf_indices,

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

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ use starknet_patricia_storage::map_storage::MapStorage;
2222
use starknet_patricia_storage::storage_trait::{DbHashMap, DbKey, DbValue};
2323
use starknet_types_core::felt::Felt;
2424

25+
use crate::db::facts_db::db::FactsNodeLayout;
2526
use crate::db::trie_traversal::create_original_skeleton_tree;
2627
use crate::patricia_merkle_tree::tree::OriginalSkeletonTrieConfig;
2728

@@ -211,7 +212,7 @@ async fn test_create_tree(
211212
let config = OriginalSkeletonTrieConfig::new_for_tests(compare_modified_leaves);
212213
let mut sorted_leaf_indices: Vec<NodeIndex> = leaf_modifications.keys().copied().collect();
213214
let sorted_leaf_indices = SortedLeafIndices::new(&mut sorted_leaf_indices);
214-
let skeleton_tree = create_original_skeleton_tree(
215+
let skeleton_tree = create_original_skeleton_tree::<MockLeaf, FactsNodeLayout>(
215216
&mut storage,
216217
root_hash,
217218
sorted_leaf_indices,

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

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -84,21 +84,22 @@ impl<S: Storage> ForestReader<FactsDbInitialRead> for FactsDb<S> {
8484
forest_sorted_indices: &'a ForestSortedIndices<'a>,
8585
config: ReaderConfig,
8686
) -> ForestResult<(OriginalSkeletonForest<'a>, HashMap<NodeIndex, ContractState>)> {
87-
let (contracts_trie, original_contracts_trie_leaves) = create_contracts_trie(
88-
&mut self.storage,
89-
context.0.contracts_trie_root_hash,
90-
forest_sorted_indices.contracts_trie_sorted_indices,
91-
)
92-
.await?;
93-
let storage_tries = create_storage_tries(
87+
let (contracts_trie, original_contracts_trie_leaves) =
88+
create_contracts_trie::<ContractState, FactsNodeLayout>(
89+
&mut self.storage,
90+
context.0.contracts_trie_root_hash,
91+
forest_sorted_indices.contracts_trie_sorted_indices,
92+
)
93+
.await?;
94+
let storage_tries = create_storage_tries::<StarknetStorageValue, FactsNodeLayout>(
9495
&mut self.storage,
9596
storage_updates,
9697
&original_contracts_trie_leaves,
9798
&config,
9899
&forest_sorted_indices.storage_tries_sorted_indices,
99100
)
100101
.await?;
101-
let classes_trie = create_classes_trie(
102+
let classes_trie = create_classes_trie::<CompiledClassHash, FactsNodeLayout>(
102103
&mut self.storage,
103104
classes_updates,
104105
context.0.classes_trie_root_hash,

crates/starknet_committer/src/db/trie_traversal.rs

Lines changed: 67 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ use starknet_patricia::patricia_merkle_tree::traversal::{
2323
UnmodifiedChildTraversal,
2424
};
2525
use starknet_patricia::patricia_merkle_tree::types::{NodeIndex, SortedLeafIndices};
26-
use starknet_patricia_storage::db_object::{DBObject, EmptyKeyContext, HasStaticPrefix};
26+
use starknet_patricia_storage::db_object::{DBObject, HasStaticPrefix};
2727
use starknet_patricia_storage::errors::StorageError;
2828
use starknet_patricia_storage::storage_trait::{create_db_key, DbKey, Storage};
2929
use tracing::warn;
@@ -34,9 +34,7 @@ use crate::block_committer::input::{
3434
StarknetStorageValue,
3535
};
3636
use crate::db::db_layout::NodeLayout;
37-
use crate::db::facts_db::create_facts_tree::create_original_skeleton_tree_and_get_previous_leaves;
38-
use crate::db::facts_db::db::FactsNodeLayout;
39-
use crate::db::facts_db::types::FactsSubTree;
37+
use crate::db::index_db::leaves::TrieType;
4038
use crate::forest::forest_errors::{ForestError, ForestResult};
4139
use crate::patricia_merkle_tree::leaf::leaf_impl::ContractState;
4240
use crate::patricia_merkle_tree::tree::OriginalSkeletonTrieConfig;
@@ -57,7 +55,7 @@ macro_rules! log_trivial_modification {
5755
///
5856
/// The function is generic over the DB layout (`Layout`), which controls the concrete node data
5957
/// (`Layout::NodeData`) and traversal strategy (via `Layout::SubTree`).
60-
pub async fn fetch_nodes<'a, L, Layout>(
58+
pub(crate) async fn fetch_nodes<'a, L, Layout>(
6159
skeleton_tree: &mut OriginalSkeletonTreeImpl<'a>,
6260
subtrees: Vec<Layout::SubTree>,
6361
storage: &mut impl Storage,
@@ -69,7 +67,6 @@ pub async fn fetch_nodes<'a, L, Layout>(
6967
where
7068
L: Leaf,
7169
Layout: NodeLayout<'a, L>,
72-
FilledNode<L, Layout::NodeData>: DBObject<DeserializeContext = Layout::DeserializationContext>,
7370
{
7471
let mut current_subtrees = subtrees;
7572
let mut next_subtrees = Vec::new();
@@ -247,10 +244,7 @@ pub async fn get_roots_from_storage<'a, L: Leaf, Layout: NodeLayout<'a, L>>(
247244
subtrees: &[Layout::SubTree],
248245
storage: &mut impl Storage,
249246
key_context: &<L as HasStaticPrefix>::KeyContext,
250-
) -> TraversalResult<Vec<FilledNode<L, Layout::NodeData>>>
251-
where
252-
FilledNode<L, Layout::NodeData>: DBObject<DeserializeContext = Layout::DeserializationContext>,
253-
{
247+
) -> TraversalResult<Vec<FilledNode<L, Layout::NodeData>>> {
254248
let mut subtrees_roots = vec![];
255249
let db_keys: Vec<DbKey> = subtrees
256250
.iter()
@@ -262,7 +256,10 @@ where
262256
let db_vals = storage.mget(&db_keys.iter().collect::<Vec<&DbKey>>()).await?;
263257
for ((subtree, optional_val), db_key) in subtrees.iter().zip(db_vals.iter()).zip(db_keys) {
264258
let Some(val) = optional_val else { Err(StorageError::MissingKey(db_key))? };
265-
let filled_node = FilledNode::deserialize(val, &subtree.get_root_context())?;
259+
let filled_node = Layout::get_filled_node(Layout::NodeDbObject::deserialize(
260+
val,
261+
&subtree.get_root_context(),
262+
)?);
266263
subtrees_roots.push(filled_node);
267264
}
268265
Ok(subtrees_roots)
@@ -288,10 +285,7 @@ pub(crate) fn log_warning_for_empty_leaves<L: Leaf, T: Borrow<NodeIndex> + Debug
288285
Ok(())
289286
}
290287

291-
pub async fn create_original_skeleton_tree<
292-
'a,
293-
L: Leaf + HasStaticPrefix<KeyContext = EmptyKeyContext>,
294-
>(
288+
pub async fn create_original_skeleton_tree<'a, L: Leaf, Layout: NodeLayout<'a, L>>(
295289
storage: &mut impl Storage,
296290
root_hash: HashOutput,
297291
sorted_leaf_indices: SortedLeafIndices<'a>,
@@ -308,11 +302,12 @@ pub async fn create_original_skeleton_tree<
308302
leaf_modifications,
309303
config,
310304
)?;
311-
return Ok(OriginalSkeletonTreeImpl::create_empty(sorted_leaf_indices));
305+
return Ok(handle_empty_subtree::<L>(sorted_leaf_indices).0);
312306
}
313-
let main_subtree = FactsSubTree::create(sorted_leaf_indices, NodeIndex::ROOT, root_hash);
307+
let main_subtree =
308+
Layout::SubTree::create(sorted_leaf_indices, NodeIndex::ROOT, root_hash.into());
314309
let mut skeleton_tree = OriginalSkeletonTreeImpl { nodes: HashMap::new(), sorted_leaf_indices };
315-
fetch_nodes::<L, FactsNodeLayout>(
310+
fetch_nodes::<L, Layout>(
316311
&mut skeleton_tree,
317312
vec![main_subtree],
318313
storage,
@@ -325,7 +320,11 @@ pub async fn create_original_skeleton_tree<
325320
Ok(skeleton_tree)
326321
}
327322

328-
pub async fn create_storage_tries<'a>(
323+
pub async fn create_storage_tries<
324+
'a,
325+
L: Leaf + From<StarknetStorageValue>,
326+
Layout: NodeLayout<'a, L>,
327+
>(
329328
storage: &mut impl Storage,
330329
actual_storage_updates: &HashMap<ContractAddress, LeafModifications<StarknetStorageValue>>,
331330
original_contracts_trie_leaves: &HashMap<NodeIndex, ContractState>,
@@ -344,13 +343,13 @@ pub async fn create_storage_tries<'a>(
344343
config.warn_on_trivial_modifications(),
345344
);
346345

347-
let original_skeleton = create_original_skeleton_tree(
346+
let original_skeleton = create_original_skeleton_tree::<L, Layout>(
348347
storage,
349348
contract_state.storage_root_hash,
350349
*sorted_leaf_indices,
351350
&config,
352-
updates,
353-
&EmptyKeyContext,
351+
&updates.iter().map(|(idx, value)| (*idx, L::from(*value))).collect(),
352+
&Layout::generate_key_context(TrieType::StorageTrie(*address)),
354353
)
355354
.await?;
356355
storage_tries.insert(*address, original_skeleton);
@@ -360,22 +359,50 @@ pub async fn create_storage_tries<'a>(
360359

361360
/// Creates the contracts trie original skeleton.
362361
/// Also returns the previous contracts state of the modified contracts.
363-
pub async fn create_contracts_trie<'a>(
362+
pub async fn create_contracts_trie<'a, L: Leaf + Into<ContractState>, Layout: NodeLayout<'a, L>>(
364363
storage: &mut impl Storage,
365364
contracts_trie_root_hash: HashOutput,
366365
contracts_trie_sorted_indices: SortedLeafIndices<'a>,
367366
) -> ForestResult<(OriginalSkeletonTreeImpl<'a>, HashMap<NodeIndex, ContractState>)> {
368-
Ok(create_original_skeleton_tree_and_get_previous_leaves(
369-
storage,
370-
contracts_trie_root_hash,
367+
if contracts_trie_sorted_indices.is_empty() {
368+
let unmodified = OriginalSkeletonTreeImpl::create_unmodified(contracts_trie_root_hash);
369+
return Ok((unmodified, HashMap::new()));
370+
}
371+
if contracts_trie_root_hash == HashOutput::ROOT_OF_EMPTY_TREE {
372+
return Ok(handle_empty_subtree(contracts_trie_sorted_indices));
373+
}
374+
let main_subtree = Layout::SubTree::create(
371375
contracts_trie_sorted_indices,
376+
NodeIndex::ROOT,
377+
contracts_trie_root_hash.into(),
378+
);
379+
let mut skeleton_tree = OriginalSkeletonTreeImpl {
380+
nodes: HashMap::new(),
381+
sorted_leaf_indices: contracts_trie_sorted_indices,
382+
};
383+
let mut leaves = HashMap::new();
384+
fetch_nodes::<L, Layout>(
385+
&mut skeleton_tree,
386+
vec![main_subtree],
387+
storage,
372388
&HashMap::new(),
373389
&OriginalSkeletonTrieConfig::new_for_contracts_trie(),
390+
Some(&mut leaves),
391+
&Layout::generate_key_context(TrieType::ContractsTrie),
374392
)
375-
.await?)
393+
.await?;
394+
395+
let leaves: HashMap<NodeIndex, ContractState> =
396+
leaves.into_iter().map(|(idx, leaf)| (idx, leaf.into())).collect();
397+
398+
Ok((skeleton_tree, leaves))
376399
}
377400

378-
pub async fn create_classes_trie<'a>(
401+
pub async fn create_classes_trie<
402+
'a,
403+
L: Leaf + From<CompiledClassHash>,
404+
Layout: NodeLayout<'a, L>,
405+
>(
379406
storage: &mut impl Storage,
380407
actual_classes_updates: &LeafModifications<CompiledClassHash>,
381408
classes_trie_root_hash: HashOutput,
@@ -386,13 +413,22 @@ pub async fn create_classes_trie<'a>(
386413
config.warn_on_trivial_modifications(),
387414
);
388415

389-
Ok(create_original_skeleton_tree(
416+
Ok(create_original_skeleton_tree::<L, Layout>(
390417
storage,
391418
classes_trie_root_hash,
392419
contracts_trie_sorted_indices,
393420
&config,
394-
actual_classes_updates,
395-
&EmptyKeyContext,
421+
&actual_classes_updates.iter().map(|(idx, value)| (*idx, L::from(*value))).collect(),
422+
&Layout::generate_key_context(TrieType::ClassesTrie),
396423
)
397424
.await?)
398425
}
426+
427+
pub(crate) fn handle_empty_subtree<'a, L: Leaf>(
428+
sorted_leaf_indices: SortedLeafIndices<'a>,
429+
) -> (OriginalSkeletonTreeImpl<'a>, HashMap<NodeIndex, L>) {
430+
(
431+
OriginalSkeletonTreeImpl::create_empty(sorted_leaf_indices),
432+
sorted_leaf_indices.get_indices().iter().map(|idx| (*idx, L::default())).collect(),
433+
)
434+
}

0 commit comments

Comments
 (0)