Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions crates/apollo_integration_tests/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@ serde_json.workspace = true
starknet-types-core.workspace = true
starknet_api.workspace = true
starknet_committer.workspace = true
starknet_patricia = { workspace = true, features = ["testing"] }
starknet_patricia_storage.workspace = true
strum.workspace = true
tempfile.workspace = true
Expand Down
22 changes: 22 additions & 0 deletions crates/apollo_integration_tests/src/flow_test_setup.rs
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ use starknet_api::consensus_transaction::ConsensusTransaction;
use starknet_api::core::{ChainId, ContractAddress};
use starknet_api::execution_resources::GasAmount;
use starknet_api::rpc_transaction::RpcTransaction;
use starknet_api::state::ThinStateDiff;
use starknet_api::transaction::{
L1HandlerTransaction,
TransactionHash,
Expand Down Expand Up @@ -425,6 +426,27 @@ impl FlowSequencerSetup {
compressed_infos.decompress().expect("stored state commitment infos decompress")
})
}

pub async fn get_thin_state_diff(&self, block_number: BlockNumber) -> ThinStateDiff {
let response = self
.send_batcher_storage_reader_request(StorageReaderRequest::StateDiffsLocation(
block_number,
))
.await;
let state_diff_location = match response {
StorageReaderResponse::StateDiffsLocation(location) => location,
other => panic!("Expected StateDiffsLocation response, got: {other:?}"),
};
let response = self
.send_batcher_storage_reader_request(StorageReaderRequest::StateDiffsFromLocation(
state_diff_location,
))
.await;
match response {
StorageReaderResponse::StateDiffsFromLocation(thin_state_diff) => thin_state_diff,
other => panic!("Expected StateDiffsFromLocation response, got: {other:?}"),
}
}
}

pub fn create_consensus_manager_configs_and_channels(
Expand Down
67 changes: 67 additions & 0 deletions crates/apollo_integration_tests/src/utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -120,10 +120,12 @@ use serde_json::{json, to_value};
use starknet_api::block::BlockNumber;
use starknet_api::core::{ChainId, ContractAddress};
use starknet_api::execution_resources::GasAmount;
use starknet_api::hash::HashOutput;
use starknet_api::rpc_transaction::{RpcInvokeTransaction, RpcTransaction};
use starknet_api::staking::StakingWeight;
use starknet_api::transaction::fields::{ContractAddressSalt, Proof, ProofFacts};
use starknet_api::transaction::{L1HandlerTransaction, TransactionHash, TransactionHasher};
use starknet_committer::block_committer::input::StarknetStorageValue;
use starknet_committer::db::forest_trait::{
ForestMetadata,
ForestMetadataType,
Expand All @@ -132,7 +134,11 @@ use starknet_committer::db::forest_trait::{
};
use starknet_committer::db::index_db::IndexDb;
use starknet_committer::db::serde_db_utils::DbBlockNumber;
use starknet_committer::hash_function::hash::TreeHashFunctionImpl;
use starknet_committer::patricia_merkle_tree::types::StateCommitmentInfos;
use starknet_patricia::patricia_merkle_tree::node_data::inner_node::{Preimage, PreimageMap};
use starknet_patricia::patricia_merkle_tree::storage_proof_verification::verify_patricia_proof;
use starknet_patricia::patricia_merkle_tree::types::NodeIndex;
use starknet_patricia_storage::storage_trait::{DbOperation, DbValue};
use starknet_types_core::felt::Felt;
use tokio::net::TcpListener;
Expand Down Expand Up @@ -1274,9 +1280,70 @@ pub async fn end_to_end_flow(args: EndToEndFlowArgs) {
);
verify_block_hash_flow(&sequencers, scenario_timeout).await;
verify_witnesses_flow(&sequencers).await;
verify_witness_storage_proofs_flow(&sequencers).await;
verify_recorder_blobs_flow(&sequencers, scenario_timeout).await;
}

/// Verifies that for every contract with storage writes in a block's state diff, the persisted
/// witnesses contain valid Patricia paths from the updated storage root to every written leaf.
async fn verify_witness_storage_proofs_flow(sequencers: &[&FlowSequencerSetup]) {
for sequencer in sequencers {
let global_root_height = sequencer.get_global_root_height().await;
for block_number in (0..global_root_height.0).map(BlockNumber) {
let Some(state_commitment_infos) =
sequencer.get_state_commitment_infos(block_number).await
else {
// Heights committed without witnesses (e.g. seeded genesis) have nothing to prove.
continue;
};
let thin_state_diff = sequencer.get_thin_state_diff(block_number).await;
for (contract_address, storage_writes) in &thin_state_diff.storage_diffs {
let commitment_info = state_commitment_infos
.storage_tries_commitment_infos
.get(contract_address)
.unwrap_or_else(|| {
panic!(
"Block {block_number}: contract {contract_address} has storage writes \
but no storage-trie witnesses."
)
});
let preimages: PreimageMap = commitment_info
.commitment_facts
.iter()
.map(|(fact_hash, raw_preimage)| {
let preimage = Preimage::try_from(raw_preimage).unwrap_or_else(|err| {
panic!(
"Block {block_number}: invalid preimage for fact {fact_hash:?}: \
{err:?}"
)
});
(*fact_hash, preimage)
})
.collect();
// A zero value is an absent leaf, proved by path structure rather than leaf hash.
let requested_leaves: HashMap<NodeIndex, HashOutput> = storage_writes
.iter()
.filter(|(_, value)| **value != Felt::ZERO)
.map(|(key, value)| {
(NodeIndex::from_leaf_felt(key.0.key()), HashOutput(*value))
})
.collect();
verify_patricia_proof::<StarknetStorageValue, TreeHashFunctionImpl>(
commitment_info.updated_root,
&preimages,
&requested_leaves,
)
.unwrap_or_else(|err| {
panic!(
"Block {block_number}: witness storage proof failed for contract \
{contract_address}: {err:?}"
)
});
}
}
}
}

/// Verifies that the dummy recorders accepted every cende blob and that state commitment infos
/// were carried in at least one blob.
async fn verify_recorder_blobs_flow(
Expand Down
Loading