@@ -34,6 +34,7 @@ use stacks::chainstate::nakamoto::{NakamotoBlock, NakamotoBlockHeader, NakamotoC
34
34
use stacks:: chainstate:: stacks:: address:: PoxAddress ;
35
35
use stacks:: chainstate:: stacks:: boot:: MINERS_NAME ;
36
36
use stacks:: chainstate:: stacks:: db:: { StacksBlockHeaderTypes , StacksChainState , StacksHeaderInfo } ;
37
+ use stacks:: chainstate:: stacks:: { StacksTransaction , TenureChangeCause , TransactionPayload } ;
37
38
use stacks:: codec:: StacksMessageCodec ;
38
39
use stacks:: core:: { StacksEpochId , CHAIN_ID_TESTNET } ;
39
40
use stacks:: libstackerdb:: StackerDBChunkData ;
@@ -42,7 +43,7 @@ use stacks::net::api::postblock_proposal::{ValidateRejectCode, TEST_VALIDATE_STA
42
43
use stacks:: net:: relay:: fault_injection:: set_ignore_block;
43
44
use stacks:: types:: chainstate:: { StacksAddress , StacksBlockId , StacksPrivateKey , StacksPublicKey } ;
44
45
use stacks:: types:: PublicKey ;
45
- use stacks:: util:: hash:: MerkleHashFunc ;
46
+ use stacks:: util:: hash:: { hex_bytes , MerkleHashFunc } ;
46
47
use stacks:: util:: secp256k1:: { Secp256k1PrivateKey , Secp256k1PublicKey } ;
47
48
use stacks:: util_lib:: boot:: boot_code_id;
48
49
use stacks:: util_lib:: signed_structured_data:: pox4:: {
@@ -5076,6 +5077,129 @@ fn miner_recovers_when_broadcast_block_delay_across_tenures_occurs() {
5076
5077
assert_ne ! ( block_n_2, block_n) ;
5077
5078
}
5078
5079
5080
+ #[ test]
5081
+ #[ ignore]
5082
+ /// Test that we can mine a tenure extend and then continue mining afterwards.
5083
+ fn continue_after_tenure_extend ( ) {
5084
+ if env:: var ( "BITCOIND_TEST" ) != Ok ( "1" . into ( ) ) {
5085
+ return ;
5086
+ }
5087
+
5088
+ tracing_subscriber:: registry ( )
5089
+ . with ( fmt:: layer ( ) )
5090
+ . with ( EnvFilter :: from_default_env ( ) )
5091
+ . init ( ) ;
5092
+
5093
+ info ! ( "------------------------- Test Setup -------------------------" ) ;
5094
+ let num_signers = 5 ;
5095
+ let sender_sk = Secp256k1PrivateKey :: new ( ) ;
5096
+ let sender_addr = tests:: to_addr ( & sender_sk) ;
5097
+ let recipient = PrincipalData :: from ( StacksAddress :: burn_address ( false ) ) ;
5098
+ let send_amt = 100 ;
5099
+ let send_fee = 180 ;
5100
+ let mut signer_test: SignerTest < SpawnedSigner > = SignerTest :: new (
5101
+ num_signers,
5102
+ vec ! [ ( sender_addr. clone( ) , ( send_amt + send_fee) * 5 ) ] ,
5103
+ ) ;
5104
+ let timeout = Duration :: from_secs ( 200 ) ;
5105
+ let coord_channel = signer_test. running_nodes . coord_channel . clone ( ) ;
5106
+ let http_origin = format ! ( "http://{}" , & signer_test. running_nodes. conf. node. rpc_bind) ;
5107
+
5108
+ signer_test. boot_to_epoch_3 ( ) ;
5109
+
5110
+ info ! ( "------------------------- Mine Normal Tenure -------------------------" ) ;
5111
+ signer_test. mine_and_verify_confirmed_naka_block ( timeout, num_signers) ;
5112
+
5113
+ info ! ( "------------------------- Extend Tenure -------------------------" ) ;
5114
+ signer_test
5115
+ . running_nodes
5116
+ . nakamoto_test_skip_commit_op
5117
+ . 0
5118
+ . lock ( )
5119
+ . unwrap ( )
5120
+ . replace ( true ) ;
5121
+
5122
+ // It's possible that we have a pending block commit already.
5123
+ // Mine two BTC blocks to "flush" this commit.
5124
+
5125
+ for i in 0 ..2 {
5126
+ info ! (
5127
+ "------------- After pausing commits, triggering 2 BTC blocks: ({} of 2) -----------" ,
5128
+ i + 1
5129
+ ) ;
5130
+
5131
+ let blocks_processed_before = coord_channel
5132
+ . lock ( )
5133
+ . expect ( "Mutex poisoned" )
5134
+ . get_stacks_blocks_processed ( ) ;
5135
+ signer_test
5136
+ . running_nodes
5137
+ . btc_regtest_controller
5138
+ . build_next_block ( 1 ) ;
5139
+
5140
+ wait_for ( 60 , || {
5141
+ let blocks_processed_after = coord_channel
5142
+ . lock ( )
5143
+ . expect ( "Mutex poisoned" )
5144
+ . get_stacks_blocks_processed ( ) ;
5145
+ Ok ( blocks_processed_after > blocks_processed_before)
5146
+ } )
5147
+ . expect ( "Timed out waiting for tenure extend block" ) ;
5148
+ }
5149
+
5150
+ // The last block should have a single instruction in it, the tenure extend
5151
+ let blocks = test_observer:: get_blocks ( ) ;
5152
+ let last_block = blocks. last ( ) . unwrap ( ) ;
5153
+ let transactions = last_block[ "transactions" ] . as_array ( ) . unwrap ( ) ;
5154
+ let tx = transactions. first ( ) . expect ( "No transactions in block" ) ;
5155
+ let raw_tx = tx[ "raw_tx" ] . as_str ( ) . unwrap ( ) ;
5156
+ let tx_bytes = hex_bytes ( & raw_tx[ 2 ..] ) . unwrap ( ) ;
5157
+ let parsed = StacksTransaction :: consensus_deserialize ( & mut & tx_bytes[ ..] ) . unwrap ( ) ;
5158
+ match & parsed. payload {
5159
+ TransactionPayload :: TenureChange ( payload)
5160
+ if payload. cause == TenureChangeCause :: Extended => { }
5161
+ _ => panic ! ( "Expected tenure extend transaction, got {:?}" , parsed) ,
5162
+ } ;
5163
+
5164
+ // Verify that the miner can continue mining in the tenure with the tenure extend
5165
+ info ! ( "------------------------- Mine After Tenure Extend -------------------------" ) ;
5166
+ let mut sender_nonce = 0 ;
5167
+ let mut blocks_processed_before = coord_channel
5168
+ . lock ( )
5169
+ . expect ( "Mutex poisoned" )
5170
+ . get_stacks_blocks_processed ( ) ;
5171
+ for _ in 0 ..5 {
5172
+ // submit a tx so that the miner will mine an extra block
5173
+ let transfer_tx = make_stacks_transfer (
5174
+ & sender_sk,
5175
+ sender_nonce,
5176
+ send_fee,
5177
+ signer_test. running_nodes . conf . burnchain . chain_id ,
5178
+ & recipient,
5179
+ send_amt,
5180
+ ) ;
5181
+ sender_nonce += 1 ;
5182
+ submit_tx ( & http_origin, & transfer_tx) ;
5183
+
5184
+ info ! ( "Submitted transfer tx and waiting for block proposal" ) ;
5185
+ wait_for ( 30 , || {
5186
+ let blocks_processed_after = coord_channel
5187
+ . lock ( )
5188
+ . expect ( "Mutex poisoned" )
5189
+ . get_stacks_blocks_processed ( ) ;
5190
+ Ok ( blocks_processed_after > blocks_processed_before)
5191
+ } )
5192
+ . expect ( "Timed out waiting for block proposal" ) ;
5193
+ blocks_processed_before = coord_channel
5194
+ . lock ( )
5195
+ . expect ( "Mutex poisoned" )
5196
+ . get_stacks_blocks_processed ( ) ;
5197
+ info ! ( "Block {blocks_processed_before} processed, continuing" ) ;
5198
+ }
5199
+
5200
+ signer_test. shutdown ( ) ;
5201
+ }
5202
+
5079
5203
#[ test]
5080
5204
#[ ignore]
5081
5205
/// Test that signers can successfully sign a block proposal in the 0th tenure of a reward cycle
0 commit comments