@@ -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 ;
@@ -359,3 +366,184 @@ async fn revert_removes_witnesses_and_digest() {
359366 assert_witnesses_and_digest_absent ( & mut committer, BlockNumber ( height_1) ) . await ;
360367 assert_eq ! ( committer. offset, BlockNumber ( height_1) ) ;
361368}
369+
370+ /// Flow overview:
371+ /// 1. Commit block 0 with three class leaves that form this Patricia topology:
372+ /// ```text
373+ /// R
374+ /// / \
375+ /// E F
376+ /// | |
377+ /// G |
378+ /// / \ \
379+ /// A B D
380+ /// ```
381+ /// 2. Commit block 1 via [crate::committer::Committer::read_paths_and_commit_block], deleting `D`
382+ /// and requesting witnesses only for the deleted key.
383+ /// 3. Assert the returned classes-trie proof contains node `G` (not strictly necessary, see comment
384+ /// below).
385+ #[ tokio:: test]
386+ async fn test_bottom_of_new_edge_to_an_unmoidifed_subtree_is_present ( ) {
387+ // Set the two leftmost and the rightmost leaves.
388+ let class_hash_a = ClassHash ( 0_u64 . into ( ) ) ;
389+ let class_hash_b = ClassHash ( 1_u64 . into ( ) ) ;
390+ let class_hash_d = ClassHash ( PATRICIA_KEY_UPPER_BOUND_FELT - 1_u64 ) ;
391+
392+ let compiled_class_hash_a_felt = 100_u64 . into ( ) ;
393+ let compiled_class_hash_b_felt = 101_u64 . into ( ) ;
394+ let compiled_class_hash_d_felt = 102_u64 . into ( ) ;
395+
396+ let mut committer = new_test_committer ( ) . await ;
397+ let height_0 = 0 ;
398+ let height_1 = 1 ;
399+ let block_0_state_diff = ThinStateDiff {
400+ class_hash_to_compiled_class_hash : indexmap ! {
401+ class_hash_a => CompiledClassHash ( compiled_class_hash_a_felt) ,
402+ class_hash_b => CompiledClassHash ( compiled_class_hash_b_felt) ,
403+ class_hash_d => CompiledClassHash ( compiled_class_hash_d_felt) ,
404+ } ,
405+ ..Default :: default ( )
406+ } ;
407+ let block_1_state_diff = ThinStateDiff {
408+ class_hash_to_compiled_class_hash : indexmap ! {
409+ class_hash_d => CompiledClassHash ( 0_u64 . into( ) ) ,
410+ } ,
411+ ..Default :: default ( )
412+ } ;
413+ let accessed_keys = AccessedKeys {
414+ accessed_class_hashes : BTreeSet :: from ( [ class_hash_d] ) ,
415+ ..Default :: default ( )
416+ } ;
417+
418+ committer
419+ . commit_block ( CommitBlockRequest {
420+ state_diff : block_0_state_diff. clone ( ) ,
421+ state_diff_commitment : Some ( calculate_state_diff_hash ( & block_0_state_diff) ) ,
422+ height : BlockNumber ( height_0) ,
423+ } )
424+ . await
425+ . unwrap ( ) ;
426+
427+ let response = committer
428+ . read_paths_and_commit_block ( read_paths_and_commit_block_request (
429+ block_1_state_diff. clone ( ) ,
430+ Some ( calculate_state_diff_hash ( & block_1_state_diff) ) ,
431+ height_1,
432+ accessed_keys,
433+ ) )
434+ . await
435+ . unwrap ( ) ;
436+
437+ let leaf_a_hash = TreeHashFunctionImpl :: compute_leaf_hash ( & CommitterCompiledClassHash (
438+ compiled_class_hash_a_felt,
439+ ) ) ;
440+ let leaf_b_hash = TreeHashFunctionImpl :: compute_leaf_hash ( & CommitterCompiledClassHash (
441+ compiled_class_hash_b_felt,
442+ ) ) ;
443+ let node_g_hash = TreeHashFunctionImpl :: compute_node_hash ( & NodeData :: <
444+ CommitterCompiledClassHash ,
445+ HashOutput ,
446+ > :: Binary ( BinaryData {
447+ left_data : leaf_a_hash,
448+ right_data : leaf_b_hash,
449+ } ) ) ;
450+
451+ // TODO(Ariel): the preimage of G is not really needed by the OS (it only needs R, F, and the
452+ // new root R', whose opening contains the hash of G). Change this to not contains or delete
453+ // this test after making request_paths_and_commit_block_request stricter.
454+ //
455+ // For completeness, the OS verifies:
456+ // hash(G_hash, truncated_path) + (len([R',G]) - 1) == E_hash.
457+ // This in turn also proves that G is not an edge node, as it's the bottom of an old
458+ // edge node, without explicitly requesting an opening of E.
459+ assert ! (
460+ response. patricia_proofs. classes_trie_proof. contains_key( & node_g_hash) ,
461+ "missing bottom of a new edge node in a proof" ,
462+ ) ;
463+ }
464+
465+ /// Flow overview:
466+ /// 1. Commit block 0 with three class leaves that form this Patricia topology:
467+ /// ```text
468+ /// R
469+ /// |
470+ /// T
471+ /// / \
472+ /// E F
473+ /// / \ \
474+ /// A B D
475+ /// ```
476+ /// 2. Commit block 1 via [crate::committer::Committer::read_paths_and_commit_block], deleting `D`
477+ /// and requesting witnesses only for the deleted key.
478+ /// 3. Assert the returned classes-trie proof contains node `E` (this will allow verifying that the
479+ /// new edge's bottom is not an edge).
480+ #[ tokio:: test]
481+ async fn test_bottom_of_new_edge_which_was_not_bottom_of_an_old_edge_is_present ( ) {
482+ let class_hash_a = ClassHash ( 0_u64 . into ( ) ) ;
483+ let class_hash_b = ClassHash ( 1_u64 . into ( ) ) ;
484+ let class_hash_d = ClassHash ( 3_u64 . into ( ) ) ;
485+
486+ let compiled_class_hash_a_felt = 100_u64 . into ( ) ;
487+ let compiled_class_hash_b_felt = 101_u64 . into ( ) ;
488+ let compiled_class_hash_d_felt = 102_u64 . into ( ) ;
489+
490+ let mut committer = new_test_committer ( ) . await ;
491+ let height_0 = 0 ;
492+ let height_1 = 1 ;
493+ let block_0_state_diff = ThinStateDiff {
494+ class_hash_to_compiled_class_hash : indexmap ! {
495+ class_hash_a => CompiledClassHash ( compiled_class_hash_a_felt) ,
496+ class_hash_b => CompiledClassHash ( compiled_class_hash_b_felt) ,
497+ class_hash_d => CompiledClassHash ( compiled_class_hash_d_felt) ,
498+ } ,
499+ ..Default :: default ( )
500+ } ;
501+ let block_1_state_diff = ThinStateDiff {
502+ class_hash_to_compiled_class_hash : indexmap ! {
503+ class_hash_d => CompiledClassHash ( 0_u64 . into( ) ) ,
504+ } ,
505+ ..Default :: default ( )
506+ } ;
507+ let accessed_keys = AccessedKeys {
508+ accessed_class_hashes : BTreeSet :: from ( [ class_hash_d] ) ,
509+ ..Default :: default ( )
510+ } ;
511+
512+ committer
513+ . commit_block ( CommitBlockRequest {
514+ state_diff : block_0_state_diff. clone ( ) ,
515+ state_diff_commitment : Some ( calculate_state_diff_hash ( & block_0_state_diff) ) ,
516+ height : BlockNumber ( height_0) ,
517+ } )
518+ . await
519+ . unwrap ( ) ;
520+
521+ let response = committer
522+ . read_paths_and_commit_block ( read_paths_and_commit_block_request (
523+ block_1_state_diff. clone ( ) ,
524+ Some ( calculate_state_diff_hash ( & block_1_state_diff) ) ,
525+ height_1,
526+ accessed_keys,
527+ ) )
528+ . await
529+ . unwrap ( ) ;
530+
531+ let leaf_a_hash = TreeHashFunctionImpl :: compute_leaf_hash ( & CommitterCompiledClassHash (
532+ compiled_class_hash_a_felt,
533+ ) ) ;
534+ let leaf_b_hash = TreeHashFunctionImpl :: compute_leaf_hash ( & CommitterCompiledClassHash (
535+ compiled_class_hash_b_felt,
536+ ) ) ;
537+ let node_e_hash = TreeHashFunctionImpl :: compute_node_hash ( & NodeData :: <
538+ CommitterCompiledClassHash ,
539+ HashOutput ,
540+ > :: Binary ( BinaryData {
541+ left_data : leaf_a_hash,
542+ right_data : leaf_b_hash,
543+ } ) ) ;
544+
545+ assert ! (
546+ response. patricia_proofs. classes_trie_proof. contains_key( & node_e_hash) ,
547+ "missing bottom of a new edge node in a proof" ,
548+ ) ;
549+ }
0 commit comments