Skip to content

Commit 1bdd2ea

Browse files
committed
apollo_committer: test new edge bottom in witnesses
1 parent eae40db commit 1bdd2ea

1 file changed

Lines changed: 202 additions & 2 deletions

File tree

crates/apollo_committer/src/request_paths_and_commit_block_tests.rs

Lines changed: 202 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,13 @@ use apollo_committer_types::committer_types::{
1010
use indexmap::indexmap;
1111
use starknet_api::block::BlockNumber;
1212
use 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+
};
1420
use starknet_api::hash::HashOutput;
1521
use starknet_api::state::ThinStateDiff;
1622
use starknet_committer::block_committer::input::{
@@ -30,9 +36,17 @@ 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::{
40+
BinaryData,
41+
EdgeData,
42+
EdgePath,
43+
EdgePathLength,
44+
NodeData,
45+
PathToBottom,
46+
};
3347
use starknet_patricia::patricia_merkle_tree::node_data::leaf::Leaf;
3448
use starknet_patricia::patricia_merkle_tree::storage_proof_verification::verify_patricia_proof;
35-
use starknet_patricia::patricia_merkle_tree::types::NodeIndex;
49+
use starknet_patricia::patricia_merkle_tree::types::{NodeIndex, SubTreeHeight};
3650
use starknet_patricia::patricia_merkle_tree::updated_skeleton_tree::hash_function::TreeHashFunction;
3751

3852
use crate::committer::committer_test::{new_test_committer, ApolloTestCommitter};
@@ -359,3 +373,189 @@ async fn revert_removes_witnesses_and_digest() {
359373
assert_witnesses_and_digest_absent(&mut committer, BlockNumber(height_1)).await;
360374
assert_eq!(committer.offset, BlockNumber(height_1));
361375
}
376+
377+
/// Flow overview:
378+
/// 1. Commit block 0 with three class leaves that form this Patricia topology:
379+
/// ```text
380+
/// R
381+
/// / \
382+
/// E F
383+
/// | |
384+
/// G |
385+
/// / \ \
386+
/// A B D
387+
/// ```
388+
/// 2. Commit block 1 via [crate::committer::Committer::read_paths_and_commit_block], deleting `D`
389+
/// and requesting witnesses only for the deleted key.
390+
/// 3. Assert the returned classes-trie proof contains node `E`.
391+
#[tokio::test]
392+
async fn test_bottom_of_new_edge_to_an_unmoidifed_subtree_is_present() {
393+
// Set the two leftmost and the rightmost leaves.
394+
let class_hash_a = ClassHash(0_u64.into());
395+
let class_hash_b = ClassHash(1_u64.into());
396+
let class_hash_d = ClassHash(PATRICIA_KEY_UPPER_BOUND_FELT - 1_u64);
397+
398+
let compiled_class_hash_a_felt = 100_u64.into();
399+
let compiled_class_hash_b_felt = 101_u64.into();
400+
let compiled_class_hash_d_felt = 102_u64.into();
401+
402+
let mut committer = new_test_committer().await;
403+
let height_0 = 0;
404+
let height_1 = 1;
405+
let block_0_state_diff = ThinStateDiff {
406+
class_hash_to_compiled_class_hash: indexmap! {
407+
class_hash_a => CompiledClassHash(compiled_class_hash_a_felt),
408+
class_hash_b => CompiledClassHash(compiled_class_hash_b_felt),
409+
class_hash_d => CompiledClassHash(compiled_class_hash_d_felt),
410+
},
411+
..Default::default()
412+
};
413+
let block_1_state_diff = ThinStateDiff {
414+
class_hash_to_compiled_class_hash: indexmap! {
415+
class_hash_d => CompiledClassHash(0_u64.into()),
416+
},
417+
..Default::default()
418+
};
419+
let accessed_keys = AccessedKeys {
420+
accessed_class_hashes: BTreeSet::from([class_hash_d]),
421+
..Default::default()
422+
};
423+
424+
committer
425+
.commit_block(CommitBlockRequest {
426+
state_diff: block_0_state_diff.clone(),
427+
state_diff_commitment: Some(calculate_state_diff_hash(&block_0_state_diff)),
428+
height: BlockNumber(height_0),
429+
})
430+
.await
431+
.unwrap();
432+
433+
let response = committer
434+
.read_paths_and_commit_block(read_paths_and_commit_block_request(
435+
block_1_state_diff.clone(),
436+
Some(calculate_state_diff_hash(&block_1_state_diff)),
437+
height_1,
438+
accessed_keys,
439+
))
440+
.await
441+
.unwrap();
442+
443+
let leaf_a_hash = TreeHashFunctionImpl::compute_leaf_hash(&CommitterCompiledClassHash(
444+
compiled_class_hash_a_felt,
445+
));
446+
let leaf_b_hash = TreeHashFunctionImpl::compute_leaf_hash(&CommitterCompiledClassHash(
447+
compiled_class_hash_b_felt,
448+
));
449+
let node_g_hash = TreeHashFunctionImpl::compute_node_hash(&NodeData::<
450+
CommitterCompiledClassHash,
451+
HashOutput,
452+
>::Binary(BinaryData {
453+
left_data: leaf_a_hash,
454+
right_data: leaf_b_hash,
455+
}));
456+
// Keys 0 and 1 place G one level above the leaves; E is the root's left child.
457+
let path_e_to_g = PathToBottom::new(
458+
EdgePath::default(),
459+
EdgePathLength::new(SubTreeHeight::ACTUAL_HEIGHT.0 - 1).expect("Illegal edge path length"),
460+
)
461+
.expect("Illegal path from E to G");
462+
let node_e_hash = TreeHashFunctionImpl::compute_node_hash(&NodeData::<
463+
CommitterCompiledClassHash,
464+
HashOutput,
465+
>::Edge(EdgeData {
466+
bottom_data: node_g_hash,
467+
path_to_bottom: path_e_to_g,
468+
}));
469+
470+
assert!(
471+
response.patricia_proofs.classes_trie_proof.contains_key(&node_e_hash),
472+
"missing bottom of a new edge node in a proof",
473+
);
474+
}
475+
476+
/// Flow overview:
477+
/// 1. Commit block 0 with three class leaves that form this Patricia topology:
478+
/// ```text
479+
/// R
480+
/// |
481+
/// T
482+
/// / \
483+
/// E F
484+
/// / \ \
485+
/// A B D
486+
/// ```
487+
/// 2. Commit block 1 via [crate::committer::Committer::read_paths_and_commit_block], deleting `D`
488+
/// and requesting witnesses only for the deleted key.
489+
/// 3. Assert the returned classes-trie proof contains node `E`. In this test, E is not the bottom
490+
/// of an existing edge, so it must be included in the proof to become convinced of the new
491+
/// tree's validity.
492+
#[tokio::test]
493+
async fn test_bottom_of_new_edge_to_a_binary_unmodified_subtree_is_present() {
494+
let class_hash_a = ClassHash(0_u64.into());
495+
let class_hash_b = ClassHash(1_u64.into());
496+
let class_hash_d = ClassHash(3_u64.into());
497+
498+
let compiled_class_hash_a_felt = 100_u64.into();
499+
let compiled_class_hash_b_felt = 101_u64.into();
500+
let compiled_class_hash_d_felt = 102_u64.into();
501+
502+
let mut committer = new_test_committer().await;
503+
let height_0 = 0;
504+
let height_1 = 1;
505+
let block_0_state_diff = ThinStateDiff {
506+
class_hash_to_compiled_class_hash: indexmap! {
507+
class_hash_a => CompiledClassHash(compiled_class_hash_a_felt),
508+
class_hash_b => CompiledClassHash(compiled_class_hash_b_felt),
509+
class_hash_d => CompiledClassHash(compiled_class_hash_d_felt),
510+
},
511+
..Default::default()
512+
};
513+
let block_1_state_diff = ThinStateDiff {
514+
class_hash_to_compiled_class_hash: indexmap! {
515+
class_hash_d => CompiledClassHash(0_u64.into()),
516+
},
517+
..Default::default()
518+
};
519+
let accessed_keys = AccessedKeys {
520+
accessed_class_hashes: BTreeSet::from([class_hash_d]),
521+
..Default::default()
522+
};
523+
524+
committer
525+
.commit_block(CommitBlockRequest {
526+
state_diff: block_0_state_diff.clone(),
527+
state_diff_commitment: Some(calculate_state_diff_hash(&block_0_state_diff)),
528+
height: BlockNumber(height_0),
529+
})
530+
.await
531+
.unwrap();
532+
533+
let response = committer
534+
.read_paths_and_commit_block(read_paths_and_commit_block_request(
535+
block_1_state_diff.clone(),
536+
Some(calculate_state_diff_hash(&block_1_state_diff)),
537+
height_1,
538+
accessed_keys,
539+
))
540+
.await
541+
.unwrap();
542+
543+
let leaf_a_hash = TreeHashFunctionImpl::compute_leaf_hash(&CommitterCompiledClassHash(
544+
compiled_class_hash_a_felt,
545+
));
546+
let leaf_b_hash = TreeHashFunctionImpl::compute_leaf_hash(&CommitterCompiledClassHash(
547+
compiled_class_hash_b_felt,
548+
));
549+
let node_e_hash = TreeHashFunctionImpl::compute_node_hash(&NodeData::<
550+
CommitterCompiledClassHash,
551+
HashOutput,
552+
>::Binary(BinaryData {
553+
left_data: leaf_a_hash,
554+
right_data: leaf_b_hash,
555+
}));
556+
557+
assert!(
558+
response.patricia_proofs.classes_trie_proof.contains_key(&node_e_hash),
559+
"missing bottom of a new edge node in a proof",
560+
);
561+
}

0 commit comments

Comments
 (0)