Skip to content

Commit baf5a6b

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

1 file changed

Lines changed: 209 additions & 2 deletions

File tree

crates/apollo_committer/src/request_paths_and_commit_block_tests.rs

Lines changed: 209 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,196 @@ 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 node attesting to the topology of the new tree",
473+
);
474+
475+
// Today we also include the bottom of every traversed edge node. This is not necessary, and is
476+
// expected to fail once we are more strict in the fetched preimages.
477+
assert!(
478+
response.patricia_proofs.classes_trie_proof.contains_key(&node_g_hash),
479+
"missing bottom of a new edge node in a proof",
480+
);
481+
}
482+
483+
/// Flow overview:
484+
/// 1. Commit block 0 with three class leaves that form this Patricia topology:
485+
/// ```text
486+
/// R
487+
/// |
488+
/// T
489+
/// / \
490+
/// E F
491+
/// / \ \
492+
/// A B D
493+
/// ```
494+
/// 2. Commit block 1 via [crate::committer::Committer::read_paths_and_commit_block], deleting `D`
495+
/// and requesting witnesses only for the deleted key.
496+
/// 3. Assert the returned classes-trie proof contains node `E`. In this test, E is not the bottom
497+
/// of an existing edge, so it must be included in the proof to become convinced of the new
498+
/// tree's validity.
499+
#[tokio::test]
500+
async fn test_bottom_of_new_edge_to_a_binary_unmodified_subtree_is_present() {
501+
let class_hash_a = ClassHash(0_u64.into());
502+
let class_hash_b = ClassHash(1_u64.into());
503+
let class_hash_d = ClassHash(3_u64.into());
504+
505+
let compiled_class_hash_a_felt = 100_u64.into();
506+
let compiled_class_hash_b_felt = 101_u64.into();
507+
let compiled_class_hash_d_felt = 102_u64.into();
508+
509+
let mut committer = new_test_committer().await;
510+
let height_0 = 0;
511+
let height_1 = 1;
512+
let block_0_state_diff = ThinStateDiff {
513+
class_hash_to_compiled_class_hash: indexmap! {
514+
class_hash_a => CompiledClassHash(compiled_class_hash_a_felt),
515+
class_hash_b => CompiledClassHash(compiled_class_hash_b_felt),
516+
class_hash_d => CompiledClassHash(compiled_class_hash_d_felt),
517+
},
518+
..Default::default()
519+
};
520+
let block_1_state_diff = ThinStateDiff {
521+
class_hash_to_compiled_class_hash: indexmap! {
522+
class_hash_d => CompiledClassHash(0_u64.into()),
523+
},
524+
..Default::default()
525+
};
526+
let accessed_keys = AccessedKeys {
527+
accessed_class_hashes: BTreeSet::from([class_hash_d]),
528+
..Default::default()
529+
};
530+
531+
committer
532+
.commit_block(CommitBlockRequest {
533+
state_diff: block_0_state_diff.clone(),
534+
state_diff_commitment: Some(calculate_state_diff_hash(&block_0_state_diff)),
535+
height: BlockNumber(height_0),
536+
})
537+
.await
538+
.unwrap();
539+
540+
let response = committer
541+
.read_paths_and_commit_block(read_paths_and_commit_block_request(
542+
block_1_state_diff.clone(),
543+
Some(calculate_state_diff_hash(&block_1_state_diff)),
544+
height_1,
545+
accessed_keys,
546+
))
547+
.await
548+
.unwrap();
549+
550+
let leaf_a_hash = TreeHashFunctionImpl::compute_leaf_hash(&CommitterCompiledClassHash(
551+
compiled_class_hash_a_felt,
552+
));
553+
let leaf_b_hash = TreeHashFunctionImpl::compute_leaf_hash(&CommitterCompiledClassHash(
554+
compiled_class_hash_b_felt,
555+
));
556+
let node_e_hash = TreeHashFunctionImpl::compute_node_hash(&NodeData::<
557+
CommitterCompiledClassHash,
558+
HashOutput,
559+
>::Binary(BinaryData {
560+
left_data: leaf_a_hash,
561+
right_data: leaf_b_hash,
562+
}));
563+
564+
assert!(
565+
response.patricia_proofs.classes_trie_proof.contains_key(&node_e_hash),
566+
"missing bottom of a new edge node in a proof",
567+
);
568+
}

0 commit comments

Comments
 (0)