@@ -2580,8 +2580,8 @@ fn signers_broadcast_signed_blocks() {
2580
2580
2581
2581
#[ test]
2582
2582
#[ ignore]
2583
- /// This test verifies that a miner will produce a TenureExtend transaction after the idle timeout is reached.
2584
- fn tenure_extend_after_idle ( ) {
2583
+ /// This test verifies that a miner will produce a TenureExtend transaction after the signers' idle timeout is reached.
2584
+ fn tenure_extend_after_idle_signers ( ) {
2585
2585
if env:: var ( "BITCOIND_TEST" ) != Ok ( "1" . into ( ) ) {
2586
2586
return ;
2587
2587
}
@@ -2629,6 +2629,173 @@ fn tenure_extend_after_idle() {
2629
2629
signer_test. shutdown ( ) ;
2630
2630
}
2631
2631
2632
+ #[ test]
2633
+ #[ ignore]
2634
+ /// This test verifies that a miner will produce a TenureExtend transaction after the miner's idle timeout
2635
+ /// even if they do not see the signers' tenure extend timestamp responses.
2636
+ fn tenure_extend_after_idle_miner ( ) {
2637
+ if env:: var ( "BITCOIND_TEST" ) != Ok ( "1" . into ( ) ) {
2638
+ return ;
2639
+ }
2640
+
2641
+ tracing_subscriber:: registry ( )
2642
+ . with ( fmt:: layer ( ) )
2643
+ . with ( EnvFilter :: from_default_env ( ) )
2644
+ . init ( ) ;
2645
+
2646
+ info ! ( "------------------------- Test Setup -------------------------" ) ;
2647
+ let num_signers = 5 ;
2648
+ let sender_sk = Secp256k1PrivateKey :: new ( ) ;
2649
+ let sender_addr = tests:: to_addr ( & sender_sk) ;
2650
+ let send_amt = 100 ;
2651
+ let send_fee = 180 ;
2652
+ let _recipient = PrincipalData :: from ( StacksAddress :: burn_address ( false ) ) ;
2653
+ let idle_timeout = Duration :: from_secs ( 30 ) ;
2654
+ let miner_idle_timeout = idle_timeout + Duration :: from_secs ( 10 ) ;
2655
+ let mut signer_test: SignerTest < SpawnedSigner > = SignerTest :: new_with_config_modifications (
2656
+ num_signers,
2657
+ vec ! [ ( sender_addr, send_amt + send_fee) ] ,
2658
+ |config| {
2659
+ config. tenure_idle_timeout = idle_timeout;
2660
+ } ,
2661
+ |config| {
2662
+ config. miner . tenure_timeout = miner_idle_timeout;
2663
+ } ,
2664
+ None ,
2665
+ None ,
2666
+ ) ;
2667
+ let _http_origin = format ! ( "http://{}" , & signer_test. running_nodes. conf. node. rpc_bind) ;
2668
+
2669
+ signer_test. boot_to_epoch_3 ( ) ;
2670
+
2671
+ info ! ( "---- Nakamoto booted, starting test ----" ) ;
2672
+ signer_test. mine_nakamoto_block ( Duration :: from_secs ( 30 ) , true ) ;
2673
+
2674
+ info ! ( "---- Start a new tenure but ignore block signatures so no timestamps are recorded ----" ) ;
2675
+ let tip_height_before = get_chain_info ( & signer_test. running_nodes . conf ) . stacks_tip_height ;
2676
+ TEST_IGNORE_SIGNERS . set ( true ) ;
2677
+ next_block_and (
2678
+ & mut signer_test. running_nodes . btc_regtest_controller ,
2679
+ 30 ,
2680
+ || {
2681
+ let tip_height = get_chain_info ( & signer_test. running_nodes . conf ) . stacks_tip_height ;
2682
+ Ok ( tip_height > tip_height_before)
2683
+ } ,
2684
+ )
2685
+ . expect ( "Failed to mine the tenure change block" ) ;
2686
+
2687
+ // Now, wait for a block with a tenure change due to the new block
2688
+ wait_for ( 30 , || {
2689
+ Ok ( last_block_contains_tenure_change_tx (
2690
+ TenureChangeCause :: BlockFound ,
2691
+ ) )
2692
+ } )
2693
+ . expect ( "Timed out waiting for a block with a tenure change" ) ;
2694
+
2695
+ info ! ( "---- Waiting for a tenure extend ----" ) ;
2696
+
2697
+ TEST_IGNORE_SIGNERS . set ( false ) ;
2698
+ // Now, wait for a block with a tenure extend
2699
+ wait_for ( miner_idle_timeout. as_secs ( ) + 20 , || {
2700
+ Ok ( last_block_contains_tenure_change_tx (
2701
+ TenureChangeCause :: Extended ,
2702
+ ) )
2703
+ } )
2704
+ . expect ( "Timed out waiting for a block with a tenure extend" ) ;
2705
+ signer_test. shutdown ( ) ;
2706
+ }
2707
+
2708
+ #[ test]
2709
+ #[ ignore]
2710
+ /// This test verifies that a miner that attempts to produce a tenure extend too early will be rejected by the signers,
2711
+ /// but will eventually succeed after the signers' idle timeout has passed.
2712
+ fn tenure_extend_succeeds_after_rejected_attempt ( ) {
2713
+ if env:: var ( "BITCOIND_TEST" ) != Ok ( "1" . into ( ) ) {
2714
+ return ;
2715
+ }
2716
+
2717
+ tracing_subscriber:: registry ( )
2718
+ . with ( fmt:: layer ( ) )
2719
+ . with ( EnvFilter :: from_default_env ( ) )
2720
+ . init ( ) ;
2721
+
2722
+ info ! ( "------------------------- Test Setup -------------------------" ) ;
2723
+ let num_signers = 5 ;
2724
+ let sender_sk = Secp256k1PrivateKey :: new ( ) ;
2725
+ let sender_addr = tests:: to_addr ( & sender_sk) ;
2726
+ let send_amt = 100 ;
2727
+ let send_fee = 180 ;
2728
+ let _recipient = PrincipalData :: from ( StacksAddress :: burn_address ( false ) ) ;
2729
+ let idle_timeout = Duration :: from_secs ( 30 ) ;
2730
+ let miner_idle_timeout = Duration :: from_secs ( 20 ) ;
2731
+ let mut signer_test: SignerTest < SpawnedSigner > = SignerTest :: new_with_config_modifications (
2732
+ num_signers,
2733
+ vec ! [ ( sender_addr, send_amt + send_fee) ] ,
2734
+ |config| {
2735
+ config. tenure_idle_timeout = idle_timeout;
2736
+ } ,
2737
+ |config| {
2738
+ config. miner . tenure_timeout = miner_idle_timeout;
2739
+ } ,
2740
+ None ,
2741
+ None ,
2742
+ ) ;
2743
+ let _http_origin = format ! ( "http://{}" , & signer_test. running_nodes. conf. node. rpc_bind) ;
2744
+
2745
+ signer_test. boot_to_epoch_3 ( ) ;
2746
+
2747
+ info ! ( "---- Nakamoto booted, starting test ----" ) ;
2748
+ signer_test. mine_nakamoto_block ( Duration :: from_secs ( 30 ) , true ) ;
2749
+
2750
+ info ! ( "---- Waiting for a rejected tenure extend ----" ) ;
2751
+ // Now, wait for a block with a tenure extend proposal from the miner, but ensure it is rejected.
2752
+ wait_for ( 30 , || {
2753
+ let block = test_observer:: get_stackerdb_chunks ( )
2754
+ . into_iter ( )
2755
+ . flat_map ( |chunk| chunk. modified_slots )
2756
+ . find_map ( |chunk| {
2757
+ let message = SignerMessage :: consensus_deserialize ( & mut chunk. data . as_slice ( ) )
2758
+ . expect ( "Failed to deserialize SignerMessage" ) ;
2759
+ if let SignerMessage :: BlockProposal ( proposal) = message {
2760
+ if proposal. block . get_tenure_tx_payload ( ) . unwrap ( ) . cause
2761
+ == TenureChangeCause :: Extended
2762
+ {
2763
+ return Some ( proposal. block ) ;
2764
+ }
2765
+ }
2766
+ None
2767
+ } ) ;
2768
+ let Some ( block) = & block else {
2769
+ return Ok ( false ) ;
2770
+ } ;
2771
+ let signatures = test_observer:: get_stackerdb_chunks ( )
2772
+ . into_iter ( )
2773
+ . flat_map ( |chunk| chunk. modified_slots )
2774
+ . filter_map ( |chunk| {
2775
+ let message = SignerMessage :: consensus_deserialize ( & mut chunk. data . as_slice ( ) )
2776
+ . expect ( "Failed to deserialize SignerMessage" ) ;
2777
+ if let SignerMessage :: BlockResponse ( BlockResponse :: Rejected ( rejected) ) = message {
2778
+ if block. header . signer_signature_hash ( ) == rejected. signer_signature_hash {
2779
+ return Some ( rejected. signature ) ;
2780
+ }
2781
+ }
2782
+ None
2783
+ } )
2784
+ . collect :: < Vec < _ > > ( ) ;
2785
+ Ok ( signatures. len ( ) >= num_signers * 7 / 10 )
2786
+ } )
2787
+ . expect ( "Test timed out while waiting for a rejected tenure extend" ) ;
2788
+
2789
+ info ! ( "---- Waiting for an accepted tenure extend ----" ) ;
2790
+ wait_for ( idle_timeout. as_secs ( ) + 10 , || {
2791
+ Ok ( last_block_contains_tenure_change_tx (
2792
+ TenureChangeCause :: Extended ,
2793
+ ) )
2794
+ } )
2795
+ . expect ( "Test timed out while waiting for an accepted tenure extend" ) ;
2796
+ signer_test. shutdown ( ) ;
2797
+ }
2798
+
2632
2799
#[ test]
2633
2800
#[ ignore]
2634
2801
/// Verify that Nakamoto blocks that don't modify the tenure's execution cost
0 commit comments