@@ -35,6 +35,7 @@ use stacks::chainstate::stacks::db::{StacksBlockHeaderTypes, StacksChainState, S
35
35
use stacks:: codec:: StacksMessageCodec ;
36
36
use stacks:: core:: { StacksEpochId , CHAIN_ID_TESTNET } ;
37
37
use stacks:: libstackerdb:: StackerDBChunkData ;
38
+ use stacks:: net:: api:: getsigner:: GetSignerResponse ;
38
39
use stacks:: net:: api:: postblock_proposal:: { ValidateRejectCode , TEST_VALIDATE_STALL } ;
39
40
use stacks:: net:: relay:: fault_injection:: set_ignore_block;
40
41
use stacks:: types:: chainstate:: { StacksAddress , StacksBlockId , StacksPrivateKey , StacksPublicKey } ;
@@ -2023,35 +2024,29 @@ fn end_of_tenure() {
2023
2024
std:: thread:: sleep ( Duration :: from_millis ( 100 ) ) ;
2024
2025
}
2025
2026
2026
- while signer_test. get_current_reward_cycle ( ) != final_reward_cycle {
2027
- next_block_and (
2028
- & mut signer_test. running_nodes . btc_regtest_controller ,
2029
- 10 ,
2030
- || Ok ( true ) ,
2031
- )
2032
- . unwrap ( ) ;
2033
- assert ! (
2034
- start_time. elapsed( ) <= short_timeout,
2035
- "Timed out waiting to enter the next reward cycle"
2036
- ) ;
2037
- std:: thread:: sleep ( Duration :: from_millis ( 100 ) ) ;
2038
- }
2027
+ wait_for ( short_timeout. as_secs ( ) , || {
2028
+ let result = signer_test. get_current_reward_cycle ( ) == final_reward_cycle;
2029
+ if !result {
2030
+ signer_test
2031
+ . running_nodes
2032
+ . btc_regtest_controller
2033
+ . build_next_block ( 1 ) ;
2034
+ }
2035
+ Ok ( result)
2036
+ } )
2037
+ . expect ( "Timed out waiting to enter the next reward cycle" ) ;
2039
2038
2040
- while test_observer:: get_burn_blocks ( )
2041
- . last ( )
2042
- . unwrap ( )
2043
- . get ( "burn_block_height" )
2044
- . unwrap ( )
2045
- . as_u64 ( )
2046
- . unwrap ( )
2047
- < final_reward_cycle_height_boundary + 1
2048
- {
2049
- assert ! (
2050
- start_time. elapsed( ) <= short_timeout,
2051
- "Timed out waiting for burn block events"
2052
- ) ;
2053
- std:: thread:: sleep ( Duration :: from_millis ( 100 ) ) ;
2054
- }
2039
+ wait_for ( short_timeout. as_secs ( ) , || {
2040
+ let blocks = test_observer:: get_burn_blocks ( )
2041
+ . last ( )
2042
+ . unwrap ( )
2043
+ . get ( "burn_block_height" )
2044
+ . unwrap ( )
2045
+ . as_u64 ( )
2046
+ . unwrap ( ) ;
2047
+ Ok ( blocks > final_reward_cycle_height_boundary)
2048
+ } )
2049
+ . expect ( "Timed out waiting for burn block events" ) ;
2055
2050
2056
2051
signer_test. wait_for_cycle ( 30 , final_reward_cycle) ;
2057
2052
@@ -2109,21 +2104,11 @@ fn retry_on_rejection() {
2109
2104
let burnchain = signer_test. running_nodes . conf . get_burnchain ( ) ;
2110
2105
let sortdb = burnchain. open_sortition_db ( true ) . unwrap ( ) ;
2111
2106
2112
- loop {
2113
- next_block_and (
2114
- & mut signer_test. running_nodes . btc_regtest_controller ,
2115
- 60 ,
2116
- || Ok ( true ) ,
2117
- )
2118
- . unwrap ( ) ;
2119
-
2120
- sleep_ms ( 10_000 ) ;
2121
-
2107
+ wait_for ( 30 , || {
2122
2108
let tip = SortitionDB :: get_canonical_burn_chain_tip ( & sortdb. conn ( ) ) . unwrap ( ) ;
2123
- if tip. sortition {
2124
- break ;
2125
- }
2126
- }
2109
+ Ok ( tip. sortition )
2110
+ } )
2111
+ . expect ( "Timed out waiting for sortition" ) ;
2127
2112
2128
2113
// mine a nakamoto block
2129
2114
let mined_blocks = signer_test. running_nodes . nakamoto_blocks_mined . clone ( ) ;
@@ -2565,12 +2550,10 @@ fn mock_sign_epoch_25() {
2565
2550
{
2566
2551
let mut mock_block_mesage = None ;
2567
2552
let mock_poll_time = Instant :: now ( ) ;
2568
- next_block_and (
2569
- & mut signer_test. running_nodes . btc_regtest_controller ,
2570
- 60 ,
2571
- || Ok ( true ) ,
2572
- )
2573
- . unwrap ( ) ;
2553
+ signer_test
2554
+ . running_nodes
2555
+ . btc_regtest_controller
2556
+ . build_next_block ( 1 ) ;
2574
2557
let current_burn_block_height = signer_test
2575
2558
. running_nodes
2576
2559
. btc_regtest_controller
@@ -2778,12 +2761,10 @@ fn multiple_miners_mock_sign_epoch_25() {
2778
2761
{
2779
2762
let mut mock_block_mesage = None ;
2780
2763
let mock_poll_time = Instant :: now ( ) ;
2781
- next_block_and (
2782
- & mut signer_test. running_nodes . btc_regtest_controller ,
2783
- 60 ,
2784
- || Ok ( true ) ,
2785
- )
2786
- . unwrap ( ) ;
2764
+ signer_test
2765
+ . running_nodes
2766
+ . btc_regtest_controller
2767
+ . build_next_block ( 1 ) ;
2787
2768
let current_burn_block_height = signer_test
2788
2769
. running_nodes
2789
2770
. btc_regtest_controller
@@ -4599,21 +4580,11 @@ fn miner_recovers_when_broadcast_block_delay_across_tenures_occurs() {
4599
4580
let burnchain = signer_test. running_nodes . conf . get_burnchain ( ) ;
4600
4581
let sortdb = burnchain. open_sortition_db ( true ) . unwrap ( ) ;
4601
4582
4602
- loop {
4603
- next_block_and (
4604
- & mut signer_test. running_nodes . btc_regtest_controller ,
4605
- 60 ,
4606
- || Ok ( true ) ,
4607
- )
4608
- . unwrap ( ) ;
4609
-
4610
- sleep_ms ( 10_000 ) ;
4611
-
4583
+ wait_for ( 30 , || {
4612
4584
let tip = SortitionDB :: get_canonical_burn_chain_tip ( & sortdb. conn ( ) ) . unwrap ( ) ;
4613
- if tip. sortition {
4614
- break ;
4615
- }
4616
- }
4585
+ Ok ( tip. sortition )
4586
+ } )
4587
+ . expect ( "Timed out waiting for sortition" ) ;
4617
4588
4618
4589
// submit a tx so that the miner will mine a stacks block
4619
4590
let mut sender_nonce = 0 ;
@@ -4874,3 +4845,97 @@ fn miner_recovers_when_broadcast_block_delay_across_tenures_occurs() {
4874
4845
assert_eq ! ( info_after. stacks_tip. to_string( ) , block_n_2. block_hash) ;
4875
4846
assert_ne ! ( block_n_2, block_n) ;
4876
4847
}
4848
+
4849
+ #[ test]
4850
+ #[ ignore]
4851
+ /// Test that signers can successfully sign a block proposal in the 0th tenure of a reward cycle
4852
+ /// This ensures there is no race condition in the /v2/pox endpoint which could prevent it from updating
4853
+ /// on time, possibly triggering an "off by one" like behaviour in the 0th tenure.
4854
+ ///
4855
+ fn signing_in_0th_tenure_of_reward_cycle ( ) {
4856
+ if env:: var ( "BITCOIND_TEST" ) != Ok ( "1" . into ( ) ) {
4857
+ return ;
4858
+ }
4859
+
4860
+ tracing_subscriber:: registry ( )
4861
+ . with ( fmt:: layer ( ) )
4862
+ . with ( EnvFilter :: from_default_env ( ) )
4863
+ . init ( ) ;
4864
+
4865
+ info ! ( "------------------------- Test Setup -------------------------" ) ;
4866
+ let num_signers = 5 ;
4867
+ let mut signer_test: SignerTest < SpawnedSigner > = SignerTest :: new ( num_signers, vec ! [ ] ) ;
4868
+ let signer_public_keys = signer_test
4869
+ . signer_stacks_private_keys
4870
+ . iter ( )
4871
+ . map ( StacksPublicKey :: from_private)
4872
+ . collect :: < Vec < _ > > ( ) ;
4873
+ let long_timeout = Duration :: from_secs ( 200 ) ;
4874
+ signer_test. boot_to_epoch_3 ( ) ;
4875
+ let curr_reward_cycle = signer_test. get_current_reward_cycle ( ) ;
4876
+ let next_reward_cycle = curr_reward_cycle + 1 ;
4877
+ // Mine until the boundary of the first full Nakamoto reward cycles (epoch 3 starts in the middle of one)
4878
+ let next_reward_cycle_height_boundary = signer_test
4879
+ . running_nodes
4880
+ . btc_regtest_controller
4881
+ . get_burnchain ( )
4882
+ . reward_cycle_to_block_height ( next_reward_cycle)
4883
+ . saturating_sub ( 1 ) ;
4884
+
4885
+ info ! ( "------------------------- Advancing to {next_reward_cycle} Boundary at Block {next_reward_cycle_height_boundary} -------------------------" ) ;
4886
+ signer_test. run_until_burnchain_height_nakamoto (
4887
+ long_timeout,
4888
+ next_reward_cycle_height_boundary,
4889
+ num_signers,
4890
+ ) ;
4891
+
4892
+ let http_origin = format ! ( "http://{}" , & signer_test. running_nodes. conf. node. rpc_bind) ;
4893
+ let get_v3_signer = |pubkey : & Secp256k1PublicKey , reward_cycle : u64 | {
4894
+ let url = & format ! (
4895
+ "{http_origin}/v3/signer/{pk}/{reward_cycle}" ,
4896
+ pk = pubkey. to_hex( )
4897
+ ) ;
4898
+ info ! ( "Send request: GET {url}" ) ;
4899
+ reqwest:: blocking:: get ( url)
4900
+ . unwrap_or_else ( |e| panic ! ( "GET request failed: {e}" ) )
4901
+ . json :: < GetSignerResponse > ( )
4902
+ . unwrap ( )
4903
+ . blocks_signed
4904
+ } ;
4905
+
4906
+ assert_eq ! ( signer_test. get_current_reward_cycle( ) , curr_reward_cycle) ;
4907
+
4908
+ for signer in & signer_public_keys {
4909
+ let blocks_signed = get_v3_signer ( & signer, next_reward_cycle) ;
4910
+ assert_eq ! ( blocks_signed, 0 ) ;
4911
+ }
4912
+
4913
+ info ! ( "------------------------- Enter Reward Cycle {next_reward_cycle} -------------------------" ) ;
4914
+ for signer in & signer_public_keys {
4915
+ let blocks_signed = get_v3_signer ( & signer, next_reward_cycle) ;
4916
+ assert_eq ! ( blocks_signed, 0 ) ;
4917
+ }
4918
+ let blocks_before = signer_test
4919
+ . running_nodes
4920
+ . nakamoto_blocks_mined
4921
+ . load ( Ordering :: SeqCst ) ;
4922
+ signer_test
4923
+ . running_nodes
4924
+ . btc_regtest_controller
4925
+ . build_next_block ( 1 ) ;
4926
+
4927
+ wait_for ( 30 , || {
4928
+ Ok ( signer_test
4929
+ . running_nodes
4930
+ . nakamoto_blocks_mined
4931
+ . load ( Ordering :: SeqCst )
4932
+ > blocks_before)
4933
+ } )
4934
+ . unwrap ( ) ;
4935
+
4936
+ for signer in & signer_public_keys {
4937
+ let blocks_signed = get_v3_signer ( & signer, next_reward_cycle) ;
4938
+ assert_eq ! ( blocks_signed, 1 ) ;
4939
+ }
4940
+ assert_eq ! ( signer_test. get_current_reward_cycle( ) , next_reward_cycle) ;
4941
+ }
0 commit comments