@@ -18077,3 +18077,114 @@ fn bitcoin_reorg_extended_tenure() {
18077
18077
18078
18078
miners.shutdown();
18079
18079
}
18080
+
18081
+ /// Tests that the active signer protocol version is set to the lowest common denominator
18082
+ #[test]
18083
+ #[ignore]
18084
+ fn multiversioned_signer_protocol_version_calculation() {
18085
+ if env::var("BITCOIND_TEST") != Ok("1".into()) {
18086
+ return;
18087
+ }
18088
+ let num_signers = 5;
18089
+ let sender_sk = Secp256k1PrivateKey::random();
18090
+ let sender_addr = tests::to_addr(&sender_sk);
18091
+ let send_amt = 1000;
18092
+ let send_fee = 180;
18093
+
18094
+ let btc_miner_1_seed = vec![1, 1, 1, 1];
18095
+ let btc_miner_2_seed = vec![2, 2, 2, 2];
18096
+ let btc_miner_1_pk = Keychain::default(btc_miner_1_seed.clone()).get_pub_key();
18097
+ let btc_miner_2_pk = Keychain::default(btc_miner_2_seed.clone()).get_pub_key();
18098
+ let signer_test: SignerTest<SpawnedSigner> = SignerTest::new_with_config_modifications(
18099
+ num_signers,
18100
+ vec![(sender_addr, send_amt + send_fee)],
18101
+ |signer_config| {
18102
+ // We don't want the miner of the "inactive" sortition before the flash block
18103
+ // to get timed out.
18104
+ signer_config.block_proposal_timeout = Duration::from_secs(600);
18105
+
18106
+ let signer_version = match signer_config.endpoint.port() % num_signers as u16 {
18107
+ 0 | 1 => 0, // first two -> version 0
18108
+ 2 | 3 => 1, // next two -> version 1
18109
+ _ => 2, // last ones -> version 2
18110
+ };
18111
+ signer_config.supported_signer_protocol_version = signer_version;
18112
+ },
18113
+ |_| {},
18114
+ Some(vec![btc_miner_1_pk, btc_miner_2_pk]),
18115
+ None,
18116
+ );
18117
+
18118
+ signer_test.boot_to_epoch_3();
18119
+ // Pause the miner to enforce exactly one proposal and to ensure it isn't just rejected with no consensus
18120
+ info!("------------------------- Pausing Mining -------------------------");
18121
+ TEST_MINE_SKIP.set(true);
18122
+ test_observer::clear();
18123
+ info!("------------------------- Reached Epoch 3.0 -------------------------");
18124
+
18125
+ // In the next block, the miner should win the tenure and mine a stacks block
18126
+ let peer_info_before = signer_test.get_peer_info();
18127
+
18128
+ info!("------------------------- Mining Burn Block for Tenure A -------------------------");
18129
+ next_block_and(
18130
+ &signer_test.running_nodes.btc_regtest_controller,
18131
+ 60,
18132
+ || {
18133
+ let peer_info = signer_test.get_peer_info();
18134
+ Ok(peer_info.burn_block_height > peer_info_before.burn_block_height)
18135
+ },
18136
+ )
18137
+ .unwrap();
18138
+ let peer_info_after = signer_test.get_peer_info();
18139
+ let signer_addresses = signer_test.signer_addresses_versions();
18140
+
18141
+ info!("------------------------- Waiting for Signer Updates -------------------------");
18142
+ // Make sure all signers are on the same page before proposing a block so its accepted
18143
+ wait_for_state_machine_update(
18144
+ 30,
18145
+ &peer_info_after.pox_consensus,
18146
+ peer_info_after.burn_block_height,
18147
+ None,
18148
+ &signer_addresses,
18149
+ )
18150
+ .unwrap();
18151
+
18152
+ info!("------------------------- Resuming Mining of Tenure Start Block for Tenure A -------------------------");
18153
+ TEST_MINE_SKIP.set(false);
18154
+ wait_for(30, || {
18155
+ Ok(signer_test.get_peer_info().stacks_tip_height > peer_info_before.stacks_tip_height)
18156
+ })
18157
+ .unwrap();
18158
+
18159
+ info!("------------------------- Verifying Signer Versions and Responses to Tenure Start Block -------------------------");
18160
+ // Assert that the signers sent only acceptances and that all updates indicate that the active protocol version is 0
18161
+ wait_for(30, || {
18162
+ let mut nmb_accept = 0;
18163
+ let stackerdb_events = test_observer::get_stackerdb_chunks();
18164
+ for chunk in stackerdb_events
18165
+ .into_iter()
18166
+ .flat_map(|chunk| chunk.modified_slots)
18167
+ {
18168
+ let message = SignerMessage::consensus_deserialize(&mut chunk.data.as_slice())
18169
+ .expect("Failed to deserialize SignerMessage");
18170
+ match message {
18171
+ SignerMessage::StateMachineUpdate(update) => {
18172
+ assert_eq!(update.active_signer_protocol_version, 0);
18173
+ }
18174
+ SignerMessage::BlockResponse(response) => {
18175
+ assert!(
18176
+ matches!(response, BlockResponse::Accepted(_)),
18177
+ "Should have only received acceptances"
18178
+ );
18179
+ nmb_accept += 1;
18180
+ }
18181
+ _ => {
18182
+ continue;
18183
+ }
18184
+ }
18185
+ }
18186
+ Ok(nmb_accept == num_signers)
18187
+ })
18188
+ .unwrap();
18189
+ signer_test.shutdown();
18190
+ }
0 commit comments