@@ -120,10 +120,12 @@ use serde_json::{json, to_value};
120120use starknet_api:: block:: BlockNumber ;
121121use starknet_api:: core:: { ChainId , ContractAddress } ;
122122use starknet_api:: execution_resources:: GasAmount ;
123+ use starknet_api:: hash:: HashOutput ;
123124use starknet_api:: rpc_transaction:: { RpcInvokeTransaction , RpcTransaction } ;
124125use starknet_api:: staking:: StakingWeight ;
125126use starknet_api:: transaction:: fields:: { ContractAddressSalt , Proof , ProofFacts } ;
126127use starknet_api:: transaction:: { L1HandlerTransaction , TransactionHash , TransactionHasher } ;
128+ use starknet_committer:: block_committer:: input:: StarknetStorageValue ;
127129use starknet_committer:: db:: forest_trait:: {
128130 ForestMetadata ,
129131 ForestMetadataType ,
@@ -132,7 +134,11 @@ use starknet_committer::db::forest_trait::{
132134} ;
133135use starknet_committer:: db:: index_db:: IndexDb ;
134136use starknet_committer:: db:: serde_db_utils:: DbBlockNumber ;
137+ use starknet_committer:: hash_function:: hash:: TreeHashFunctionImpl ;
135138use starknet_committer:: patricia_merkle_tree:: types:: StateCommitmentInfos ;
139+ use starknet_patricia:: patricia_merkle_tree:: node_data:: inner_node:: { Preimage , PreimageMap } ;
140+ use starknet_patricia:: patricia_merkle_tree:: storage_proof_verification:: verify_patricia_proof;
141+ use starknet_patricia:: patricia_merkle_tree:: types:: NodeIndex ;
136142use starknet_patricia_storage:: storage_trait:: { DbOperation , DbValue } ;
137143use starknet_types_core:: felt:: Felt ;
138144use tokio:: net:: TcpListener ;
@@ -1273,9 +1279,70 @@ pub async fn end_to_end_flow(args: EndToEndFlowArgs) {
12731279 ) ;
12741280 verify_block_hash_flow ( & sequencers, scenario_timeout) . await ;
12751281 verify_witnesses_flow ( & sequencers) . await ;
1282+ verify_witness_storage_proofs_flow ( & sequencers) . await ;
12761283 verify_recorder_blobs_flow ( & sequencers, scenario_timeout) . await ;
12771284}
12781285
1286+ /// Verifies that for every contract with storage writes in a block's state diff, the persisted
1287+ /// witnesses contain valid Patricia paths from the updated storage root to every written leaf.
1288+ async fn verify_witness_storage_proofs_flow ( sequencers : & [ & FlowSequencerSetup ] ) {
1289+ for sequencer in sequencers {
1290+ let global_root_height = sequencer. get_global_root_height ( ) . await ;
1291+ for block_number in ( 0 ..global_root_height. 0 ) . map ( BlockNumber ) {
1292+ let Some ( state_commitment_infos) =
1293+ sequencer. get_state_commitment_infos ( block_number) . await
1294+ else {
1295+ // Heights committed without witnesses (e.g. seeded genesis) have nothing to prove.
1296+ continue ;
1297+ } ;
1298+ let thin_state_diff = sequencer. get_thin_state_diff ( block_number) . await ;
1299+ for ( contract_address, storage_writes) in & thin_state_diff. storage_diffs {
1300+ let commitment_info = state_commitment_infos
1301+ . storage_tries_commitment_infos
1302+ . get ( contract_address)
1303+ . unwrap_or_else ( || {
1304+ panic ! (
1305+ "Block {block_number}: contract {contract_address} has storage writes \
1306+ but no storage-trie witnesses."
1307+ )
1308+ } ) ;
1309+ let preimages: PreimageMap = commitment_info
1310+ . commitment_facts
1311+ . iter ( )
1312+ . map ( |( fact_hash, raw_preimage) | {
1313+ let preimage = Preimage :: try_from ( raw_preimage) . unwrap_or_else ( |err| {
1314+ panic ! (
1315+ "Block {block_number}: invalid preimage for fact {fact_hash:?}: \
1316+ {err:?}"
1317+ )
1318+ } ) ;
1319+ ( * fact_hash, preimage)
1320+ } )
1321+ . collect ( ) ;
1322+ // A zero value is an absent leaf, proved by path structure rather than leaf hash.
1323+ let requested_leaves: HashMap < NodeIndex , HashOutput > = storage_writes
1324+ . iter ( )
1325+ . filter ( |( _, value) | * * value != Felt :: ZERO )
1326+ . map ( |( key, value) | {
1327+ ( NodeIndex :: from_leaf_felt ( key. 0 . key ( ) ) , HashOutput ( * value) )
1328+ } )
1329+ . collect ( ) ;
1330+ verify_patricia_proof :: < StarknetStorageValue , TreeHashFunctionImpl > (
1331+ commitment_info. updated_root ,
1332+ & preimages,
1333+ & requested_leaves,
1334+ )
1335+ . unwrap_or_else ( |err| {
1336+ panic ! (
1337+ "Block {block_number}: witness storage proof failed for contract \
1338+ {contract_address}: {err:?}"
1339+ )
1340+ } ) ;
1341+ }
1342+ }
1343+ }
1344+ }
1345+
12791346/// Verifies that the dummy recorders accepted every cende blob and that state commitment infos
12801347/// were carried in at least one blob.
12811348async fn verify_recorder_blobs_flow (
0 commit comments