Skip to content

Commit 102f542

Browse files
committed
starknet_committer: add patricia paths forest reader/writer traits
1 parent 401e67a commit 102f542

3 files changed

Lines changed: 118 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: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
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+
/// The information required to write Patricia proofs to the database.
25+
pub struct PatriciaProofsWrite {
26+
pub block_number: BlockNumber,
27+
pub keys_digest: [u8; 32],
28+
pub witnesses: StarknetForestProofs,
29+
}
30+
31+
/// Patricia proofs DB operation, which can be either delete or write.
32+
/// Expected by [ForestWriterWithMetadataAndWitnesses::write_with_metadata_and_witnesses], which
33+
/// accumulates all DB operations to guarantee atomicity.
34+
pub enum PatriciaProofsUpdate {
35+
Write(PatriciaProofsWrite),
36+
Delete(BlockNumber),
37+
}
38+
39+
/// Reads committed OS-input witness payload (structured [`StarknetForestProofs`]) for a block
40+
/// height.
41+
#[async_trait]
42+
pub trait ForestReaderWithWitnesses:
43+
ForestReader<InitialReadContext: EmptyInitialReadContext> + Send
44+
{
45+
async fn read_witnesses(
46+
&mut self,
47+
height: BlockNumber,
48+
) -> ForestResult<Option<StarknetForestProofs>>;
49+
50+
/// Fetches Patricia witness paths for OS input, optionally staging serialized trie node KVs on
51+
/// an in-memory overlay so reads match post-commit state before the forest is persisted.
52+
async fn fetch_patricia_witnesses(
53+
&mut self,
54+
classes_trie_root_hash: HashOutput,
55+
contracts_trie_root_hash: HashOutput,
56+
class_sorted_leaf_indices: SortedLeafIndices<'_>,
57+
contract_sorted_leaf_indices: SortedLeafIndices<'_>,
58+
contract_storage_sorted_leaf_indices: &HashMap<NodeIndex, SortedLeafIndices<'_>>,
59+
staged_serialized_forest: Option<DbHashMap>,
60+
) -> TraversalResult<StarknetForestProofs>;
61+
}
62+
63+
/// Writes forest + metadata + deleted nodes, and applies [`PatriciaProofsUpdate`] in the same
64+
/// batch.
65+
#[async_trait]
66+
pub trait ForestWriterWithMetadataAndWitnesses: ForestWriterWithMetadata + Send {
67+
async fn write_with_metadata_and_witnesses(
68+
&mut self,
69+
filled_forest: &FilledForest,
70+
metadata: HashMap<ForestMetadataType, DbValue>,
71+
deleted_nodes: DeletedNodes,
72+
patricia_proofs_update: PatriciaProofsUpdate,
73+
) -> SerializationResult<usize>;
74+
}
75+
76+
/// Forest storage with empty [`ForestReader::InitialReadContext`] plus OS-input witness read/write.
77+
pub trait ForestStorageWithWitnesses:
78+
ForestReaderWithWitnesses + ForestWriterWithMetadataAndWitnesses + StorageInitializer
79+
{
80+
}
81+
82+
impl<T> ForestStorageWithWitnesses for T where
83+
T: ForestReaderWithWitnesses + ForestWriterWithMetadataAndWitnesses + StorageInitializer
84+
{
85+
}

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

Lines changed: 26 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,11 @@ 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+
#[cfg_attr(not(feature = "os_input"), expect(dead_code))]
90+
pub(crate) static ACCESSED_KEYS_DIGEST_METADATA_PREFIX: LazyLock<[u8; 32]> =
91+
LazyLock::new(|| (Felt::from_bytes_be(&STATE_ROOT_METADATA_PREFIX) + Felt::ONE).to_bytes_be());
92+
8793
pub struct IndexDb<S: Storage, H = TreeHashFunctionImpl> {
8894
storage: S,
8995
phantom: PhantomData<H>,
@@ -267,28 +273,26 @@ impl<S: Storage> ForestWriter for IndexDb<S> {
267273
#[async_trait]
268274
impl<S: Storage> ForestMetadata for IndexDb<S> {
269275
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.
276+
// Padding to 64byte keys to keep the 32byte prefix aligned between metadata and
277+
// patricia nodes.
278+
DbKey(match metadata_type {
274279
ForestMetadataType::CommitmentOffset => {
280+
let mut key = Vec::with_capacity(64);
275281
key.extend_from_slice(&*COMMITMENT_OFFSET_METADATA_PREFIX);
276282
key.extend_from_slice(&[0u8; 32]);
283+
key
277284
}
278285
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]);
286+
metadata_block_number_key(&STATE_DIFF_HASH_METADATA_PREFIX, block_number)
283287
}
284288
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]);
289+
metadata_block_number_key(&STATE_ROOT_METADATA_PREFIX, block_number)
290+
}
291+
#[cfg(feature = "os_input")]
292+
ForestMetadataType::AccessedKeysDigest(block_number) => {
293+
metadata_block_number_key(&ACCESSED_KEYS_DIGEST_METADATA_PREFIX, block_number)
289294
}
290-
}
291-
DbKey(key)
295+
})
292296
}
293297

294298
async fn get_from_storage(&mut self, db_key: DbKey) -> ForestResult<Option<DbValue>> {
@@ -320,6 +324,14 @@ impl<S: Storage> ForestWriterWithMetadata for IndexDb<S> {
320324
}
321325
}
322326

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

0 commit comments

Comments
 (0)