@@ -18195,3 +18195,160 @@ fn multiversioned_signer_protocol_version_calculation() {
18195
18195
.unwrap();
18196
18196
signer_test.shutdown();
18197
18197
}
18198
+
18199
+ /// Ensure that signers can immediately start participating in signing when starting up
18200
+ /// after crashing mid reward cycle.
18201
+ ///
18202
+ /// Test scenario:
18203
+ /// - Miner A wins Tenure A
18204
+ /// - Miner A proposes block N (Tenure Change)
18205
+ /// - All signers sign block N.
18206
+ /// - Miner B wins Tenure B.
18207
+ /// - Shutdown one signer.
18208
+ /// - Shutdown signer is restarted.
18209
+ /// - Miner B proposes block N+1 (TenureChange).
18210
+ /// - All signers sign the block without issue
18211
+ /// -> Verifies that updates are loaded from signerdb on init
18212
+ /// - Same signer is shutdown.
18213
+ /// - Shutdown signers db is cleared.
18214
+ /// - Signer is restarted.
18215
+ /// - Miner B proposes block N+2 (Transfer).
18216
+ /// - All signers including the restarted signer sign block N+2
18217
+ /// -> Verifies that updates are loaded from stackerdb on init
18218
+ #[test]
18219
+ #[ignore]
18220
+ fn signer_loads_stackerdb_updates_on_startup() {
18221
+ if env::var("BITCOIND_TEST") != Ok("1".into()) {
18222
+ return;
18223
+ }
18224
+
18225
+ let num_signers = 5;
18226
+ let mut miners = MultipleMinerTest::new(num_signers, 1);
18227
+
18228
+ let skip_commit_op_rl1 = miners
18229
+ .signer_test
18230
+ .running_nodes
18231
+ .counters
18232
+ .naka_skip_commit_op
18233
+ .clone();
18234
+ let skip_commit_op_rl2 = miners.rl2_counters.naka_skip_commit_op.clone();
18235
+
18236
+ let (conf_1, _conf_2) = miners.get_node_configs();
18237
+ let (miner_pk_1, miner_pk_2) = miners.get_miner_public_keys();
18238
+ let (miner_pkh_1, miner_pkh_2) = miners.get_miner_public_key_hashes();
18239
+
18240
+ let all_signers = miners.signer_test.signer_test_pks();
18241
+
18242
+ // Pause Miner 2's commits to ensure Miner 1 wins the first sortition.
18243
+ skip_commit_op_rl2.set(true);
18244
+ miners.boot_to_epoch_3();
18245
+
18246
+ let sortdb = conf_1.get_burnchain().open_sortition_db(true).unwrap();
18247
+
18248
+ info!("Pausing miner 1's block commit submissions");
18249
+ skip_commit_op_rl1.set(true);
18250
+
18251
+ info!("------------------------- Miner A Wins Tenure A -------------------------");
18252
+ let info_before = get_chain_info(&conf_1);
18253
+ // Let's not mine anything until we see consensus on new tenure start.
18254
+ TEST_MINE_SKIP.set(true);
18255
+ next_block_and(&miners.btc_regtest_controller_mut(), 60, || {
18256
+ let info = get_chain_info(&conf_1);
18257
+ Ok(info.burn_block_height > info_before.burn_block_height)
18258
+ })
18259
+ .unwrap();
18260
+ let chain_after = get_chain_info(&conf_1);
18261
+ wait_for_state_machine_update_by_miner_tenure_id(
18262
+ 30,
18263
+ &chain_after.pox_consensus,
18264
+ &miners.signer_test.signer_addresses_versions(),
18265
+ )
18266
+ .expect("Timed out waiting for the signers to update their state");
18267
+ verify_sortition_winner(&sortdb, &miner_pkh_1);
18268
+
18269
+ info!(
18270
+ "------------------------- Miner A Mines Block N (Tenure Change) -------------------------"
18271
+ );
18272
+ TEST_MINE_SKIP.set(false);
18273
+ let block_n =
18274
+ wait_for_block_pushed_by_miner_key(30, chain_after.stacks_tip_height + 1, &miner_pk_1)
18275
+ .expect("Failed to mine block N");
18276
+ wait_for_block_acceptance_from_signers(
18277
+ 30,
18278
+ &block_n.header.signer_signature_hash(),
18279
+ &all_signers,
18280
+ )
18281
+ .expect("Not all signers accepted the block");
18282
+
18283
+ info!("------------------------- Miner B Wins Tenure B -------------------------");
18284
+ miners.submit_commit_miner_2(&sortdb);
18285
+ let chain_before = get_chain_info(&conf_1);
18286
+ // Let's not mine anything until we see consensus on new tenure start.
18287
+ TEST_MINE_SKIP.set(true);
18288
+ next_block_and(&miners.btc_regtest_controller_mut(), 60, || {
18289
+ let info = get_chain_info(&conf_1);
18290
+ Ok(info.burn_block_height > chain_before.burn_block_height)
18291
+ })
18292
+ .unwrap();
18293
+ let chain_after = get_chain_info(&conf_1);
18294
+ wait_for_state_machine_update_by_miner_tenure_id(
18295
+ 30,
18296
+ &chain_after.pox_consensus,
18297
+ &miners.signer_test.signer_addresses_versions(),
18298
+ )
18299
+ .expect("Signers failed to update their state");
18300
+ verify_sortition_winner(&sortdb, &miner_pkh_2);
18301
+
18302
+ let stop_idx = 0;
18303
+ info!("------------------------- Shutdown Signer at idx {stop_idx} -------------------------");
18304
+ let stopped_signer_config = miners.signer_test.stop_signer(stop_idx);
18305
+ info!("------------------------- Restart Signer at idx {stop_idx} -------------------------");
18306
+ miners
18307
+ .signer_test
18308
+ .restart_signer(stop_idx, stopped_signer_config);
18309
+
18310
+ info!("------------------------- Miner B Mines Block N+1 (Tenure Change) -------------------------");
18311
+ TEST_MINE_SKIP.set(false);
18312
+ let block_n_1 =
18313
+ wait_for_block_pushed_by_miner_key(30, chain_after.stacks_tip_height + 1, &miner_pk_2)
18314
+ .expect("Failed to mine block N+1");
18315
+ wait_for_block_acceptance_from_signers(
18316
+ 30,
18317
+ &block_n_1.header.signer_signature_hash(),
18318
+ &all_signers,
18319
+ )
18320
+ .expect("Not all signers accepted the block");
18321
+
18322
+ info!("------------------------- Shutdown Signer at idx {stop_idx} -------------------------");
18323
+ let stopped_signer_config = miners.signer_test.stop_signer(stop_idx);
18324
+ {
18325
+ let mut signer_db = SignerDb::new(stopped_signer_config.db_path.clone()).unwrap();
18326
+ signer_db
18327
+ .clear_state_machine_updates()
18328
+ .expect("Failed to clear state machine updates");
18329
+ }
18330
+ info!("------------------------- Restart Signer at idx {stop_idx} -------------------------");
18331
+ miners
18332
+ .signer_test
18333
+ .restart_signer(stop_idx, stopped_signer_config);
18334
+
18335
+ // Wait until signer boots up BEFORE proposing the next block
18336
+ miners.signer_test.wait_for_registered();
18337
+ info!("------------------------- Miner B Mines Block N+2 (Transfer) -------------------------");
18338
+ let (accepting, ignoring) = all_signers.split_at(4);
18339
+ // Make some of the signers ignore so that we CANNOT advance without approval from the restarted signer (its at index 0)
18340
+ TEST_IGNORE_ALL_BLOCK_PROPOSALS.set(ignoring.into());
18341
+ miners.send_transfer_tx();
18342
+ let block_n_2 =
18343
+ wait_for_block_pushed_by_miner_key(30, chain_after.stacks_tip_height + 2, &miner_pk_2)
18344
+ .expect("Failed to mine block N+2");
18345
+ wait_for_block_acceptance_from_signers(
18346
+ 30,
18347
+ &block_n_2.header.signer_signature_hash(),
18348
+ &accepting,
18349
+ )
18350
+ .expect("Not all signers accepted the block");
18351
+
18352
+ info!("------------------------- Shutdown -------------------------");
18353
+ miners.shutdown();
18354
+ }
0 commit comments