Skip to content

Commit ea6f561

Browse files
Merge pull request #6636 from jacinta-stacks/chore/fix-race-conditions-in-scenario-tests
Remove FromGlobalHeight from scenario tests as it has a race condition
2 parents 252142a + ea5e1ed commit ea6f561

File tree

3 files changed

+39
-58
lines changed

3 files changed

+39
-58
lines changed

stacks-node/src/tests/nakamoto_integrations.rs

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1365,6 +1365,8 @@ pub fn setup_epoch_3_reward_set(
13651365
"epoch_3_start_height" => {epoch_3_start_height},
13661366
);
13671367
for (stacker_sk, signer_sk) in stacker_sks.iter().zip(signer_sks.iter()) {
1368+
let address = StacksAddress::p2pkh(false, &StacksPublicKey::from_private(stacker_sk));
1369+
let nonce = get_account(&http_origin, &address).nonce;
13681370
let pox_addr = PoxAddress::from_legacy(
13691371
AddressHashMode::SerializeP2PKH,
13701372
tests::to_addr(stacker_sk).bytes().clone(),
@@ -1387,7 +1389,7 @@ pub fn setup_epoch_3_reward_set(
13871389
let signer_pk = StacksPublicKey::from_private(signer_sk);
13881390
let stacking_tx = make_contract_call(
13891391
stacker_sk,
1390-
0,
1392+
nonce,
13911393
1000,
13921394
naka_conf.burnchain.chain_id,
13931395
&StacksAddress::burn_address(false),
@@ -1430,12 +1432,15 @@ pub fn boot_to_epoch_3_reward_set_calculation_boundary(
14301432
num_stacking_cycles,
14311433
);
14321434

1433-
let epochs = naka_conf.burnchain.epochs.clone().unwrap();
1434-
let epoch_3 = &epochs[StacksEpochId::Epoch30];
1435+
let epoch_3_start_height = naka_conf
1436+
.burnchain
1437+
.epochs
1438+
.as_ref()
1439+
.map(|epochs| epochs[StacksEpochId::Epoch30].start_height)
1440+
.unwrap();
14351441
let reward_cycle_len = naka_conf.get_burnchain().pox_constants.reward_cycle_length as u64;
14361442
let prepare_phase_len = naka_conf.get_burnchain().pox_constants.prepare_length as u64;
14371443

1438-
let epoch_3_start_height = epoch_3.start_height;
14391444
assert!(
14401445
epoch_3_start_height > 0,
14411446
"Epoch 3.0 start height must be greater than 0"

stacks-node/src/tests/signer/commands/block_wait.rs

Lines changed: 14 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,6 @@ pub struct ChainExpectNakaBlock {
2626

2727
#[derive(Debug)]
2828
enum HeightStrategy {
29-
FromGlobalHeight,
3029
FromMinerHeight,
3130
FromStateHeight,
3231
}
@@ -44,10 +43,6 @@ impl ChainExpectNakaBlock {
4443
}
4544
}
4645

47-
pub fn from_global_height(ctx: Arc<SignerTestContext>, miner_index: usize) -> Self {
48-
Self::new(ctx, miner_index, HeightStrategy::FromGlobalHeight)
49-
}
50-
5146
pub fn from_miner_height(ctx: Arc<SignerTestContext>, miner_index: usize) -> Self {
5247
Self::new(ctx, miner_index, HeightStrategy::FromMinerHeight)
5348
}
@@ -76,33 +71,6 @@ impl Command<SignerTestState, SignerTestContext> for ChainExpectNakaBlock {
7671

7772
// Calculate expected height based on the strategy
7873
match self.height_strategy {
79-
HeightStrategy::FromGlobalHeight => {
80-
// Use global height approach
81-
let conf = self.ctx.get_node_config(self.miner_index);
82-
let stacks_height_before = self.ctx.get_peer_stacks_tip_height();
83-
let expected_height = stacks_height_before + 1;
84-
85-
let miner_block =
86-
wait_for_block_pushed_by_miner_key(30, expected_height, &miner_pk).expect(
87-
&format!(
88-
"Failed to get block for miner {} - Strategy: {:?}",
89-
self.miner_index, self.height_strategy
90-
),
91-
);
92-
93-
let mined_block_height = miner_block.header.chain_length;
94-
95-
info!(
96-
"Miner {} mined Nakamoto block at height {}",
97-
self.miner_index, mined_block_height
98-
);
99-
100-
let info_after = get_chain_info(&conf);
101-
102-
assert_eq!(info_after.stacks_tip, miner_block.header.block_hash());
103-
assert_eq!(info_after.stacks_tip_height, mined_block_height);
104-
assert_eq!(mined_block_height, expected_height);
105-
}
10674
HeightStrategy::FromMinerHeight => {
10775
// Use miner-specific height approach
10876
let conf = self.ctx.get_node_config(self.miner_index);
@@ -175,7 +143,7 @@ impl Command<SignerTestState, SignerTestContext> for ChainExpectNakaBlock {
175143
(1usize..=2usize).prop_flat_map(move |miner_index| {
176144
prop_oneof![
177145
Just(CommandWrapper::new(
178-
ChainExpectNakaBlock::from_global_height(ctx.clone(), miner_index)
146+
ChainExpectNakaBlock::from_state_height(ctx.clone(), miner_index)
179147
)),
180148
Just(CommandWrapper::new(
181149
ChainExpectNakaBlock::from_miner_height(ctx.clone(), miner_index)
@@ -349,22 +317,23 @@ impl Command<SignerTestState, SignerTestContext> for ChainExpectStacksTenureChan
349317
true
350318
}
351319

352-
fn apply(&self, _state: &mut SignerTestState) {
320+
fn apply(&self, state: &mut SignerTestState) {
353321
let miner_pk = self.ctx.get_miner_public_key(self.miner_index);
354-
// TODO: this is a bug. You cannot gaurantee that the block has not already been processed
355-
// by the node causing a potential off by one race condition.
356-
// See https://github.com/stacks-network/stacks-core/issues/6221
357-
let expected_height = self.ctx.get_peer_stacks_tip_height() + 1;
322+
// Cannot use global height as this would result in a race condition. Cannot gaurantee
323+
// that the node has not already processed the stacks block. Must use stored state.
324+
let expected_height = state.last_stacks_block_height.expect(
325+
"Cannot wait for a tenure change block if we haven't set the last_stacks_block_height",
326+
) + 1;
358327

359328
info!(
360-
"Applying: Waiting for tenure change block at height {} from miner {}",
361-
expected_height, self.miner_index
329+
"Applying: Waiting for tenure change block at height {expected_height} from miner {}",
330+
self.miner_index
362331
);
363332

364333
let block =
365334
wait_for_block_pushed_by_miner_key(30, expected_height, &miner_pk).expect(&format!(
366-
"Failed to get tenure change block for miner {} at height {}",
367-
self.miner_index, expected_height
335+
"Failed to get tenure change block for miner {} at height {expected_height}",
336+
self.miner_index
368337
));
369338

370339
// Verify this is a tenure change block
@@ -380,15 +349,14 @@ impl Command<SignerTestState, SignerTestContext> for ChainExpectStacksTenureChan
380349

381350
assert!(
382351
is_tenure_change_block_found,
383-
"Block at height {} from miner {} is not a proper tenure change block. Transactions: {:?}",
384-
expected_height,
352+
"Block at height {expected_height} from miner {} is not a proper tenure change block. Transactions: {:?}",
385353
self.miner_index,
386354
block.txs.iter().map(|tx| &tx.payload).collect::<Vec<_>>()
387355
);
388356

389357
info!(
390-
"Successfully verified tenure change block at height {} from miner {}",
391-
expected_height, self.miner_index
358+
"Successfully verified tenure change block at height {expected_height} from miner {}",
359+
self.miner_index
392360
);
393361
}
394362

stacks-node/src/tests/signer/commands/boot.rs

Lines changed: 16 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ use std::sync::Arc;
22

33
use madhouse::{Command, CommandWrapper};
44
use proptest::prelude::{Just, Strategy};
5+
use stacks::core::StacksEpochId;
56

67
use super::context::{SignerTestContext, SignerTestState};
78
use crate::tests::neon_integrations::get_chain_info;
@@ -32,17 +33,24 @@ impl Command<SignerTestState, SignerTestContext> for ChainBootToEpoch3 {
3233
fn apply(&self, state: &mut SignerTestState) {
3334
info!("Applying: Booting miners to Nakamoto");
3435

35-
self.ctx.miners.lock().unwrap().boot_to_epoch_3();
36-
3736
// We can use miner 1 conf to get the chain info - it's the same for both miners
3837
let conf = self.ctx.get_node_config(1);
39-
let burn_block_height = get_chain_info(&conf).burn_block_height;
40-
41-
state.epoch_3_start_block_height = Some(self.ctx.get_peer_stacks_tip_height());
42-
43-
// Epoch 3.0 is expected to start at burn block height 231
44-
assert_eq!(burn_block_height, 231);
4538

39+
let epoch_3_start_height = conf
40+
.burnchain
41+
.epochs
42+
.as_ref()
43+
.map(|epochs| epochs[StacksEpochId::Epoch30].start_height)
44+
.unwrap();
45+
// If we have successfully bootstrapped already, don't bother doing it again.
46+
if get_chain_info(&conf).burn_block_height < epoch_3_start_height {
47+
self.ctx.miners.lock().unwrap().boot_to_epoch_3();
48+
assert_eq!(
49+
get_chain_info(&conf).burn_block_height,
50+
epoch_3_start_height
51+
);
52+
state.epoch_3_start_block_height = Some(self.ctx.get_peer_stacks_tip_height());
53+
}
4654
state.is_booted_to_nakamoto = true;
4755
}
4856

0 commit comments

Comments
 (0)