@@ -3,93 +3,13 @@ mod test_helpers;
33use light_batched_merkle_tree:: {
44 merkle_tree:: BatchedMerkleTreeAccount , merkle_tree_ref:: BatchedMerkleTreeRef ,
55} ;
6- use light_compressed_account:: { pubkey:: Pubkey , TreeType , STATE_MERKLE_TREE_TYPE_V2 } ;
7- use light_merkle_tree_metadata:: { errors:: MerkleTreeMetadataError , merkle_tree :: MerkleTreeMetadata } ;
6+ use light_compressed_account:: { pubkey:: Pubkey , TreeType } ;
7+ use light_merkle_tree_metadata:: errors:: MerkleTreeMetadataError ;
88use test_helpers:: { account_builders:: MerkleTreeAccountBuilder , assertions:: * } ;
99
10- #[ test]
11- fn test_merkle_tree_ref_matches_mutable ( ) {
12- let mut account_data = vec ! [ 0u8 ; 3376 ] ;
13- let batch_size = 5 ;
14- let zkp_batch_size = 1 ;
15- let root_history_len = 10 ;
16- let num_iter = 1 ;
17- let bloom_filter_capacity = 8000 ;
18- let height = 40 ;
19- let pubkey = Pubkey :: new_unique ( ) ;
20-
21- // Initialize via mutable path.
22- let _account = BatchedMerkleTreeAccount :: init (
23- & mut account_data,
24- & pubkey,
25- MerkleTreeMetadata :: default ( ) ,
26- root_history_len,
27- batch_size,
28- zkp_batch_size,
29- height,
30- num_iter,
31- bloom_filter_capacity,
32- TreeType :: AddressV2 ,
33- )
34- . unwrap ( ) ;
35-
36- // Collect expected values from the mutable path.
37- let expected_metadata;
38- let expected_height;
39- let expected_tree_type;
40- let expected_seq;
41- let expected_pubkey;
42- let mut expected_roots = Vec :: new ( ) ;
43- let expected_bf0;
44- let expected_bf1;
45- {
46- let tree_mut =
47- BatchedMerkleTreeAccount :: address_from_bytes ( & mut account_data, & pubkey) . unwrap ( ) ;
48- expected_metadata = * tree_mut. get_metadata ( ) ;
49- expected_height = tree_mut. height ;
50- expected_tree_type = tree_mut. tree_type ;
51- expected_seq = tree_mut. sequence_number ;
52- expected_pubkey = * tree_mut. pubkey ( ) ;
53- for i in 0 ..root_history_len as usize {
54- expected_roots. push ( tree_mut. get_root_by_index ( i) . copied ( ) ) ;
55- }
56- expected_bf0 = tree_mut. bloom_filter_stores [ 0 ] . to_vec ( ) ;
57- expected_bf1 = tree_mut. bloom_filter_stores [ 1 ] . to_vec ( ) ;
58- }
59-
60- // Read via immutable ref.
61- let tree_ref = BatchedMerkleTreeRef :: address_from_bytes ( & account_data, & pubkey) . unwrap ( ) ;
62-
63- // Metadata should match (use Deref trait).
64- assert_eq ! ( * tree_ref, expected_metadata) ;
65- assert_eq ! ( tree_ref. height, expected_height) ;
66- assert_eq ! ( tree_ref. tree_type, expected_tree_type) ;
67- assert_eq ! ( tree_ref. sequence_number, expected_seq) ;
68- assert_eq ! ( * tree_ref. pubkey( ) , expected_pubkey) ;
69-
70- // Root history should match (using root_history() accessor).
71- for ( i, expected) in expected_roots. iter ( ) . enumerate ( ) {
72- assert_eq ! ( Some ( * tree_ref. get_root_by_index( i) . unwrap( ) ) , * expected) ;
73- }
74-
75- // Bloom filter stores should match.
76- assert_eq ! ( tree_ref. bloom_filter_stores[ 0 ] , expected_bf0. as_slice( ) ) ;
77- assert_eq ! ( tree_ref. bloom_filter_stores[ 1 ] , expected_bf1. as_slice( ) ) ;
78-
79- // Non-inclusion check should work.
80- let random_value = [ 42u8 ; 32 ] ;
81- tree_ref
82- . check_input_queue_non_inclusion ( & random_value)
83- . unwrap ( ) ;
84- }
85-
86- // ============================================================================
87- // New comprehensive tests for 100% coverage
88- // ============================================================================
89-
9010#[ test]
9111fn test_merkle_tree_ref_deserialization_matrix ( ) {
92- // Test matrix: tree type × API method (table-driven test)
12+ // Test matrix: tree type x API method (table-driven test)
9313 let test_cases = vec ! [
9414 ( "State tree with state API" , TreeType :: StateV2 , "state" , true ) ,
9515 ( "Address tree with address API" , TreeType :: AddressV2 , "address" , true ) ,
@@ -160,211 +80,15 @@ fn test_merkle_tree_ref_from_bytes_errors() {
16080 MerkleTreeMetadataError :: InvalidTreeType ,
16181 "Wrong tree type should fail" ,
16282 ) ;
163- }
164-
165- #[ test]
166- fn test_merkle_tree_ref_root_history_access ( ) {
167- let ( mut account_data, pubkey) = MerkleTreeAccountBuilder :: state_tree ( ) . build ( ) ;
168- let root_history_len = 10 ;
169-
170- // Populate root history via mutable ref and collect expected values
171- let mut expected_roots = Vec :: new ( ) ;
172- {
173- let mut tree_mut = BatchedMerkleTreeAccount :: state_from_bytes ( & mut account_data, & pubkey) . unwrap ( ) ;
174- // Init already pushed an initial root at index 0. Push additional values.
175- for i in 1u8 ..6 {
176- tree_mut. root_history . push ( [ i; 32 ] ) ;
177- }
178- // Collect expected root values from mutable path
179- for i in 0 ..root_history_len as usize {
180- expected_roots. push ( tree_mut. get_root_by_index ( i) . copied ( ) ) ;
181- }
182- }
183-
184- // Access via immutable ref
185- let tree_ref = BatchedMerkleTreeRef :: state_from_bytes ( & account_data, & pubkey) . unwrap ( ) ;
186-
187- // Verify root_history at physical indices matches mutable path
188- for ( i, expected) in expected_roots. iter ( ) . enumerate ( ) {
189- assert_eq ! (
190- Some ( * tree_ref. get_root_by_index( i) . unwrap( ) ) ,
191- * expected,
192- "Root at index {} should match" ,
193- i
194- ) ;
195- }
196- }
19783
198- #[ test]
199- fn test_merkle_tree_ref_root_history_boundaries ( ) {
200- let ( mut account_data, pubkey) = MerkleTreeAccountBuilder :: state_tree ( ) . build ( ) ;
201- let root_history_len = 10 ;
202-
203- // Collect boundary values from the mutable path
204- let first_root;
205- let last_root;
206- {
207- let tree_mut = BatchedMerkleTreeAccount :: state_from_bytes ( & mut account_data, & pubkey) . unwrap ( ) ;
208- // Init already pushed an initial root. Collect it at index 0.
209- first_root = tree_mut. get_root_by_index ( 0 ) . copied ( ) . unwrap ( ) ;
210- last_root = tree_mut. get_root_by_index ( ( root_history_len - 1 ) as usize ) . copied ( ) . unwrap ( ) ;
211- }
212-
213- let tree_ref = BatchedMerkleTreeRef :: state_from_bytes ( & account_data, & pubkey) . unwrap ( ) ;
214-
215- // Verify boundary access works (index 0 and capacity-1)
216- assert_eq ! (
217- * tree_ref. get_root_by_index( 0 ) . unwrap( ) ,
218- first_root,
219- "First root should be accessible"
220- ) ;
221- assert_eq ! (
222- * tree_ref
223- . get_root_by_index( ( root_history_len - 1 ) as usize )
224- . unwrap( ) ,
225- last_root,
226- "Last root should be accessible"
227- ) ;
228- }
229-
230- #[ test]
231- fn test_merkle_tree_ref_root_history_out_of_bounds ( ) {
84+ // Test 5: Root history out-of-bounds returns None
23285 let ( data, pubkey) = MerkleTreeAccountBuilder :: state_tree ( )
23386 . with_root_history_capacity ( 5 )
23487 . build ( ) ;
235-
23688 let tree_ref = BatchedMerkleTreeRef :: state_from_bytes ( & data, & pubkey) . unwrap ( ) ;
237-
238- // Access beyond length returns None
23989 assert ! ( tree_ref. get_root_by_index( 10 ) . is_none( ) ) ;
24090}
24191
242- #[ test]
243- fn test_merkle_tree_ref_bloom_filter_stores ( ) {
244- let ( data, pubkey) = MerkleTreeAccountBuilder :: state_tree ( )
245- . with_bloom_filter_capacity ( 8000 )
246- . build ( ) ;
247-
248- let tree_ref = BatchedMerkleTreeRef :: state_from_bytes ( & data, & pubkey) . unwrap ( ) ;
249-
250- // Verify bloom filter stores are accessible
251- assert_eq ! (
252- tree_ref. bloom_filter_stores. len( ) ,
253- 2 ,
254- "Should have 2 bloom filter stores"
255- ) ;
256-
257- // Each bloom filter store should have the correct size (capacity / 8)
258- let expected_size = 8000 / 8 ;
259- assert_eq ! (
260- tree_ref. bloom_filter_stores[ 0 ] . len( ) ,
261- expected_size,
262- "First bloom filter store should have correct size"
263- ) ;
264- assert_eq ! (
265- tree_ref. bloom_filter_stores[ 1 ] . len( ) ,
266- expected_size,
267- "Second bloom filter store should have correct size"
268- ) ;
269- }
270-
271- #[ test]
272- fn test_merkle_tree_ref_check_non_inclusion_empty ( ) {
273- // Table-driven test: various values against empty bloom filters
274- let test_values = vec ! [
275- [ 0u8 ; 32 ] ,
276- [ 0xFF ; 32 ] ,
277- [ 0x55 ; 32 ] ,
278- [ 0xAA ; 32 ] ,
279- ] ;
280-
281- let ( data, pubkey) = MerkleTreeAccountBuilder :: state_tree ( ) . build ( ) ;
282- let tree_ref = BatchedMerkleTreeRef :: state_from_bytes ( & data, & pubkey) . unwrap ( ) ;
283-
284- // All should pass non-inclusion check (no values inserted yet)
285- for ( i, value) in test_values. iter ( ) . enumerate ( ) {
286- tree_ref
287- . check_input_queue_non_inclusion ( value)
288- . unwrap_or_else ( |_| panic ! ( "Test value {} should pass non-inclusion on empty filter" , i) ) ;
289- }
290- }
291-
292- #[ test]
293- fn test_merkle_tree_ref_check_non_inclusion_with_values ( ) {
294- let ( mut account_data, pubkey) = MerkleTreeAccountBuilder :: state_tree ( )
295- . with_num_iters ( 3 )
296- . build ( ) ;
297-
298- let inserted_value = [ 0x42 ; 32 ] ;
299- let non_inserted_value = [ 0x99 ; 32 ] ;
300-
301- // Insert value into bloom filter via mutable path
302- {
303- let mut tree_mut = BatchedMerkleTreeAccount :: state_from_bytes ( & mut account_data, & pubkey) . unwrap ( ) ;
304- // Insert into current batch's bloom filter
305- use light_bloom_filter:: BloomFilter ;
306- // Get metadata values first before borrowing bloom_filter_stores
307- let num_iters = tree_mut. queue_batches . batches [ 0 ] . num_iters as usize ;
308- let capacity = tree_mut. queue_batches . batches [ 0 ] . bloom_filter_capacity ;
309- let bloom_filter = & mut tree_mut. bloom_filter_stores [ 0 ] ;
310- let mut bf = BloomFilter :: new ( num_iters, capacity, bloom_filter) . unwrap ( ) ;
311- bf. insert ( & inserted_value) . unwrap ( ) ;
312- }
313-
314- // Read via immutable ref
315- let tree_ref = BatchedMerkleTreeRef :: state_from_bytes ( & account_data, & pubkey) . unwrap ( ) ;
316-
317- // Check inserted value fails non-inclusion
318- assert ! (
319- tree_ref. check_input_queue_non_inclusion( & inserted_value) . is_err( ) ,
320- "Inserted value should fail non-inclusion check"
321- ) ;
322-
323- // Check non-inserted value passes non-inclusion
324- assert ! (
325- tree_ref. check_input_queue_non_inclusion( & non_inserted_value) . is_ok( ) ,
326- "Non-inserted value should pass non-inclusion check"
327- ) ;
328- }
329-
330- #[ test]
331- fn test_merkle_tree_ref_metadata_deref ( ) {
332- let ( data, pubkey) = MerkleTreeAccountBuilder :: state_tree ( )
333- . with_height ( 26 )
334- . build ( ) ;
335-
336- let tree_ref = BatchedMerkleTreeRef :: state_from_bytes ( & data, & pubkey) . unwrap ( ) ;
337-
338- // Access metadata fields via Deref
339- assert_eq ! (
340- tree_ref. tree_type,
341- STATE_MERKLE_TREE_TYPE_V2 ,
342- "tree_type should be accessible via Deref"
343- ) ;
344- assert_eq ! (
345- tree_ref. height,
346- 26 ,
347- "height should be accessible via Deref"
348- ) ;
349- assert_eq ! (
350- tree_ref. sequence_number,
351- 0 ,
352- "sequence_number should be accessible via Deref"
353- ) ;
354-
355- // Access queue_batches fields
356- assert_eq ! (
357- tree_ref. queue_batches. num_batches,
358- 2 ,
359- "num_batches should be accessible"
360- ) ;
361- assert_eq ! (
362- tree_ref. queue_batches. batch_size,
363- 5 ,
364- "batch_size should be accessible"
365- ) ;
366- }
367-
36892#[ test]
36993fn test_merkle_tree_ref_different_configurations ( ) {
37094 // Table-driven test: different tree configurations
@@ -529,4 +253,31 @@ fn test_merkle_tree_ref_randomized_equivalence() {
529253 // Pubkey.
530254 assert_eq ! ( tree_ref. pubkey( ) , tree_mut. pubkey( ) ) ;
531255 }
256+
257+ // Non-inclusion coverage: insert a known value and verify it fails non-inclusion,
258+ // while a non-inserted value passes.
259+ let inserted_value = [ 0x42 ; 32 ] ;
260+ let non_inserted_value = [ 0x99 ; 32 ] ;
261+ {
262+ let mut tree_mut =
263+ BatchedMerkleTreeAccount :: state_from_bytes ( & mut account_data, & pubkey) . unwrap ( ) ;
264+ let num_iters = tree_mut. queue_batches . batches [ 0 ] . num_iters as usize ;
265+ let capacity = tree_mut. queue_batches . batches [ 0 ] . bloom_filter_capacity ;
266+ let mut bf =
267+ BloomFilter :: new ( num_iters, capacity, & mut tree_mut. bloom_filter_stores [ 0 ] ) . unwrap ( ) ;
268+ bf. insert ( & inserted_value) . unwrap ( ) ;
269+ }
270+ let tree_ref = BatchedMerkleTreeRef :: state_from_bytes ( & account_data, & pubkey) . unwrap ( ) ;
271+ assert ! (
272+ tree_ref
273+ . check_input_queue_non_inclusion( & inserted_value)
274+ . is_err( ) ,
275+ "Inserted value should fail non-inclusion check"
276+ ) ;
277+ assert ! (
278+ tree_ref
279+ . check_input_queue_non_inclusion( & non_inserted_value)
280+ . is_ok( ) ,
281+ "Non-inserted value should pass non-inclusion check"
282+ ) ;
532283}
0 commit comments