Skip to content

Commit bd02493

Browse files
committed
starknet_committer: underlying logic of the new read witnesses and commit endpoint
1 parent 2892fbe commit bd02493

1 file changed

Lines changed: 179 additions & 0 deletions

File tree

crates/apollo_committer/src/committer.rs

Lines changed: 179 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,11 @@ use apollo_committer_types::committer_types::{
99
RevertBlockRequest,
1010
RevertBlockResponse,
1111
};
12+
#[cfg(feature = "os_input")]
13+
use apollo_committer_types::committer_types::{
14+
ReadPathsAndCommitBlockRequest,
15+
ReadPathsAndCommitBlockResponse,
16+
};
1217
use apollo_committer_types::errors::{CommitterError, CommitterResult};
1318
use apollo_infra::component_definitions::{default_component_start_fn, ComponentStarter};
1419
use async_trait::async_trait;
@@ -27,21 +32,34 @@ use starknet_committer::block_committer::measurements_util::{
2732
MeasurementsTrait,
2833
SingleBlockMeasurements,
2934
};
35+
#[cfg(feature = "os_input")]
36+
use starknet_committer::db::forest_trait::ForestStorageWithWitnesses;
37+
#[cfg(feature = "os_input")]
38+
use starknet_committer::db::forest_trait::PatriciaProofsUpdates;
3039
use starknet_committer::db::forest_trait::{
3140
EmptyInitialReadContext,
3241
ForestMetadataType,
3342
ForestStorageWithEmptyReadContext,
43+
ForestWriterWithMetadataAndWitnesses,
3444
};
3545
use starknet_committer::db::index_db::IndexDb;
46+
#[cfg(feature = "os_input")]
47+
use starknet_committer::db::serde_db_utils::accessed_keys_digest;
3648
use starknet_committer::db::serde_db_utils::{
3749
deserialize_felt_no_packing,
3850
serialize_felt_no_packing,
3951
DbBlockNumber,
4052
};
4153
use starknet_committer::forest::deleted_nodes::DeletedNodes;
4254
use starknet_committer::forest::filled_forest::FilledForest;
55+
#[cfg(feature = "os_input")]
56+
use starknet_committer::patricia_merkle_tree::tree::get_leaf_indices;
57+
#[cfg(feature = "os_input")]
58+
use starknet_patricia_storage::errors::SerializationError;
4359
use starknet_patricia_storage::map_storage::CachedStorage;
4460
use starknet_patricia_storage::rocksdb_storage::RocksDbStorage;
61+
#[cfg(feature = "os_input")]
62+
use starknet_patricia_storage::storage_trait::ImmutableReadOnlyStorage;
4563
use starknet_patricia_storage::storage_trait::{DbValue, Storage};
4664
use tracing::{debug, error, info, warn};
4765

@@ -443,6 +461,167 @@ where
443461
}
444462
}
445463

464+
#[cfg(feature = "os_input")]
465+
impl<S, ForestDB> Committer<S, ForestDB>
466+
where
467+
S: StorageConstructor + ImmutableReadOnlyStorage + 'static,
468+
ForestDB: ForestStorageWithWitnesses<Storage = S>,
469+
{
470+
async fn load_witnesses_digest(
471+
&mut self,
472+
block_number: BlockNumber,
473+
) -> CommitterResult<Option<[u8; 32]>> {
474+
Ok(
475+
match self
476+
.forest_storage
477+
.read_metadata(ForestMetadataType::OsInputWitnessDigest(DbBlockNumber(
478+
block_number,
479+
)))
480+
.await
481+
.map_err(|e| self.map_internal_error(e))?
482+
{
483+
None => None,
484+
Some(v) => {
485+
let s = v.0.as_slice();
486+
let arr: [u8; 32] = s.try_into().map_err(|_| CommitterError::Internal {
487+
height: block_number,
488+
message: format!(
489+
"Invalid OS-input witness digest length {} (expected 32)",
490+
s.len()
491+
),
492+
})?;
493+
Some(arr)
494+
}
495+
},
496+
)
497+
}
498+
499+
/// Commits the next block and returns merged Patricia witness facts for OS input, persisting
500+
/// digest + payload for idempotent replay.
501+
pub async fn read_paths_and_commit_block(
502+
&mut self,
503+
ReadPathsAndCommitBlockRequest {
504+
commit: CommitBlockRequest { state_diff, state_diff_commitment, height },
505+
class_hashes,
506+
contract_addresses,
507+
contract_storage_keys,
508+
}: ReadPathsAndCommitBlockRequest,
509+
) -> CommitterResult<ReadPathsAndCommitBlockResponse> {
510+
let digest =
511+
accessed_keys_digest(&class_hashes, &contract_addresses, &contract_storage_keys);
512+
info!(
513+
"read_paths_and_commit_block: block {height} with {} class hashes, {} contract \
514+
addresses",
515+
class_hashes.len(),
516+
contract_addresses.len()
517+
);
518+
519+
match self.commit_or_load(&state_diff, state_diff_commitment, height).await? {
520+
CommitBlockHeightPlan::Historical { global_root } => {
521+
let stored_digest = self.load_witnesses_digest(height).await?;
522+
if stored_digest != Some(digest) {
523+
return Err(CommitterError::AccessedKeysDigestMismatch {
524+
height,
525+
stored: stored_digest,
526+
expected: digest,
527+
});
528+
}
529+
let proofs = self
530+
.forest_storage
531+
.read_witnesses(height)
532+
.await
533+
.map_err(|e| self.map_internal_error(e))?;
534+
let proofs = proofs.ok_or(CommitterError::MissingPatriciaPaths { height })?;
535+
Ok(ReadPathsAndCommitBlockResponse { global_root, patricia_proofs: proofs })
536+
}
537+
CommitBlockHeightPlan::CommitTip { state_diff_commitment } => {
538+
let mut leaves_request =
539+
get_leaf_indices(&class_hashes, &contract_addresses, &contract_storage_keys);
540+
541+
let pre_roots = self
542+
.forest_storage
543+
.read_roots(ForestDB::InitialReadContext::create_empty())
544+
.await
545+
.map_err(|e| self.map_internal_error(e))?;
546+
let (class_sorted, contract_sorted, storage_sorted) = leaves_request.get_stored();
547+
548+
let proof_before = self
549+
.forest_storage
550+
.fetch_patricia_witnesses(
551+
pre_roots.classes_trie_root_hash,
552+
pre_roots.contracts_trie_root_hash,
553+
class_sorted,
554+
contract_sorted,
555+
&storage_sorted,
556+
None,
557+
)
558+
.await
559+
.map_err(|e| CommitterError::PatriciaPathsCollectionFailed {
560+
height,
561+
message: format!("pre-commit witness paths: {e:?}"),
562+
})?;
563+
564+
let mut block_measurements = SingleBlockMeasurements::default();
565+
block_measurements.start_measurement(Action::EndToEnd);
566+
let CommitStateDiffOutput { filled_forest, global_root, deleted_nodes } =
567+
self.commit_state_diff(state_diff.clone(), &mut block_measurements).await?;
568+
let post_roots = filled_forest.state_roots();
569+
570+
let forest_updates = ForestDB::serialize_forest(&filled_forest)
571+
.map_err(|e| self.map_internal_error(e))?;
572+
573+
let proof_after = self
574+
.forest_storage
575+
.fetch_patricia_witnesses(
576+
post_roots.classes_trie_root_hash,
577+
post_roots.contracts_trie_root_hash,
578+
class_sorted,
579+
contract_sorted,
580+
&storage_sorted,
581+
Some(forest_updates),
582+
)
583+
.await
584+
.map_err(|e| CommitterError::PatriciaPathsCollectionFailed {
585+
height,
586+
message: format!("post-commit witness paths: {e:?}"),
587+
})?;
588+
589+
let mut merged_proofs = proof_before;
590+
merged_proofs.extend(proof_after);
591+
let patricia_proofs = merged_proofs.clone();
592+
593+
let (metadata, next_offset) =
594+
commit_tip_metadata_bundle(height, global_root, state_diff_commitment);
595+
info!(
596+
"For block number {height}, writing filled forest and witnesses to storage \
597+
with metadata: {metadata:?}, delete {} nodes",
598+
deleted_nodes.len()
599+
);
600+
block_measurements.start_measurement(Action::Write);
601+
let n_write_entries = self
602+
.forest_storage
603+
.write_with_metadata_and_witnesses(
604+
&filled_forest,
605+
metadata,
606+
deleted_nodes,
607+
PatriciaProofsUpdates::Set {
608+
height,
609+
keys_digest: digest,
610+
witnesses: merged_proofs,
611+
},
612+
)
613+
.await
614+
.map_err(|e: SerializationError| self.map_internal_error(e))?;
615+
block_measurements.attempt_to_stop_measurement(Action::Write, n_write_entries).ok();
616+
block_measurements.attempt_to_stop_measurement(Action::EndToEnd, 0).ok();
617+
update_metrics(height, &block_measurements.block_measurement);
618+
self.update_offset(next_offset);
619+
Ok(ReadPathsAndCommitBlockResponse { global_root, patricia_proofs })
620+
}
621+
}
622+
}
623+
}
624+
446625
#[async_trait]
447626
impl ComponentStarter for ApolloCommitter {
448627
async fn start(&mut self) {

0 commit comments

Comments
 (0)