Skip to content

Commit c6695e5

Browse files
committed
starknet_committer: add patricia paths forest reader/writer traits
1 parent 2e82fa4 commit c6695e5

3 files changed

Lines changed: 111 additions & 14 deletions

File tree

crates/starknet_committer/src/db/forest_trait.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,11 +30,18 @@ use crate::forest::original_skeleton_forest::{ForestSortedIndices, OriginalSkele
3030
use crate::patricia_merkle_tree::leaf::leaf_impl::ContractState;
3131
use crate::patricia_merkle_tree::types::CompiledClassHash;
3232

33+
#[cfg(feature = "os_input")]
34+
#[path = "forest_trait_witnesses.rs"]
35+
pub mod forest_trait_witnesses;
36+
3337
#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Hash, Serialize)]
3438
pub enum ForestMetadataType {
3539
CommitmentOffset,
3640
StateDiffHash(DbBlockNumber),
3741
StateRoot(DbBlockNumber),
42+
/// BLAKE2s digest of the canonical accessed-keys set for the block.
43+
#[cfg(feature = "os_input")]
44+
AccessedKeysDigest(DbBlockNumber),
3845
}
3946

4047
#[async_trait]
Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
use std::collections::HashMap;
2+
3+
use async_trait::async_trait;
4+
use starknet_api::block::BlockNumber;
5+
use starknet_api::hash::HashOutput;
6+
use starknet_patricia::patricia_merkle_tree::traversal::TraversalResult;
7+
use starknet_patricia::patricia_merkle_tree::types::NodeIndex;
8+
use starknet_patricia_storage::errors::SerializationResult;
9+
use starknet_patricia_storage::storage_trait::{DbHashMap, DbValue};
10+
11+
use super::{
12+
EmptyInitialReadContext,
13+
ForestMetadataType,
14+
ForestReader,
15+
ForestWriterWithMetadata,
16+
StorageInitializer,
17+
};
18+
use crate::forest::deleted_nodes::DeletedNodes;
19+
use crate::forest::filled_forest::FilledForest;
20+
use crate::forest::forest_errors::ForestResult;
21+
use crate::patricia_merkle_tree::tree::SortedLeafIndices;
22+
use crate::patricia_merkle_tree::types::StarknetForestProofs;
23+
24+
/// How Patricia proofs and read-keys digest metadata are updated in the same batch as a forest
25+
/// write.
26+
pub enum PatriciaProofsUpdates {
27+
/// Remove read-keys digest + Patricia proofs on revert.
28+
Delete(BlockNumber),
29+
/// Persist read-keys digest + Patricia proofs for this block.
30+
Set { height: BlockNumber, keys_digest: [u8; 32], witnesses: StarknetForestProofs },
31+
}
32+
33+
/// Reads committed OS-input witness payload (structured [`StarknetForestProofs`]) for a block
34+
/// height.
35+
#[async_trait]
36+
pub trait ForestReaderWithWitnesses:
37+
ForestReader<InitialReadContext: EmptyInitialReadContext> + Send
38+
{
39+
async fn read_witnesses(
40+
&mut self,
41+
height: BlockNumber,
42+
) -> ForestResult<Option<StarknetForestProofs>>;
43+
44+
/// Fetches Patricia witness paths for OS input, optionally staging serialized trie node KVs on
45+
/// an in-memory overlay so reads match post-commit state before the forest is persisted.
46+
async fn fetch_patricia_witnesses(
47+
&mut self,
48+
classes_trie_root_hash: HashOutput,
49+
contracts_trie_root_hash: HashOutput,
50+
class_sorted_leaf_indices: SortedLeafIndices<'_>,
51+
contract_sorted_leaf_indices: SortedLeafIndices<'_>,
52+
contract_storage_sorted_leaf_indices: &HashMap<NodeIndex, SortedLeafIndices<'_>>,
53+
staged_serialized_forest: Option<DbHashMap>,
54+
) -> TraversalResult<StarknetForestProofs>;
55+
}
56+
57+
/// Writes forest + metadata + deleted nodes, and optionally applies [`PatriciaProofsUpdates`] in
58+
/// the same batch.
59+
#[async_trait]
60+
pub trait ForestWriterWithMetadataAndWitnesses: ForestWriterWithMetadata + Send {
61+
async fn write_with_metadata_and_witnesses(
62+
&mut self,
63+
filled_forest: &FilledForest,
64+
metadata: HashMap<ForestMetadataType, DbValue>,
65+
deleted_nodes: DeletedNodes,
66+
patricia_proofs_updates: PatriciaProofsUpdates,
67+
) -> SerializationResult<usize>;
68+
}
69+
70+
/// Forest storage with empty [`ForestReader::InitialReadContext`] plus OS-input witness read/write.
71+
pub trait ForestStorageWithWitnesses:
72+
ForestReaderWithWitnesses + ForestWriterWithMetadataAndWitnesses + StorageInitializer
73+
{
74+
}
75+
76+
impl<T> ForestStorageWithWitnesses for T where
77+
T: ForestReaderWithWitnesses + ForestWriterWithMetadataAndWitnesses + StorageInitializer
78+
{
79+
}

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

Lines changed: 25 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ use crate::db::index_db::types::{
5050
IndexLayoutSubTree,
5151
IndexNodeContext,
5252
};
53+
use crate::db::serde_db_utils::DbBlockNumber;
5354
use crate::forest::deleted_nodes::DeletedNodes;
5455
use crate::forest::filled_forest::FilledForest;
5556
use crate::forest::forest_errors::ForestResult;
@@ -84,6 +85,10 @@ static STATE_ROOT_METADATA_PREFIX: LazyLock<[u8; 32]> = LazyLock::new(|| {
8485
(Felt::from_bytes_be(&STATE_DIFF_HASH_METADATA_PREFIX) + Felt::ONE).to_bytes_be()
8586
});
8687

88+
/// Prefix for accessed-keys digest metadata (committed per block).
89+
pub(crate) static ACCESSED_KEYS_DIGEST_METADATA_PREFIX: LazyLock<[u8; 32]> =
90+
LazyLock::new(|| (Felt::from_bytes_be(&STATE_ROOT_METADATA_PREFIX) + Felt::ONE).to_bytes_be());
91+
8792
pub struct IndexDb<S: Storage, H = TreeHashFunctionImpl> {
8893
storage: S,
8994
phantom: PhantomData<H>,
@@ -267,28 +272,26 @@ impl<S: Storage> ForestWriter for IndexDb<S> {
267272
#[async_trait]
268273
impl<S: Storage> ForestMetadata for IndexDb<S> {
269274
fn metadata_key(metadata_type: ForestMetadataType) -> DbKey {
270-
let mut key = Vec::with_capacity(64);
271-
match metadata_type {
272-
// Padding to 64byte keys to keep the 32byte prefix aligned between metadata and
273-
// patricia nodes.
275+
// Padding to 64byte keys to keep the 32byte prefix aligned between metadata and
276+
// patricia nodes.
277+
DbKey(match metadata_type {
274278
ForestMetadataType::CommitmentOffset => {
279+
let mut key = Vec::with_capacity(64);
275280
key.extend_from_slice(&*COMMITMENT_OFFSET_METADATA_PREFIX);
276281
key.extend_from_slice(&[0u8; 32]);
282+
key
277283
}
278284
ForestMetadataType::StateDiffHash(block_number) => {
279-
key.extend_from_slice(&*STATE_DIFF_HASH_METADATA_PREFIX);
280-
let block_number_bytes: [u8; 8] = block_number.serialize();
281-
key.extend_from_slice(&block_number_bytes);
282-
key.extend_from_slice(&[0u8; 24]);
285+
metadata_block_number_key(&*STATE_DIFF_HASH_METADATA_PREFIX, block_number)
283286
}
284287
ForestMetadataType::StateRoot(block_number) => {
285-
key.extend_from_slice(&*STATE_ROOT_METADATA_PREFIX);
286-
let block_number_bytes: [u8; 8] = block_number.serialize();
287-
key.extend_from_slice(&block_number_bytes);
288-
key.extend_from_slice(&[0u8; 24]);
288+
metadata_block_number_key(&*STATE_ROOT_METADATA_PREFIX, block_number)
289+
}
290+
#[cfg(feature = "os_input")]
291+
ForestMetadataType::AccessedKeysDigest(block_number) => {
292+
metadata_block_number_key(&*ACCESSED_KEYS_DIGEST_METADATA_PREFIX, block_number)
289293
}
290-
}
291-
DbKey(key)
294+
})
292295
}
293296

294297
async fn get_from_storage(&mut self, db_key: DbKey) -> ForestResult<Option<DbValue>> {
@@ -320,6 +323,14 @@ impl<S: Storage> ForestWriterWithMetadata for IndexDb<S> {
320323
}
321324
}
322325

326+
fn metadata_block_number_key(prefix: &[u8; 32], block_number: DbBlockNumber) -> Vec<u8> {
327+
let mut key = Vec::with_capacity(64);
328+
key.extend_from_slice(prefix);
329+
key.extend_from_slice(&block_number.serialize());
330+
key.extend_from_slice(&[0u8; 24]);
331+
key
332+
}
333+
323334
fn extract_root_hash<L: Leaf>(root: &Option<DbValue>) -> Result<HashOutput, DeserializationError>
324335
where
325336
TreeHashFunctionImpl: TreeHashFunction<L>,

0 commit comments

Comments
 (0)