@@ -10,7 +10,13 @@ use apollo_committer_types::committer_types::{
1010use indexmap:: indexmap;
1111use starknet_api:: block:: BlockNumber ;
1212use starknet_api:: block_hash:: state_diff_hash:: calculate_state_diff_hash;
13- use starknet_api:: core:: { ClassHash , CompiledClassHash , ContractAddress , StateDiffCommitment } ;
13+ use starknet_api:: core:: {
14+ ClassHash ,
15+ CompiledClassHash ,
16+ ContractAddress ,
17+ StateDiffCommitment ,
18+ PATRICIA_KEY_UPPER_BOUND_FELT ,
19+ } ;
1420use starknet_api:: hash:: HashOutput ;
1521use starknet_api:: state:: ThinStateDiff ;
1622use starknet_committer:: block_committer:: input:: {
@@ -30,6 +36,7 @@ use starknet_committer::patricia_merkle_tree::types::{
3036 CompiledClassHash as CommitterCompiledClassHash ,
3137 StarknetForestProofs ,
3238} ;
39+ use starknet_patricia:: patricia_merkle_tree:: node_data:: inner_node:: { BinaryData , NodeData } ;
3340use starknet_patricia:: patricia_merkle_tree:: node_data:: leaf:: Leaf ;
3441use starknet_patricia:: patricia_merkle_tree:: storage_proof_verification:: verify_patricia_proof;
3542use starknet_patricia:: patricia_merkle_tree:: types:: NodeIndex ;
@@ -391,3 +398,88 @@ async fn revert_removes_witnesses_and_digest() {
391398 assert_witnesses_and_digest_absent ( & mut committer, BlockNumber ( height_1) ) . await ;
392399 assert_eq ! ( committer. offset, BlockNumber ( height_1) ) ;
393400}
401+
402+ /// Flow overview:
403+ /// 1. Commit block 0 with three class leaves that form this Patricia topology:
404+ /// ```text
405+ /// R
406+ /// / \
407+ /// E F
408+ /// / \ \
409+ /// A B .
410+ /// .
411+ /// D
412+ /// ```
413+ /// 2. Commit block 1 via [crate::committer::Committer::read_paths_and_commit_block], deleting `D`
414+ /// and requesting witnesses only for the deleted key.
415+ /// 3. Assert the returned classes-trie proof contains node `E`.
416+ #[ tokio:: test]
417+ async fn test_bottom_of_new_edge_to_an_unmoidifed_subtree_is_present ( ) {
418+ // Set the two leftmost and the rightmost leaves.
419+ let class_hash_a = ClassHash ( 0_u64 . into ( ) ) ;
420+ let class_hash_b = ClassHash ( 1_u64 . into ( ) ) ;
421+ let class_hash_d = ClassHash ( PATRICIA_KEY_UPPER_BOUND_FELT - 1_u64 ) ;
422+
423+ let compiled_class_hash_a_felt = 100_u64 . into ( ) ;
424+ let compiled_class_hash_b_felt = 101_u64 . into ( ) ;
425+ let compiled_class_hash_d_felt = 102_u64 . into ( ) ;
426+
427+ let mut committer = new_test_committer ( ) . await ;
428+ let height_0 = 0 ;
429+ let height_1 = 1 ;
430+ let block_0_state_diff = ThinStateDiff {
431+ class_hash_to_compiled_class_hash : indexmap ! {
432+ class_hash_a => CompiledClassHash ( compiled_class_hash_a_felt) ,
433+ class_hash_b => CompiledClassHash ( compiled_class_hash_b_felt) ,
434+ class_hash_d => CompiledClassHash ( compiled_class_hash_d_felt) ,
435+ } ,
436+ ..Default :: default ( )
437+ } ;
438+ let block_1_state_diff = ThinStateDiff {
439+ class_hash_to_compiled_class_hash : indexmap ! {
440+ class_hash_d => CompiledClassHash ( 0_u64 . into( ) ) ,
441+ } ,
442+ ..Default :: default ( )
443+ } ;
444+ let accessed_keys = AccessedKeys {
445+ accessed_class_hashes : BTreeSet :: from ( [ class_hash_d] ) ,
446+ ..Default :: default ( )
447+ } ;
448+
449+ committer
450+ . commit_block ( CommitBlockRequest {
451+ state_diff : block_0_state_diff. clone ( ) ,
452+ state_diff_commitment : Some ( calculate_state_diff_hash ( & block_0_state_diff) ) ,
453+ height : BlockNumber ( height_0) ,
454+ } )
455+ . await
456+ . unwrap ( ) ;
457+
458+ let response = committer
459+ . read_paths_and_commit_block ( read_paths_and_commit_block_request (
460+ block_1_state_diff. clone ( ) ,
461+ Some ( calculate_state_diff_hash ( & block_1_state_diff) ) ,
462+ height_1,
463+ accessed_keys,
464+ ) )
465+ . await
466+ . unwrap ( ) ;
467+
468+ let leaf_a_hash = TreeHashFunctionImpl :: compute_leaf_hash ( & CommitterCompiledClassHash (
469+ compiled_class_hash_a_felt,
470+ ) ) ;
471+ let leaf_b_hash = TreeHashFunctionImpl :: compute_leaf_hash ( & CommitterCompiledClassHash (
472+ compiled_class_hash_b_felt,
473+ ) ) ;
474+ let edge_tree_node_e_hash = TreeHashFunctionImpl :: compute_node_hash ( & NodeData :: <
475+ CommitterCompiledClassHash ,
476+ HashOutput ,
477+ > :: Binary (
478+ BinaryData { left_data : leaf_a_hash, right_data : leaf_b_hash } ,
479+ ) ) ;
480+
481+ assert ! (
482+ response. patricia_proofs. classes_trie_proof. contains_key( & edge_tree_node_e_hash) ,
483+ "missing bottom of a new edge node in a proof" ,
484+ ) ;
485+ }
0 commit comments