@@ -389,3 +389,112 @@ async fn test_append_bug_repro_2() {
389
389
}
390
390
assert_eq ! ( cmt. get_change_log( ) . root, tree. get_root( ) ) ;
391
391
}
392
+
393
+ #[ tokio:: test( flavor = "multi_thread" ) ]
394
+ /// Test that empty trees are checked properly by adding & removing leaves one by one
395
+ async fn test_prove_tree_empty_incremental ( ) {
396
+ let ( mut cmt, mut tree) = setup ( ) ;
397
+ let mut rng = thread_rng ( ) ;
398
+ cmt. initialize ( ) . unwrap ( ) ;
399
+
400
+ cmt. prove_tree_is_empty ( ) . unwrap ( ) ;
401
+
402
+ // Append a random leaf & remove it, and make sure that the tree is empty at the end
403
+ let tree_size = 64 ;
404
+ for i in 0 ..tree_size {
405
+ let leaf = rng. gen :: < [ u8 ; 32 ] > ( ) ;
406
+ cmt. append ( leaf) . unwrap ( ) ;
407
+ tree. add_leaf ( leaf, i) ;
408
+
409
+ match cmt. prove_tree_is_empty ( ) {
410
+ Ok ( _) => {
411
+ panic ! ( "Tree has a leaf in it -- should not be possible to prove empty!" )
412
+ }
413
+ Err ( e) => match e {
414
+ ConcurrentMerkleTreeError :: TreeNonEmpty => { }
415
+ _ => {
416
+ panic ! ( "Wrong error thrown. Expected TreeNonEmpty erro" )
417
+ }
418
+ } ,
419
+ }
420
+
421
+ cmt. set_leaf (
422
+ tree. get_root ( ) ,
423
+ tree. get_leaf ( i) ,
424
+ EMPTY ,
425
+ & tree. get_proof_of_leaf ( i) ,
426
+ i as u32 ,
427
+ )
428
+ . unwrap ( ) ;
429
+ tree. add_leaf ( EMPTY , i) ;
430
+
431
+ cmt. prove_tree_is_empty ( ) . unwrap ( ) ;
432
+ }
433
+ }
434
+
435
+ #[ tokio:: test( flavor = "multi_thread" ) ]
436
+ /// Test that empty trees are checked properly by adding & removing leaves in a batch
437
+ async fn test_prove_tree_empty_batched ( ) {
438
+ let ( mut cmt, mut tree) = setup ( ) ;
439
+ let mut rng = thread_rng ( ) ;
440
+ cmt. initialize ( ) . unwrap ( ) ;
441
+
442
+ // Sanity check
443
+ cmt. prove_tree_is_empty ( ) . unwrap ( ) ;
444
+
445
+ // Add random leaves to the tree
446
+ let tree_size = 64 ;
447
+ for i in 0 ..tree_size {
448
+ let leaf = rng. gen :: < [ u8 ; 32 ] > ( ) ;
449
+ cmt. append ( leaf) . unwrap ( ) ;
450
+ tree. add_leaf ( leaf, i) ;
451
+
452
+ match cmt. prove_tree_is_empty ( ) {
453
+ Ok ( _) => {
454
+ panic ! ( "Tree has a leaf in it -- should not be possible to prove empty!" )
455
+ }
456
+ Err ( e) => match e {
457
+ ConcurrentMerkleTreeError :: TreeNonEmpty => { }
458
+ _ => {
459
+ panic ! ( "Wrong error thrown. Expected TreeNonEmpty erro" )
460
+ }
461
+ } ,
462
+ }
463
+ }
464
+ // Remove random leaves
465
+ for i in 0 ..tree_size - 1 {
466
+ cmt. set_leaf (
467
+ tree. get_root ( ) ,
468
+ tree. get_leaf ( i) ,
469
+ EMPTY ,
470
+ & tree. get_proof_of_leaf ( i) ,
471
+ i as u32 ,
472
+ )
473
+ . unwrap ( ) ;
474
+ tree. add_leaf ( EMPTY , i) ;
475
+
476
+ match cmt. prove_tree_is_empty ( ) {
477
+ Ok ( _) => {
478
+ panic ! ( "Tree has a leaf in it -- should not be possible to prove empty!" )
479
+ }
480
+ Err ( e) => match e {
481
+ ConcurrentMerkleTreeError :: TreeNonEmpty => { }
482
+ _ => {
483
+ panic ! ( "Wrong error thrown. Expected TreeNonEmpty erro" )
484
+ }
485
+ } ,
486
+ }
487
+ }
488
+ cmt. set_leaf (
489
+ tree. get_root ( ) ,
490
+ tree. get_leaf ( tree_size - 1 ) ,
491
+ EMPTY ,
492
+ & tree. get_proof_of_leaf ( tree_size - 1 ) ,
493
+ ( tree_size - 1 ) as u32 ,
494
+ )
495
+ . unwrap ( ) ;
496
+ tree. add_leaf ( EMPTY , tree_size - 1 ) ;
497
+
498
+ // Check that the last leaf was successfully removed
499
+ cmt. prove_tree_is_empty ( ) . unwrap ( ) ;
500
+ }
0 commit comments