@@ -505,12 +505,41 @@ impl MultipleMinerTest {
505
505
F: FnMut(&mut SignerConfig),
506
506
G: FnMut(&mut NeonConfig),
507
507
H: FnMut(&mut NeonConfig),
508
+ >(
509
+ num_signers: usize,
510
+ num_transfer_txs: u64,
511
+ signer_config_modifier: F,
512
+ node_1_config_modifier: G,
513
+ node_2_config_modifier: H,
514
+ ) -> MultipleMinerTest {
515
+ Self::new_with_signer_dist(
516
+ num_signers,
517
+ num_transfer_txs,
518
+ signer_config_modifier,
519
+ node_1_config_modifier,
520
+ node_2_config_modifier,
521
+ |port| u8::try_from(port % 2).unwrap(),
522
+ )
523
+ }
524
+
525
+ /// Create a new test harness for running multiple miners with num_signers underlying signers and enough funds to send
526
+ /// num_txs transfer transactions.
527
+ ///
528
+ /// Will also modify the signer config and the node 1 and node 2 configs with the provided
529
+ /// modifiers. Will partition the signer set so that ~half are listening and using node 1 for RPC and events,
530
+ /// and the rest are using node 2 unless otherwise specified via the signer config modifier.
531
+ pub fn new_with_signer_dist<
532
+ F: FnMut(&mut SignerConfig),
533
+ G: FnMut(&mut NeonConfig),
534
+ H: FnMut(&mut NeonConfig),
535
+ S: Fn(u16) -> u8,
508
536
>(
509
537
num_signers: usize,
510
538
num_transfer_txs: u64,
511
539
mut signer_config_modifier: F,
512
540
mut node_1_config_modifier: G,
513
541
mut node_2_config_modifier: H,
542
+ signer_distributor: S,
514
543
) -> MultipleMinerTest {
515
544
let sender_sk = Secp256k1PrivateKey::random();
516
545
let sender_addr = tests::to_addr(&sender_sk);
@@ -538,10 +567,10 @@ impl MultipleMinerTest {
538
567
num_signers,
539
568
vec![(sender_addr, (send_amt + send_fee) * num_transfer_txs)],
540
569
|signer_config| {
541
- let node_host = if signer_config.endpoint.port() % 2 == 0 {
542
- &node_1_rpc_bind
543
- } else {
544
- &node_2_rpc_bind
570
+ let node_host = match signer_distributor( signer_config.endpoint.port()) {
571
+ 0 => &node_1_rpc_bind,
572
+ 1 => &node_2_rpc_bind,
573
+ o => panic!("Multiminer test can't distribute signer to node #{o}"),
545
574
};
546
575
signer_config.node_host = node_host.to_string();
547
576
signer_config_modifier(signer_config);
@@ -567,11 +596,17 @@ impl MultipleMinerTest {
567
596
);
568
597
return true;
569
598
};
570
- if addr.port() % 2 == 0 || addr.port() == test_observer::EVENT_OBSERVER_PORT {
599
+ if addr.port() == test_observer::EVENT_OBSERVER_PORT {
571
600
return true;
572
601
}
573
- node_2_listeners.push(listener.clone());
574
- false
602
+ match signer_distributor(addr.port()) {
603
+ 0 => true,
604
+ 1 => {
605
+ node_2_listeners.push(listener.clone());
606
+ false
607
+ }
608
+ o => panic!("Multiminer test can't distribute signer to node #{o}"),
609
+ }
575
610
});
576
611
node_1_config_modifier(config);
577
612
},
@@ -15260,9 +15295,9 @@ fn bitcoin_reorg_extended_tenure() {
15260
15295
if env::var("BITCOIND_TEST") != Ok("1".into()) {
15261
15296
return;
15262
15297
}
15263
- let num_signers = 6 ;
15298
+ let num_signers = 5 ;
15264
15299
15265
- let mut miners = MultipleMinerTest::new_with_config_modifications (
15300
+ let mut miners = MultipleMinerTest::new_with_signer_dist (
15266
15301
num_signers,
15267
15302
60,
15268
15303
|signer_config| {
@@ -15271,10 +15306,38 @@ fn bitcoin_reorg_extended_tenure() {
15271
15306
signer_config.block_proposal_timeout = Duration::from_secs(600);
15272
15307
},
15273
15308
|_| {},
15274
- |_| {},
15309
+ |config| {
15310
+ config.burnchain.rpc_port = 28132;
15311
+ config.burnchain.peer_port = 28133;
15312
+ },
15313
+ |signer_port| {
15314
+ // only put 1 out of 5 signers on the second node.
15315
+ // this way, the 4 out of 5 signers can approve a block in bitcoin fork
15316
+ // that the fifth signer does not witness
15317
+ if signer_port % 5 == 0 {
15318
+ 1
15319
+ } else {
15320
+ 0
15321
+ }
15322
+ },
15275
15323
);
15276
15324
15277
15325
let (conf_1, _conf_2) = miners.get_node_configs();
15326
+ let btc_p2p_proxy = TestProxy {
15327
+ bind_port: 28133,
15328
+ forward_port: conf_1.burnchain.peer_port,
15329
+ drop_control: Arc::new(Mutex::new(false)),
15330
+ keep_running: Arc::new(Mutex::new(true)),
15331
+ };
15332
+ let btc_rpc_proxy = TestProxy {
15333
+ bind_port: 28132,
15334
+ forward_port: conf_1.burnchain.rpc_port,
15335
+ drop_control: Arc::new(Mutex::new(false)),
15336
+ keep_running: Arc::new(Mutex::new(true)),
15337
+ };
15338
+
15339
+ btc_p2p_proxy.spawn();
15340
+ btc_rpc_proxy.spawn();
15278
15341
15279
15342
let rl1_counters = miners.signer_test.running_nodes.counters.clone();
15280
15343
@@ -15315,7 +15378,9 @@ fn bitcoin_reorg_extended_tenure() {
15315
15378
15316
15379
let tenure_0_stacks_height = get_chain_info(&conf_1).stacks_tip_height;
15317
15380
miners.pause_commits_miner_1();
15318
- miners.signer_test.mine_bitcoin_block();
15381
+ miners
15382
+ .mine_bitcoin_blocks_and_confirm(&sortdb, 1, 60)
15383
+ .unwrap();
15319
15384
miners.signer_test.check_signer_states_normal();
15320
15385
let tip_sn = SortitionDB::get_canonical_burn_chain_tip(sortdb.conn()).unwrap();
15321
15386
assert_eq!(tip_sn.miner_pk_hash, Some(mining_pkh_1));
@@ -15336,7 +15401,13 @@ fn bitcoin_reorg_extended_tenure() {
15336
15401
assert!(last_active_sortition.was_sortition);
15337
15402
15338
15403
let tenure_1_info = get_chain_info(&conf_1);
15404
+
15339
15405
info!("Mining empty block!");
15406
+ // make sure that the second node *doesn't* get this bitcoin block
15407
+ // that way they will never see the losing side of the btc fork.
15408
+ *btc_p2p_proxy.drop_control.lock().unwrap() = true;
15409
+ *btc_rpc_proxy.drop_control.lock().unwrap() = true;
15410
+
15340
15411
miners.btc_regtest_controller_mut().build_next_block(1);
15341
15412
15342
15413
wait_for(60, || {
@@ -15357,10 +15428,6 @@ fn bitcoin_reorg_extended_tenure() {
15357
15428
.expect("Timed out waiting for contract-call");
15358
15429
}
15359
15430
15360
- miners
15361
- .signer_test
15362
- .check_signer_states_normal_missed_sortition();
15363
-
15364
15431
info!("------------------------- Triggering Bitcoin Fork -------------------------");
15365
15432
15366
15433
let burn_block_height = get_chain_info(&conf_1).burn_block_height;
@@ -15382,6 +15449,9 @@ fn bitcoin_reorg_extended_tenure() {
15382
15449
.btc_regtest_controller
15383
15450
.build_next_block(2);
15384
15451
15452
+ *btc_p2p_proxy.drop_control.lock().unwrap() = false;
15453
+ *btc_rpc_proxy.drop_control.lock().unwrap() = false;
15454
+
15385
15455
info!("Bitcoin fork triggered"; "ch" => %before_fork, "btc_height" => burn_block_height);
15386
15456
info!("Chain info before fork: {:?}", get_chain_info(&conf_1));
15387
15457
@@ -15393,15 +15463,40 @@ fn bitcoin_reorg_extended_tenure() {
15393
15463
15394
15464
info!("Chain info after fork: {:?}", get_chain_info(&conf_1));
15395
15465
15396
- for _ in 0..2 {
15397
- miners
15398
- .signer_test
15399
- .submit_burn_block_call_and_wait(&miners.sender_sk)
15400
- .expect("Timed out waiting for contract-call");
15401
- }
15466
+ miners
15467
+ .signer_test
15468
+ .submit_burn_block_call_and_wait(&miners.sender_sk)
15469
+ .expect("Timed out waiting for contract-call");
15470
+
15471
+ let latest = get_chain_info(&conf_1);
15472
+
15473
+ let rc = miners.signer_test.get_current_reward_cycle();
15474
+ let slot_ids = miners.signer_test.get_signer_indices(rc);
15475
+ let mut block_responses: Vec<_> = vec![];
15476
+ wait_for(60, || {
15477
+ block_responses = slot_ids
15478
+ .iter()
15479
+ .filter_map(|slot_id| {
15480
+ let latest_br = miners.signer_test.get_latest_block_response(slot_id.0);
15481
+ if latest_br.get_signer_signature_hash().0 == latest.stacks_tip.0 {
15482
+ Some(latest_br)
15483
+ } else {
15484
+ None
15485
+ }
15486
+ })
15487
+ .collect();
15488
+ Ok(block_responses.len() == num_signers)
15489
+ })
15490
+ .unwrap();
15491
+
15492
+ assert!(block_responses
15493
+ .iter()
15494
+ .all(|resp| resp.as_block_accepted().is_some()));
15402
15495
15403
15496
miners.submit_commit_miner_1(&sortdb);
15404
- miners.signer_test.mine_bitcoin_block();
15497
+ miners
15498
+ .mine_bitcoin_blocks_and_confirm(&sortdb, 1, 60)
15499
+ .unwrap();
15405
15500
15406
15501
let last_active_sortition = get_sortition_info(&conf_1);
15407
15502
assert!(last_active_sortition.was_sortition);
0 commit comments