Skip to content

Commit 103c388

Browse files
committed
Split MinerMineBlockAndTriggerTenureChange into MinerMineBtcBlocks + ChainExpectTenureChange
1 parent b12eabc commit 103c388

File tree

4 files changed

+91
-101
lines changed

4 files changed

+91
-101
lines changed

testnet/stacks-node/src/tests/signer/commands/bitcoin_mining.rs

Lines changed: 5 additions & 97 deletions
Original file line numberDiff line numberDiff line change
@@ -1,104 +1,10 @@
1-
use std::sync::atomic::Ordering;
21
use std::sync::Arc;
32

43
use madhouse::{Command, CommandWrapper};
5-
use proptest::prelude::{Just, Strategy};
6-
use stacks::chainstate::stacks::TenureChangeCause;
4+
use proptest::prelude::Strategy;
75
use tracing::info;
86

97
use super::context::{SignerTestContext, SignerTestState};
10-
use crate::tests::neon_integrations::get_chain_info;
11-
12-
/// Command to mine a new Bitcoin block and trigger a tenure change for a specified miner.
13-
/// This command simulates the process of a miner finding a Bitcoin block, submitting a tenure
14-
/// change transaction, and then mining a corresponding Stacks Nakamoto block.
15-
pub struct MinerMineBlockAndTriggerTenureChange {
16-
ctx: Arc<SignerTestContext>,
17-
miner_index: usize,
18-
}
19-
20-
impl MinerMineBlockAndTriggerTenureChange {
21-
pub fn new(ctx: Arc<SignerTestContext>, miner_index: usize) -> Self {
22-
Self { ctx, miner_index }
23-
}
24-
}
25-
26-
impl Command<SignerTestState, SignerTestContext> for MinerMineBlockAndTriggerTenureChange {
27-
fn check(&self, state: &SignerTestState) -> bool {
28-
let conf = self.ctx.get_node_config(self.miner_index);
29-
let burn_height = get_chain_info(&conf).burn_block_height;
30-
31-
let (miner_1_submitted_commit_last_burn_height, miner_2_submitted_commit_last_burn_height) = {
32-
let miner_1_height = self
33-
.ctx
34-
.get_counters_for_miner(1)
35-
.naka_submitted_commit_last_burn_height
36-
.load(Ordering::SeqCst);
37-
let miner_2_height = self
38-
.ctx
39-
.get_counters_for_miner(2)
40-
.naka_submitted_commit_last_burn_height
41-
.load(Ordering::SeqCst);
42-
(miner_1_height, miner_2_height)
43-
};
44-
45-
let (current_miner_height, other_miner_height) = match self.miner_index {
46-
1 => (
47-
miner_1_submitted_commit_last_burn_height,
48-
miner_2_submitted_commit_last_burn_height,
49-
),
50-
2 => (
51-
miner_2_submitted_commit_last_burn_height,
52-
miner_1_submitted_commit_last_burn_height,
53-
),
54-
_ => panic!("Invalid miner index: {}", self.miner_index),
55-
};
56-
57-
info!(
58-
"Checking: Miner {} block verification - burn height: {}, current miner: {}, other miner: {}",
59-
self.miner_index,
60-
burn_height,
61-
current_miner_height,
62-
other_miner_height
63-
);
64-
65-
state.is_booted_to_nakamoto
66-
&& burn_height == current_miner_height
67-
&& burn_height > other_miner_height
68-
}
69-
70-
fn apply(&self, state: &mut SignerTestState) {
71-
info!("Applying: Mining Bitcoin block and tenure change tx");
72-
73-
state.last_block_height = Some(self.ctx.get_peer_stacks_tip_height());
74-
75-
let sortdb = self.ctx.get_sortition_db(self.miner_index);
76-
77-
self.ctx
78-
.miners
79-
.lock()
80-
.unwrap()
81-
.mine_bitcoin_block_and_tenure_change_tx(&sortdb, TenureChangeCause::BlockFound, 60)
82-
.expect("Failed to mine BTC block");
83-
}
84-
85-
fn label(&self) -> String {
86-
format!(
87-
"MINE_BITCOIN_BLOCK_AND_TENURE_CHANGE_MINER_{}",
88-
self.miner_index
89-
)
90-
}
91-
92-
fn build(
93-
ctx: Arc<SignerTestContext>,
94-
) -> impl Strategy<Value = CommandWrapper<SignerTestState, SignerTestContext>> {
95-
(1usize..=2usize).prop_flat_map(move |miner_index| {
96-
Just(CommandWrapper::new(
97-
MinerMineBlockAndTriggerTenureChange::new(ctx.clone(), miner_index),
98-
))
99-
})
100-
}
101-
}
1028

1039
/// Command to mine a single Bitcoin block in the test environment and wait for its confirmation.
10410
/// This command simulates the process of mining a new Bitcoin block in the Stacks blockchain
@@ -129,9 +35,11 @@ impl Command<SignerTestState, SignerTestContext> for MinerMineBtcBlocks {
12935
true
13036
}
13137

132-
fn apply(&self, _state: &mut SignerTestState) {
38+
fn apply(&self, state: &mut SignerTestState) {
13339
info!("Applying: Mining {} Bitcoin block(s)", self.num_blocks);
13440

41+
state.last_block_height = Some(self.ctx.get_peer_stacks_tip_height());
42+
13543
// We can use miner 1 sortition db - it's the same for both miners
13644
let sortdb = self.ctx.get_sortition_db(1);
13745

@@ -227,4 +135,4 @@ impl Command<SignerTestState, SignerTestContext> for ChainGenerateBtcBlocks {
227135
})
228136
]
229137
}
230-
}
138+
}

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

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ use libsigner::v0::messages::RejectReason;
55
use madhouse::{Command, CommandWrapper};
66
use proptest::prelude::{Just, Strategy};
77
use proptest::prop_oneof;
8+
use stacks::chainstate::stacks::{TenureChangeCause, TransactionPayload};
89

910
use super::context::{SignerTestContext, SignerTestState};
1011
use crate::tests::neon_integrations::get_chain_info;
@@ -326,3 +327,81 @@ impl Command<SignerTestState, SignerTestContext> for ChainExpectNakaBlockProposa
326327
})
327328
}
328329
}
330+
331+
/// Command to wait for a tenure change block from a specific miner.
332+
/// This command waits for a block that contains exactly 2 transactions:
333+
/// 1. A TenureChange transaction with cause BlockFound
334+
/// 2. A Coinbase transaction
335+
/// This verifies that a proper tenure change has occurred.
336+
pub struct ChainExpectTenureChange {
337+
ctx: Arc<SignerTestContext>,
338+
miner_index: usize,
339+
}
340+
341+
impl ChainExpectTenureChange {
342+
pub fn new(ctx: Arc<SignerTestContext>, miner_index: usize) -> Self {
343+
Self { ctx, miner_index }
344+
}
345+
}
346+
347+
impl Command<SignerTestState, SignerTestContext> for ChainExpectTenureChange {
348+
fn check(&self, _state: &SignerTestState) -> bool {
349+
info!(
350+
"Checking: Waiting for tenure change block from miner {}",
351+
self.miner_index
352+
);
353+
true
354+
}
355+
356+
fn apply(&self, _state: &mut SignerTestState) {
357+
let miner_pk = self.ctx.get_miner_public_key(self.miner_index);
358+
let expected_height = self.ctx.get_peer_stacks_tip_height() + 1;
359+
360+
info!(
361+
"Applying: Waiting for tenure change block at height {} from miner {}",
362+
expected_height, self.miner_index
363+
);
364+
365+
let block = wait_for_block_pushed_by_miner_key(30, expected_height, &miner_pk)
366+
.expect(&format!(
367+
"Failed to get tenure change block for miner {} at height {}",
368+
self.miner_index, expected_height
369+
));
370+
371+
// Verify this is a tenure change block
372+
let is_tenure_change_block_found = block.txs.len() == 2
373+
&& matches!(
374+
block.txs[0].payload,
375+
TransactionPayload::TenureChange(ref payload) if payload.cause == TenureChangeCause::BlockFound
376+
)
377+
&& matches!(block.txs[1].payload, TransactionPayload::Coinbase(..));
378+
379+
assert!(
380+
is_tenure_change_block_found,
381+
"Block at height {} from miner {} is not a proper tenure change block. Transactions: {:?}",
382+
expected_height,
383+
self.miner_index,
384+
block.txs.iter().map(|tx| &tx.payload).collect::<Vec<_>>()
385+
);
386+
387+
info!(
388+
"Successfully verified tenure change block at height {} from miner {}",
389+
expected_height, self.miner_index
390+
);
391+
}
392+
393+
fn label(&self) -> String {
394+
format!("WAIT_FOR_TENURE_CHANGE_BLOCK_FROM_MINER_{}", self.miner_index)
395+
}
396+
397+
fn build(
398+
ctx: Arc<SignerTestContext>,
399+
) -> impl Strategy<Value = CommandWrapper<SignerTestState, SignerTestContext>> {
400+
(1usize..=2usize).prop_flat_map(move |miner_index| {
401+
Just(CommandWrapper::new(ChainExpectTenureChange::new(
402+
ctx.clone(),
403+
miner_index,
404+
)))
405+
})
406+
}
407+
}

testnet/stacks-node/src/tests/signer/commands/mod.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,11 +12,11 @@ mod stacks_mining;
1212
mod transfer;
1313

1414
pub use bitcoin_mining::{
15-
ChainGenerateBtcBlocks, MinerMineBlockAndTriggerTenureChange, MinerMineBtcBlocks,
15+
ChainGenerateBtcBlocks, MinerMineBtcBlocks,
1616
};
1717
pub use block_commit::MinerSubmitBlockCommit;
1818
pub use block_verify::ChainVerifyMinerBlockCount;
19-
pub use block_wait::{ChainExpectNakaBlock, ChainExpectNakaBlockProposal};
19+
pub use block_wait::{ChainExpectNakaBlock, ChainExpectNakaBlockProposal, ChainExpectTenureChange};
2020
pub use boot::ChainBootToEpoch3;
2121
pub use commit_ops::ChainMinerCommitOp;
2222
pub use context::SignerTestContext;

testnet/stacks-node/src/tests/signer/v0.rs

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10963,8 +10963,11 @@ fn disallow_reorg_within_first_proposal_burn_block_timing_secs_but_more_than_one
1096310963
(ChainMinerCommitOp::disable_for(test_context.clone(), MINER2)),
1096410964
ChainBootToEpoch3,
1096510965
(ChainMinerCommitOp::disable_for(test_context.clone(), MINER1)),
10966-
(MinerMineBlockAndTriggerTenureChange::new(test_context.clone(), MINER1)), // TODO: This can be splitted in two commands (MinerMineBtcBlocks + ChainExpectTenureChange)
10967-
(ChainExpectNakaBlock::from_state_height(test_context.clone(), MINER1)),
10966+
10967+
(MinerMineBtcBlocks::one(test_context.clone())), // Sets block height in the state
10968+
(ChainExpectTenureChange::new(test_context.clone(), MINER1)),
10969+
(ChainExpectNakaBlock::from_state_height(test_context.clone(), MINER1)), // Uses block height from the state
10970+
1096810971
(ChainExpectSortitionWinner::new(test_context.clone(), MINER1)),
1096910972
(MinerSubmitBlockCommit::new(test_context.clone(), MINER2)),
1097010973
(ChainStacksMining::pause()),

0 commit comments

Comments
 (0)