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