Skip to content

Commit 38f3023

Browse files
committed
starknet_committer: enrich layout trait to abstract skeleton creation
1 parent ca220f7 commit 38f3023

File tree

10 files changed

+92
-66
lines changed

10 files changed

+92
-66
lines changed
Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,38 @@
1+
use starknet_api::hash::HashOutput;
12
use starknet_patricia::patricia_merkle_tree::filled_tree::node::FilledNode;
23
use starknet_patricia::patricia_merkle_tree::node_data::leaf::Leaf;
34
use starknet_patricia::patricia_merkle_tree::traversal::SubTreeTrait;
4-
use starknet_patricia_storage::db_object::DBObject;
5+
use starknet_patricia_storage::db_object::{DBObject, HasStaticPrefix};
6+
7+
use crate::db::index_db::leaves::TrieType;
58

69
/// Specifies the trie db layout.
710
pub trait NodeLayout<'a, L: Leaf>
811
where
912
FilledNode<L, Self::NodeData>: DBObject<DeserializeContext = Self::DeserializationContext>,
1013
{
1114
/// Additional data that a node stores about its children.
12-
type NodeData: Clone;
15+
type NodeData: Clone + From<HashOutput>;
1316

1417
/// The context needed to deserialize the node from a raw
1518
/// [starknet_patricia_storage::storage_trait::DbValue].
1619
type DeserializationContext;
1720

21+
/// The storage representation of the node.
22+
type NodeDbObject: DBObject<DeserializeContext = Self::DeserializationContext>;
23+
1824
/// The type of the subtree that is used to traverse the trie.
1925
type SubTree: SubTreeTrait<
2026
'a,
2127
NodeData = Self::NodeData,
2228
NodeDeserializeContext = Self::DeserializationContext,
2329
>;
30+
31+
/// Generates the key context for the given trie type. Used for reading nodes of a specific
32+
/// tree (contracts, classes, or storage), to construct a skeleton tree.
33+
fn generate_key_context(trie_type: TrieType) -> <L as HasStaticPrefix>::KeyContext;
34+
35+
/// Converts a node db object to a filled node. Used during the trie traversal for the skeleton
36+
/// construction.
37+
fn get_filled_node(node_db_object: Self::NodeDbObject) -> FilledNode<L, Self::NodeData>;
2438
}

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

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ use starknet_patricia::patricia_merkle_tree::original_skeleton_tree::tree::{
99
};
1010
use starknet_patricia::patricia_merkle_tree::traversal::SubTreeTrait;
1111
use starknet_patricia::patricia_merkle_tree::types::{NodeIndex, SortedLeafIndices};
12-
use starknet_patricia_storage::db_object::HasStaticPrefix;
12+
use starknet_patricia_storage::db_object::{EmptyKeyContext, HasStaticPrefix};
1313
use starknet_patricia_storage::storage_trait::Storage;
1414

1515
use crate::db::facts_db::db::FactsNodeLayout;
@@ -21,13 +21,15 @@ use crate::patricia_merkle_tree::tree::OriginalSkeletonTrieConfig;
2121
#[path = "create_facts_tree_test.rs"]
2222
pub mod create_facts_tree_test;
2323

24-
pub async fn create_original_skeleton_tree_and_get_previous_leaves<'a, L: Leaf>(
24+
pub async fn create_original_skeleton_tree_and_get_previous_leaves<
25+
'a,
26+
L: Leaf + HasStaticPrefix<KeyContext = EmptyKeyContext>,
27+
>(
2528
storage: &mut impl Storage,
2629
root_hash: HashOutput,
2730
sorted_leaf_indices: SortedLeafIndices<'a>,
2831
leaf_modifications: &LeafModifications<L>,
2932
config: &impl OriginalSkeletonTreeConfig,
30-
key_context: &<L as HasStaticPrefix>::KeyContext,
3133
) -> OriginalSkeletonTreeResult<(OriginalSkeletonTreeImpl<'a>, HashMap<NodeIndex, L>)> {
3234
if sorted_leaf_indices.is_empty() {
3335
let unmodified = OriginalSkeletonTreeImpl::create_unmodified(root_hash);
@@ -49,7 +51,7 @@ pub async fn create_original_skeleton_tree_and_get_previous_leaves<'a, L: Leaf>(
4951
leaf_modifications,
5052
config,
5153
Some(&mut leaves),
52-
key_context,
54+
&EmptyKeyContext,
5355
)
5456
.await?;
5557
Ok((skeleton_tree, leaves))
@@ -58,11 +60,10 @@ pub async fn create_original_skeleton_tree_and_get_previous_leaves<'a, L: Leaf>(
5860
/// Prepares the OS inputs by fetching paths to the given leaves (i.e. their induced Skeleton tree).
5961
/// Note that ATM, the Rust committer does not manage history and is not used for storage proofs;
6062
/// Thus, this function assumes facts layout.
61-
pub async fn get_leaves<'a, L: Leaf>(
63+
pub async fn get_leaves<'a, L: Leaf + HasStaticPrefix<KeyContext = EmptyKeyContext>>(
6264
storage: &mut impl Storage,
6365
root_hash: HashOutput,
6466
sorted_leaf_indices: SortedLeafIndices<'a>,
65-
key_context: &<L as HasStaticPrefix>::KeyContext,
6667
) -> OriginalSkeletonTreeResult<HashMap<NodeIndex, L>> {
6768
let config = OriginalSkeletonTrieConfig::default();
6869
let leaf_modifications = LeafModifications::new();
@@ -72,7 +73,6 @@ pub async fn get_leaves<'a, L: Leaf>(
7273
sorted_leaf_indices,
7374
&leaf_modifications,
7475
&config,
75-
key_context,
7676
)
7777
.await?;
7878
Ok(previous_leaves)

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

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,12 @@ use std::collections::HashMap;
33
use async_trait::async_trait;
44
use starknet_api::core::ContractAddress;
55
use starknet_api::hash::HashOutput;
6+
use starknet_patricia::patricia_merkle_tree::filled_tree::node::{FactDbFilledNode, FilledNode};
67
use starknet_patricia::patricia_merkle_tree::filled_tree::node_serde::FactNodeDeserializationContext;
78
use starknet_patricia::patricia_merkle_tree::filled_tree::tree::FilledTree;
89
use starknet_patricia::patricia_merkle_tree::node_data::leaf::{Leaf, LeafModifications};
910
use starknet_patricia::patricia_merkle_tree::types::NodeIndex;
10-
use starknet_patricia_storage::db_object::EmptyKeyContext;
11+
use starknet_patricia_storage::db_object::{EmptyKeyContext, HasStaticPrefix};
1112
use starknet_patricia_storage::errors::SerializationResult;
1213
use starknet_patricia_storage::map_storage::MapStorage;
1314
use starknet_patricia_storage::storage_trait::{DbHashMap, Storage};
@@ -16,6 +17,7 @@ use crate::block_committer::input::{ReaderConfig, StarknetStorageValue};
1617
use crate::db::db_layout::NodeLayout;
1718
use crate::db::facts_db::types::{FactsDbInitialRead, FactsSubTree};
1819
use crate::db::forest_trait::{ForestReader, ForestWriter};
20+
use crate::db::index_db::leaves::TrieType;
1921
use crate::db::trie_traversal::{create_classes_trie, create_contracts_trie, create_storage_tries};
2022
use crate::forest::filled_forest::FilledForest;
2123
use crate::forest::forest_errors::ForestResult;
@@ -30,12 +32,25 @@ use crate::patricia_merkle_tree::types::CompiledClassHash;
3032
/// have the db keys of its children.
3133
pub struct FactsNodeLayout {}
3234

33-
impl<'a, L: Leaf> NodeLayout<'a, L> for FactsNodeLayout {
35+
impl<'a, L: Leaf> NodeLayout<'a, L> for FactsNodeLayout
36+
where
37+
L: HasStaticPrefix<KeyContext = EmptyKeyContext>,
38+
{
3439
type NodeData = HashOutput;
3540

41+
type NodeDbObject = FactDbFilledNode<L>;
42+
3643
type DeserializationContext = FactNodeDeserializationContext;
3744

3845
type SubTree = FactsSubTree<'a>;
46+
47+
fn generate_key_context(_trie_type: TrieType) -> <L as HasStaticPrefix>::KeyContext {
48+
EmptyKeyContext
49+
}
50+
51+
fn get_filled_node(node_db_object: Self::NodeDbObject) -> FilledNode<L, Self::NodeData> {
52+
node_db_object
53+
}
3954
}
4055

4156
pub struct FactsDb<S: Storage> {

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

Lines changed: 13 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ use starknet_patricia::patricia_merkle_tree::node_data::inner_node::{
99
use starknet_patricia::patricia_merkle_tree::node_data::leaf::Leaf;
1010
use starknet_patricia::patricia_merkle_tree::traversal::{SubTreeTrait, TraversalResult};
1111
use starknet_patricia::patricia_merkle_tree::types::{NodeIndex, SortedLeafIndices};
12-
use starknet_patricia_storage::db_object::HasStaticPrefix;
12+
use starknet_patricia_storage::db_object::{EmptyKeyContext, HasStaticPrefix};
1313
use starknet_patricia_storage::storage_trait::Storage;
1414

1515
use crate::db::facts_db::db::FactsNodeLayout;
@@ -24,12 +24,11 @@ pub mod traversal_test;
2424
/// given tree according to the `root_hash`.
2525
/// If `leaves` is not `None`, it also fetches the modified leaves and inserts them into the
2626
/// provided map.
27-
pub async fn fetch_patricia_paths<L: Leaf>(
27+
pub async fn fetch_patricia_paths<L: Leaf + HasStaticPrefix<KeyContext = EmptyKeyContext>>(
2828
storage: &mut impl Storage,
2929
root_hash: HashOutput,
3030
sorted_leaf_indices: SortedLeafIndices<'_>,
3131
leaves: Option<&mut HashMap<NodeIndex, L>>,
32-
key_context: &<L as HasStaticPrefix>::KeyContext,
3332
) -> TraversalResult<PreimageMap> {
3433
let mut witnesses = PreimageMap::new();
3534

@@ -39,14 +38,7 @@ pub async fn fetch_patricia_paths<L: Leaf>(
3938

4039
let main_subtree = FactsSubTree::create(sorted_leaf_indices, NodeIndex::ROOT, root_hash);
4140

42-
fetch_patricia_paths_inner::<L>(
43-
storage,
44-
vec![main_subtree],
45-
&mut witnesses,
46-
leaves,
47-
key_context,
48-
)
49-
.await?;
41+
fetch_patricia_paths_inner::<L>(storage, vec![main_subtree], &mut witnesses, leaves).await?;
5042
Ok(witnesses)
5143
}
5244

@@ -59,19 +51,24 @@ pub async fn fetch_patricia_paths<L: Leaf>(
5951
/// inner nodes in their paths and their siblings.
6052
/// If `leaves` is not `None`, it also fetches the modified leaves and inserts them into the
6153
/// provided map.
62-
pub(crate) async fn fetch_patricia_paths_inner<'a, L: Leaf>(
54+
pub(crate) async fn fetch_patricia_paths_inner<
55+
'a,
56+
L: Leaf + HasStaticPrefix<KeyContext = EmptyKeyContext>,
57+
>(
6358
storage: &mut impl Storage,
6459
subtrees: Vec<FactsSubTree<'a>>,
6560
witnesses: &mut PreimageMap,
6661
mut leaves: Option<&mut HashMap<NodeIndex, L>>,
67-
key_context: &<L as HasStaticPrefix>::KeyContext,
6862
) -> TraversalResult<()> {
6963
let mut current_subtrees = subtrees;
7064
let mut next_subtrees = Vec::new();
7165
while !current_subtrees.is_empty() {
72-
let filled_roots =
73-
get_roots_from_storage::<L, FactsNodeLayout>(&current_subtrees, storage, key_context)
74-
.await?;
66+
let filled_roots = get_roots_from_storage::<L, FactsNodeLayout>(
67+
&current_subtrees,
68+
storage,
69+
&EmptyKeyContext,
70+
)
71+
.await?;
7572
for (filled_root, subtree) in filled_roots.into_iter().zip(current_subtrees.iter()) {
7673
match filled_root.data {
7774
// Binary node.

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

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,6 @@ use starknet_patricia::patricia_merkle_tree::node_data::inner_node::{
2727
};
2828
use starknet_patricia::patricia_merkle_tree::traversal::SubTreeTrait;
2929
use starknet_patricia::patricia_merkle_tree::types::{SortedLeafIndices, SubTreeHeight};
30-
use starknet_patricia_storage::db_object::EmptyKeyContext;
3130
use starknet_patricia_storage::map_storage::MapStorage;
3231
use starknet_patricia_storage::storage_trait::{DbHashMap, DbKey, DbValue};
3332
use starknet_types_core::felt::Felt;
@@ -88,7 +87,6 @@ async fn test_fetch_patricia_paths_inner_impl(
8887
vec![main_subtree],
8988
&mut nodes,
9089
Some(&mut fetched_leaves),
91-
&EmptyKeyContext,
9290
)
9391
.await
9492
.unwrap();

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

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ use crate::db::index_db::leaves::{
2626
IndexLayoutContractState,
2727
IndexLayoutStarknetStorageValue,
2828
};
29-
use crate::db::index_db::types::{IndexFilledNode, IndexNodeContext};
29+
use crate::db::index_db::types::{EmptyNodeData, IndexFilledNode, IndexNodeContext};
3030
use crate::hash_function::hash::TreeHashFunctionImpl;
3131
use crate::patricia_merkle_tree::leaf::leaf_impl::ContractState;
3232
use crate::patricia_merkle_tree::types::CompiledClassHash;
@@ -35,7 +35,9 @@ use crate::patricia_merkle_tree::types::CompiledClassHash;
3535
///
3636
/// Useful for using the same data for computing the hash and creating an index layout leaf
3737
/// instance.
38-
fn index_leaf_data_from_hash_data<L: Leaf>(data: NodeData<L, HashOutput>) -> NodeData<L, ()> {
38+
fn index_leaf_data_from_hash_data<L: Leaf>(
39+
data: NodeData<L, HashOutput>,
40+
) -> NodeData<L, EmptyNodeData> {
3941
match data {
4042
NodeData::Binary(_) | NodeData::Edge(_) => {
4143
unreachable!("this helper is intended for leaf-only test data")
@@ -85,15 +87,15 @@ fn starknet_storage_value_leaf_136_bits() -> IndexLayoutStarknetStorageValue {
8587
fn binary_node() -> IndexFilledNode<IndexLayoutContractState> {
8688
IndexFilledNode(FilledNode {
8789
hash: HashOutput(Felt::from(1)),
88-
data: NodeData::Binary(BinaryData { left_data: (), right_data: () }),
90+
data: NodeData::Binary(BinaryData { left_data: EmptyNodeData, right_data: EmptyNodeData }),
8991
})
9092
}
9193

9294
fn edge_node_short_path_len_3() -> IndexFilledNode<IndexLayoutContractState> {
9395
IndexFilledNode(FilledNode {
9496
hash: HashOutput(Felt::from(1)),
9597
data: NodeData::Edge(EdgeData {
96-
bottom_data: (),
98+
bottom_data: EmptyNodeData,
9799
// 110, right, right, left
98100
path_to_bottom: PathToBottom::new(
99101
EdgePath(U256::from(6_u128)),
@@ -108,7 +110,7 @@ fn edge_node_short_path_len_10() -> IndexFilledNode<IndexLayoutContractState> {
108110
IndexFilledNode(FilledNode {
109111
hash: HashOutput(Felt::from(1)),
110112
data: NodeData::Edge(EdgeData {
111-
bottom_data: (),
113+
bottom_data: EmptyNodeData,
112114
// 0...0 seven times followed by 110
113115
path_to_bottom: PathToBottom::new(
114116
EdgePath(U256::from(6_u128)),
@@ -123,7 +125,7 @@ fn edge_node_path_divisible_by_8() -> IndexFilledNode<IndexLayoutContractState>
123125
IndexFilledNode(FilledNode {
124126
hash: HashOutput(Felt::from(1)),
125127
data: NodeData::Edge(EdgeData {
126-
bottom_data: (),
128+
bottom_data: EmptyNodeData,
127129
path_to_bottom: PathToBottom::new(
128130
// 1...1 24 times
129131
EdgePath(U256::from((1_u128 << 24) - 1)),
@@ -138,7 +140,7 @@ fn edge_node_path_not_divisible_by_8() -> IndexFilledNode<IndexLayoutContractSta
138140
IndexFilledNode(FilledNode {
139141
hash: HashOutput(Felt::from(1)),
140142
data: NodeData::Edge(EdgeData {
141-
bottom_data: (),
143+
bottom_data: EmptyNodeData,
142144
// 000 followed by 1...1 19 times
143145
path_to_bottom: PathToBottom::new(
144146
EdgePath(U256::from((1_u128 << 19) - 1)),
@@ -153,7 +155,7 @@ fn edge_node_long_zero_path() -> IndexFilledNode<IndexLayoutContractState> {
153155
IndexFilledNode(FilledNode {
154156
hash: HashOutput(Felt::from(1)),
155157
data: NodeData::Edge(EdgeData {
156-
bottom_data: (),
158+
bottom_data: EmptyNodeData,
157159
// 0...0 path of length 250
158160
path_to_bottom: PathToBottom::new(
159161
EdgePath(U256::ZERO),
@@ -168,7 +170,7 @@ fn edge_node_long_non_zero_path() -> IndexFilledNode<IndexLayoutContractState> {
168170
IndexFilledNode(FilledNode {
169171
hash: HashOutput(Felt::from(1)),
170172
data: NodeData::Edge(EdgeData {
171-
bottom_data: (),
173+
bottom_data: EmptyNodeData,
172174
// 1 followed by 250 zeros path of length 251
173175
path_to_bottom: PathToBottom::new(
174176
EdgePath(U256::from(1u8) << 250),

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

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -28,8 +28,17 @@ use crate::hash_function::hash::TreeHashFunctionImpl;
2828
// In index layout, for binary nodes, only the hash is stored.
2929
pub(crate) const INDEX_LAYOUT_BINARY_BYTES: usize = SERIALIZE_HASH_BYTES;
3030

31+
#[derive(Clone, Debug, PartialEq, Eq)]
32+
pub struct EmptyNodeData;
33+
34+
impl From<HashOutput> for EmptyNodeData {
35+
fn from(_hash: HashOutput) -> Self {
36+
Self
37+
}
38+
}
39+
3140
#[derive(PartialEq, Debug)]
32-
pub struct IndexFilledNode<L: Leaf>(pub FilledNode<L, ()>);
41+
pub struct IndexFilledNode<L: Leaf>(pub FilledNode<L, EmptyNodeData>);
3342

3443
pub struct IndexNodeContext {
3544
pub is_leaf: bool,
@@ -82,7 +91,10 @@ where
8291
} else if value.0.len() == INDEX_LAYOUT_BINARY_BYTES {
8392
Ok(Self(FilledNode {
8493
hash: HashOutput(Felt::from_bytes_be_slice(&value.0)),
85-
data: NodeData::Binary(BinaryData { left_data: (), right_data: () }),
94+
data: NodeData::Binary(BinaryData {
95+
left_data: EmptyNodeData,
96+
right_data: EmptyNodeData,
97+
}),
8698
}))
8799
}
88100
// Edge nodes are always serailized to more than INDEX_LAYOUT_BINARY_BYTES bytes.
@@ -112,8 +124,8 @@ where
112124

113125
Ok(Self(FilledNode {
114126
hash: node_hash,
115-
data: NodeData::Edge(EdgeData::<()> {
116-
bottom_data: (),
127+
data: NodeData::Edge(EdgeData {
128+
bottom_data: EmptyNodeData,
117129
path_to_bottom: PathToBottom::new(
118130
EdgePath(path),
119131
EdgePathLength::new(bit_len)

crates/starknet_committer/src/db/trie_traversal.rs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -288,7 +288,10 @@ pub(crate) fn log_warning_for_empty_leaves<L: Leaf, T: Borrow<NodeIndex> + Debug
288288
Ok(())
289289
}
290290

291-
pub async fn create_original_skeleton_tree<'a, L: Leaf>(
291+
pub async fn create_original_skeleton_tree<
292+
'a,
293+
L: Leaf + HasStaticPrefix<KeyContext = EmptyKeyContext>,
294+
>(
292295
storage: &mut impl Storage,
293296
root_hash: HashOutput,
294297
sorted_leaf_indices: SortedLeafIndices<'a>,
@@ -368,7 +371,6 @@ pub async fn create_contracts_trie<'a>(
368371
contracts_trie_sorted_indices,
369372
&HashMap::new(),
370373
&OriginalSkeletonTrieConfig::new_for_contracts_trie(),
371-
&EmptyKeyContext,
372374
)
373375
.await?)
374376
}

0 commit comments

Comments
 (0)