Skip to content

Commit 43c8509

Browse files
committed
starknet_committer: add index db
1 parent c0770f7 commit 43c8509

File tree

6 files changed

+186
-28
lines changed

6 files changed

+186
-28
lines changed

crates/starknet_committer/src/db/db_layout.rs

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,13 +8,13 @@ use starknet_patricia_storage::db_object::{DBObject, HasStaticPrefix};
88
use crate::db::index_db::leaves::TrieType;
99

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

15+
/// The storage representation of the node.
16+
type NodeDbObject: DBObject<DeserializeContext = Self::DeserializationContext>;
17+
1818
/// The context needed to deserialize the node from a raw
1919
/// [starknet_patricia_storage::storage_trait::DbValue].
2020
type DeserializationContext;
@@ -33,4 +33,6 @@ where
3333
) -> Self::SubTree;
3434

3535
fn generate_key_context(trie_type: TrieType) -> <L as HasStaticPrefix>::KeyContext;
36+
37+
fn get_filled_node(node_db_object: Self::NodeDbObject) -> FilledNode<L, Self::NodeData>;
3638
}

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

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ 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};
@@ -44,6 +45,8 @@ where
4445
{
4546
type NodeData = HashOutput;
4647

48+
type NodeDbObject = FactDbFilledNode<L>;
49+
4750
type DeserializationContext = FactNodeDeserializationContext;
4851

4952
type SubTree = FactsSubTree<'a>;
@@ -59,6 +62,10 @@ where
5962
fn generate_key_context(_trie_type: TrieType) -> <L as HasStaticPrefix>::KeyContext {
6063
EmptyKeyContext
6164
}
65+
66+
fn get_filled_node(node_db_object: Self::NodeDbObject) -> FilledNode<L, Self::NodeData> {
67+
node_db_object
68+
}
6269
}
6370

6471
pub struct FactsDb<S: Storage> {
Lines changed: 154 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,154 @@
1+
use std::collections::HashMap;
2+
3+
use async_trait::async_trait;
4+
use starknet_api::core::ContractAddress;
5+
use starknet_api::hash::HashOutput;
6+
use starknet_patricia::patricia_merkle_tree::filled_tree::node::FilledNode;
7+
use starknet_patricia::patricia_merkle_tree::filled_tree::tree::FilledTree;
8+
use starknet_patricia::patricia_merkle_tree::node_data::leaf::{Leaf, LeafModifications};
9+
use starknet_patricia::patricia_merkle_tree::types::{NodeIndex, SortedLeafIndices};
10+
use starknet_patricia::patricia_merkle_tree::updated_skeleton_tree::hash_function::TreeHashFunction;
11+
use starknet_patricia_storage::db_object::{EmptyKeyContext, HasStaticPrefix};
12+
use starknet_patricia_storage::errors::SerializationResult;
13+
use starknet_patricia_storage::storage_trait::{DbHashMap, DbKey, Storage};
14+
15+
use crate::block_committer::input::{FactsDbInitialRead, ReaderConfig, StarknetStorageValue};
16+
use crate::db::db_layout::NodeLayout;
17+
use crate::db::forest_trait::{ForestMetadata, ForestMetadataType, ForestReader, ForestWriter};
18+
use crate::db::index_db::leaves::{
19+
IndexLayoutCompiledClassHash,
20+
IndexLayoutContractState,
21+
IndexLayoutStarknetStorageValue,
22+
TrieType,
23+
};
24+
use crate::db::index_db::types::{IndexFilledNode, IndexLayoutSubTree, IndexNodeContext};
25+
use crate::db::trie_traversal::{create_classes_trie, create_contracts_trie, create_storage_tries};
26+
use crate::forest::filled_forest::FilledForest;
27+
use crate::forest::forest_errors::ForestResult;
28+
use crate::forest::original_skeleton_forest::{ForestSortedIndices, OriginalSkeletonForest};
29+
use crate::hash_function::hash::TreeHashFunctionImpl;
30+
use crate::patricia_merkle_tree::leaf::leaf_impl::ContractState;
31+
use crate::patricia_merkle_tree::types::CompiledClassHash;
32+
33+
pub struct IndexDb<S: Storage> {
34+
pub storage: S,
35+
}
36+
37+
impl<S: Storage> IndexDb<S> {
38+
pub fn new(storage: S) -> Self {
39+
Self { storage }
40+
}
41+
}
42+
43+
pub struct IndexNodeLayout {}
44+
45+
impl<'a, L: Leaf> NodeLayout<'a, L> for IndexNodeLayout
46+
where
47+
L: HasStaticPrefix<KeyContext = TrieType>,
48+
TreeHashFunctionImpl: TreeHashFunction<L>,
49+
{
50+
type NodeData = ();
51+
type NodeDbObject = IndexFilledNode<L>;
52+
type DeserializationContext = IndexNodeContext;
53+
type SubTree = IndexLayoutSubTree<'a>;
54+
55+
fn create_subtree(
56+
sorted_leaf_indices: SortedLeafIndices<'a>,
57+
root_index: NodeIndex,
58+
_root_hash: HashOutput,
59+
) -> Self::SubTree {
60+
IndexLayoutSubTree { sorted_leaf_indices, root_index }
61+
}
62+
63+
fn generate_key_context(trie_type: TrieType) -> <L as HasStaticPrefix>::KeyContext {
64+
trie_type
65+
}
66+
67+
fn get_filled_node(node_db_object: Self::NodeDbObject) -> FilledNode<L, Self::NodeData> {
68+
node_db_object.0
69+
}
70+
}
71+
72+
// TODO(Ariel): define an IndexDbInitialRead empty type, and check whether each tree is empty inside
73+
// create_xxx_trie.
74+
#[async_trait]
75+
impl<S: Storage> ForestReader<FactsDbInitialRead> for IndexDb<S> {
76+
/// Creates an original skeleton forest that includes the storage tries of the modified
77+
/// contracts, the classes trie and the contracts trie. Additionally, returns the original
78+
/// contract states that are needed to compute the contract state tree.
79+
async fn read<'a>(
80+
&mut self,
81+
context: FactsDbInitialRead,
82+
storage_updates: &'a HashMap<ContractAddress, LeafModifications<StarknetStorageValue>>,
83+
classes_updates: &'a LeafModifications<CompiledClassHash>,
84+
forest_sorted_indices: &'a ForestSortedIndices<'a>,
85+
config: ReaderConfig,
86+
) -> ForestResult<(OriginalSkeletonForest<'a>, HashMap<NodeIndex, ContractState>)> {
87+
let (contracts_trie, original_contracts_trie_leaves) =
88+
create_contracts_trie::<IndexLayoutContractState, IndexNodeLayout>(
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 =
95+
create_storage_tries::<IndexLayoutStarknetStorageValue, IndexNodeLayout>(
96+
&mut self.storage,
97+
storage_updates,
98+
&original_contracts_trie_leaves,
99+
&config,
100+
&forest_sorted_indices.storage_tries_sorted_indices,
101+
)
102+
.await?;
103+
let classes_trie = create_classes_trie::<IndexLayoutCompiledClassHash, IndexNodeLayout>(
104+
&mut self.storage,
105+
classes_updates,
106+
context.0.classes_trie_root_hash,
107+
&config,
108+
forest_sorted_indices.classes_trie_sorted_indices,
109+
)
110+
.await?;
111+
112+
Ok((
113+
OriginalSkeletonForest { classes_trie, contracts_trie, storage_tries },
114+
original_contracts_trie_leaves,
115+
))
116+
}
117+
}
118+
119+
#[async_trait]
120+
impl<S: Storage> ForestWriter for IndexDb<S> {
121+
fn serialize_forest(filled_forest: &FilledForest) -> SerializationResult<DbHashMap> {
122+
let mut serialized_forest = DbHashMap::new();
123+
124+
// TODO(Ariel): use a different key context when FilledForest is generic over leaf types.
125+
for tree in filled_forest.storage_tries.values() {
126+
serialized_forest.extend(tree.serialize(&EmptyKeyContext)?);
127+
}
128+
129+
// Contracts and classes tries.
130+
serialized_forest.extend(filled_forest.contracts_trie.serialize(&EmptyKeyContext)?);
131+
serialized_forest.extend(filled_forest.classes_trie.serialize(&EmptyKeyContext)?);
132+
133+
Ok(serialized_forest)
134+
}
135+
136+
async fn write_updates(&mut self, updates: DbHashMap) -> usize {
137+
let n_updates = updates.len();
138+
self.storage
139+
.mset(updates)
140+
.await
141+
.unwrap_or_else(|_| panic!("Write of {n_updates} new updates to storage failed"));
142+
n_updates
143+
}
144+
}
145+
146+
// TODO(Ariel): Add index DB metadata keys.
147+
impl<S: Storage> ForestMetadata for IndexDb<S> {
148+
/// Returns the db key for the metadata type.
149+
/// The data keys in an index DB are the result of a hash function; therefore, they are not
150+
/// expected to collide with these metadata keys.
151+
fn metadata_key(_metadata_type: ForestMetadataType) -> DbKey {
152+
DbKey(vec![0])
153+
}
154+
}

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

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,9 @@ use crate::patricia_merkle_tree::types::CompiledClassHash;
1717

1818
// Wrap the leaves types so that we can implement the [DBObject] trait differently in index
1919
// layout.
20-
#[derive(Clone, Debug, Default, Eq, PartialEq, derive_more::AsRef, derive_more::From)]
20+
#[derive(
21+
Clone, Debug, Default, Eq, PartialEq, derive_more::AsRef, derive_more::From, derive_more::Into,
22+
)]
2123
pub struct IndexLayoutContractState(pub ContractState);
2224

2325
#[derive(Clone, Debug, Default, Eq, PartialEq, derive_more::AsRef, derive_more::From)]

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
pub mod db;
12
pub mod leaves;
23
#[cfg(test)]
34
pub mod serde_tests;

crates/starknet_committer/src/db/trie_traversal.rs

Lines changed: 15 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,6 @@ pub(crate) async fn fetch_nodes<'a, L, Layout>(
7070
where
7171
L: Leaf,
7272
Layout: NodeLayout<'a, L>,
73-
FilledNode<L, Layout::NodeData>: DBObject<DeserializeContext = Layout::DeserializationContext>,
7473
{
7574
let mut current_subtrees = subtrees;
7675
let mut next_subtrees = Vec::new();
@@ -248,10 +247,7 @@ pub async fn get_roots_from_storage<'a, L: Leaf, Layout: NodeLayout<'a, L>>(
248247
subtrees: &[Layout::SubTree],
249248
storage: &mut impl Storage,
250249
key_context: &<L as HasStaticPrefix>::KeyContext,
251-
) -> TraversalResult<Vec<FilledNode<L, Layout::NodeData>>>
252-
where
253-
FilledNode<L, Layout::NodeData>: DBObject<DeserializeContext = Layout::DeserializationContext>,
254-
{
250+
) -> TraversalResult<Vec<FilledNode<L, Layout::NodeData>>> {
255251
let mut subtrees_roots = vec![];
256252
let db_keys: Vec<DbKey> = subtrees
257253
.iter()
@@ -263,7 +259,11 @@ where
263259
let db_vals = storage.mget(&db_keys.iter().collect::<Vec<&DbKey>>()).await?;
264260
for ((subtree, optional_val), db_key) in subtrees.iter().zip(db_vals.iter()).zip(db_keys) {
265261
let Some(val) = optional_val else { Err(StorageError::MissingKey(db_key))? };
266-
let filled_node = FilledNode::deserialize(val, &subtree.get_root_context())?;
262+
let filled_node = Layout::get_filled_node(Layout::NodeDbObject::deserialize(
263+
val,
264+
&subtree.get_root_context(),
265+
)?);
266+
// let filled_node = FilledNode::deserialize(val, &subtree.get_root_context())?;
267267
subtrees_roots.push(filled_node);
268268
}
269269
Ok(subtrees_roots)
@@ -276,10 +276,7 @@ pub async fn create_original_skeleton_tree<'a, L: Leaf, Layout: NodeLayout<'a, L
276276
config: &impl OriginalSkeletonTreeConfig,
277277
leaf_modifications: &LeafModifications<L>,
278278
key_context: &<L as HasStaticPrefix>::KeyContext,
279-
) -> OriginalSkeletonTreeResult<OriginalSkeletonTreeImpl<'a>>
280-
where
281-
FilledNode<L, Layout::NodeData>: DBObject<DeserializeContext = Layout::DeserializationContext>,
282-
{
279+
) -> OriginalSkeletonTreeResult<OriginalSkeletonTreeImpl<'a>> {
283280
if sorted_leaf_indices.is_empty() {
284281
return Ok(OriginalSkeletonTreeImpl::create_unmodified(root_hash));
285282
}
@@ -311,10 +308,7 @@ pub async fn create_storage_tries<
311308
original_contracts_trie_leaves: &HashMap<NodeIndex, ContractState>,
312309
config: &impl Config,
313310
storage_tries_sorted_indices: &HashMap<ContractAddress, SortedLeafIndices<'a>>,
314-
) -> ForestResult<HashMap<ContractAddress, OriginalSkeletonTreeImpl<'a>>>
315-
where
316-
FilledNode<L, Layout::NodeData>: DBObject<DeserializeContext = Layout::DeserializationContext>,
317-
{
311+
) -> ForestResult<HashMap<ContractAddress, OriginalSkeletonTreeImpl<'a>>> {
318312
let mut storage_tries = HashMap::new();
319313
for (address, updates) in actual_storage_updates {
320314
let sorted_leaf_indices = storage_tries_sorted_indices
@@ -343,10 +337,7 @@ pub async fn create_contracts_trie<'a, L: Leaf + Into<ContractState>, Layout: No
343337
storage: &mut impl Storage,
344338
root_hash: HashOutput,
345339
sorted_leaf_indices: SortedLeafIndices<'a>,
346-
) -> ForestResult<(OriginalSkeletonTreeImpl<'a>, HashMap<NodeIndex, ContractState>)>
347-
where
348-
FilledNode<L, Layout::NodeData>: DBObject<DeserializeContext = Layout::DeserializationContext>,
349-
{
340+
) -> ForestResult<(OriginalSkeletonTreeImpl<'a>, HashMap<NodeIndex, ContractState>)> {
350341
if sorted_leaf_indices.is_empty() {
351342
let unmodified = OriginalSkeletonTreeImpl::create_unmodified(root_hash);
352343
return Ok((unmodified, HashMap::new()));
@@ -374,16 +365,17 @@ where
374365
Ok((skeleton_tree, leaves))
375366
}
376367

377-
pub async fn create_classes_trie<'a, L: Leaf + From<CompiledClassHash>, Layout: NodeLayout<'a, L>>(
368+
pub async fn create_classes_trie<
369+
'a,
370+
L: Leaf + From<CompiledClassHash>,
371+
Layout: NodeLayout<'a, L>,
372+
>(
378373
storage: &mut impl Storage,
379374
actual_classes_updates: &LeafModifications<CompiledClassHash>,
380375
classes_trie_root_hash: HashOutput,
381376
config: &impl Config,
382377
contracts_trie_sorted_indices: SortedLeafIndices<'a>,
383-
) -> ForestResult<OriginalSkeletonTreeImpl<'a>>
384-
where
385-
FilledNode<L, Layout::NodeData>: DBObject<DeserializeContext = Layout::DeserializationContext>,
386-
{
378+
) -> ForestResult<OriginalSkeletonTreeImpl<'a>> {
387379
let config = OriginalSkeletonTrieConfig::new(config.warn_on_trivial_modifications());
388380

389381
Ok(create_original_skeleton_tree::<L, Layout>(

0 commit comments

Comments
 (0)