Skip to content

Commit c0beda9

Browse files
committed
fix: mock-miner should alway resets the mempool caches
1 parent 7856d63 commit c0beda9

File tree

4 files changed

+71
-126
lines changed

4 files changed

+71
-126
lines changed

stackslib/src/core/mempool.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1695,7 +1695,7 @@ impl MemPoolDB {
16951695
break MempoolIterationStopReason::DeadlineReached;
16961696
}
16971697

1698-
// First, try to read from the retry list
1698+
// Get the next candidate transaction.
16991699
let (candidate, update_estimate) = match settings.strategy {
17001700
MemPoolWalkStrategy::GlobalFeeRate => {
17011701
// First, try to read from the retry list

testnet/stacks-node/src/nakamoto_node/miner.rs

Lines changed: 15 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -528,16 +528,21 @@ impl BlockMinerThread {
528528
thread::sleep(Duration::from_millis(ABORT_TRY_AGAIN_MS));
529529
return Ok(());
530530
}
531+
532+
// Reset the mempool caches if needed. When mock-mining, we always
533+
// reset the caches, because the blocks we mine are not actually
534+
// processed, so the mempool caches are not valid.
531535
if self.reset_mempool_caches
532536
|| self.config.miner.mempool_walk_strategy
533537
== MemPoolWalkStrategy::NextNonceWithHighestFeeRate
538+
|| self.config.node.mock_mining
534539
{
535540
let mut mem_pool = self
536541
.config
537542
.connect_mempool_db()
538543
.expect("Database failure opening mempool");
539544

540-
if self.reset_mempool_caches {
545+
if self.reset_mempool_caches || self.config.node.mock_mining {
541546
mem_pool.reset_mempool_caches()?;
542547
} else {
543548
// Even if the nonce cache is still valid, NextNonceWithHighestFeeRate strategy
@@ -1400,20 +1405,15 @@ impl BlockMinerThread {
14001405
.make_vrf_proof()
14011406
.ok_or_else(|| NakamotoNodeError::BadVrfConstruction)?;
14021407

1403-
if self.last_block_mined.is_none() && parent_block_info.parent_tenure.is_none() {
1404-
warn!("Miner should be starting a new tenure, but failed to load parent tenure info");
1405-
return Err(NakamotoNodeError::ParentNotFound);
1406-
};
1407-
1408-
// If we're mock mining, we need to manipulate the `last_block_mined`
1409-
// to match what it should be based on the actual chainstate.
14101408
if self.config.node.mock_mining {
14111409
if let Some((last_block_consensus_hash, _)) = &self.last_block_mined {
1412-
// If the parent block is in the same tenure, then we should
1413-
// pretend that we mined it.
1410+
// If we're mock mining, we need to manipulate the `last_block_mined`
1411+
// to match what it should be based on the actual chainstate.
14141412
if last_block_consensus_hash
14151413
== &parent_block_info.stacks_parent_header.consensus_hash
14161414
{
1415+
// If the parent block is in the same tenure, then we should
1416+
// pretend that we mined it.
14171417
self.last_block_mined = Some((
14181418
parent_block_info.stacks_parent_header.consensus_hash,
14191419
parent_block_info
@@ -1429,6 +1429,11 @@ impl BlockMinerThread {
14291429
}
14301430
}
14311431

1432+
if self.last_block_mined.is_none() && parent_block_info.parent_tenure.is_none() {
1433+
warn!("Miner should be starting a new tenure, but failed to load parent tenure info");
1434+
return Err(NakamotoNodeError::ParentNotFound);
1435+
};
1436+
14321437
// create our coinbase if this is the first block we've mined this tenure
14331438
let tenure_start_info = self.make_tenure_start_info(
14341439
&chain_state,

testnet/stacks-node/src/nakamoto_node/relayer.rs

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1298,9 +1298,14 @@ impl RelayerThread {
12981298
debug!("Relayer: starting new tenure thread");
12991299

13001300
let rand_id = thread_rng().gen::<u32>();
1301+
let is_mock = if self.config.node.mock_mining {
1302+
"mock-"
1303+
} else {
1304+
""
1305+
};
13011306

13021307
let new_miner_handle = std::thread::Builder::new()
1303-
.name(format!("miner.{parent_tenure_start}.{rand_id}",))
1308+
.name(format!("{is_mock}miner.{parent_tenure_start}.{rand_id}",))
13041309
.stack_size(BLOCK_PROCESSOR_STACK_SIZE)
13051310
.spawn(move || {
13061311
debug!(

testnet/stacks-node/src/tests/nakamoto_integrations.rs

Lines changed: 49 additions & 114 deletions
Original file line numberDiff line numberDiff line change
@@ -109,7 +109,7 @@ use stacks_signer::v0::SpawnedSigner;
109109
use super::bitcoin_regtest::BitcoinCoreController;
110110
use crate::nakamoto_node::miner::{
111111
TEST_BLOCK_ANNOUNCE_STALL, TEST_BROADCAST_PROPOSAL_STALL, TEST_MINE_STALL,
112-
TEST_P2P_BROADCAST_SKIP,
112+
TEST_P2P_BROADCAST_SKIP, TEST_P2P_BROADCAST_STALL,
113113
};
114114
use crate::nakamoto_node::relayer::TEST_MINER_THREAD_STALL;
115115
use crate::neon::Counters;
@@ -8901,24 +8901,6 @@ fn mock_mining() {
89018901
&mut btc_regtest_controller,
89028902
);
89038903

8904-
info!("Bootstrapped to Epoch-3.0 boundary, starting nakamoto miner");
8905-
8906-
let burnchain = naka_conf.get_burnchain();
8907-
let sortdb = burnchain.open_sortition_db(true).unwrap();
8908-
let (chainstate, _) = StacksChainState::open(
8909-
naka_conf.is_mainnet(),
8910-
naka_conf.burnchain.chain_id,
8911-
&naka_conf.get_chainstate_path_str(),
8912-
None,
8913-
)
8914-
.unwrap();
8915-
8916-
let block_height_pre_3_0 =
8917-
NakamotoChainState::get_canonical_block_header(chainstate.db(), &sortdb)
8918-
.unwrap()
8919-
.unwrap()
8920-
.stacks_block_height;
8921-
89228904
info!("Nakamoto miner started...");
89238905
blind_signer(&naka_conf, &signers, &counters);
89248906

@@ -8953,12 +8935,10 @@ fn mock_mining() {
89538935
let follower_coord_channel = follower_run_loop.coordinator_channels();
89548936

89558937
let Counters {
8956-
naka_mined_blocks: follower_naka_mined_blocks,
8938+
naka_mined_blocks: follower_mined_blocks,
89578939
..
89588940
} = follower_run_loop.counters();
89598941

8960-
let mock_mining_blocks_start = follower_naka_mined_blocks.load(Ordering::SeqCst);
8961-
89628942
debug!(
89638943
"Booting follower-thread ({},{})",
89648944
&follower_conf.node.p2p_bind, &follower_conf.node.rpc_bind
@@ -8993,21 +8973,43 @@ fn mock_mining() {
89938973

89948974
// Mine `tenure_count` nakamoto tenures
89958975
for tenure_ix in 0..tenure_count {
8996-
let follower_naka_mined_blocks_before = follower_naka_mined_blocks.load(Ordering::SeqCst);
8997-
89988976
let commits_before = commits_submitted.load(Ordering::SeqCst);
8999-
next_block_and_process_new_stacks_block(&mut btc_regtest_controller, 60, &coord_channel)
9000-
.unwrap();
8977+
info!("Mining tenure {tenure_ix}");
90018978

9002-
let mut last_tip = BlockHeaderHash([0x00; 32]);
9003-
let mut last_tip_height = 0;
8979+
let height_before = get_chain_info(&naka_conf).stacks_tip_height;
8980+
let follower_mined_before = follower_mined_blocks.load(Ordering::SeqCst);
8981+
let follower_height_before = get_chain_info(&follower_conf).stacks_tip_height;
8982+
8983+
// Stall p2p broadcast so that the mock miner mines a block before
8984+
// seeing the block from the real miner.
8985+
TEST_P2P_BROADCAST_STALL.set(true);
8986+
info!("Waiting for the tenure {tenure_ix} start block to be mock-mined");
8987+
next_block_and(&mut btc_regtest_controller, 60, || {
8988+
Ok(follower_mined_blocks.load(Ordering::SeqCst) > follower_mined_before)
8989+
})
8990+
.expect("Failed to start a new tenure");
8991+
8992+
// Unstall p2p broadcast so that miner broadcasts the block and both
8993+
// nodes can process it.
8994+
TEST_P2P_BROADCAST_STALL.set(false);
8995+
wait_for(30, || {
8996+
Ok(get_chain_info(&naka_conf).stacks_tip_height > height_before
8997+
&& get_chain_info(&follower_conf).stacks_tip_height > follower_height_before)
8998+
})
8999+
.expect("Failed to advanced to the tenure start block");
90049000

90059001
// mine the interim blocks
90069002
for interim_block_ix in 0..inter_blocks_per_tenure {
9007-
let blocks_processed_before = coord_channel
9008-
.lock()
9009-
.expect("Mutex poisoned")
9010-
.get_stacks_blocks_processed();
9003+
let height_before = get_chain_info(&naka_conf).stacks_tip_height;
9004+
let follower_mined_before = follower_mined_blocks.load(Ordering::SeqCst);
9005+
let follower_height_before = get_chain_info(&follower_conf).stacks_tip_height;
9006+
9007+
// Stall p2p broadcast so that the mock miner mines a block before
9008+
// seeing the block from the real miner.
9009+
TEST_P2P_BROADCAST_STALL.set(true);
9010+
9011+
info!("Sending transfer tx for interim block {interim_block_ix} of tenure {tenure_ix}");
9012+
90119013
// submit a tx so that the miner will mine an extra block
90129014
let sender_nonce = tenure_ix * inter_blocks_per_tenure + interim_block_ix;
90139015
let transfer_tx = make_stacks_transfer_serialized(
@@ -9020,94 +9022,27 @@ fn mock_mining() {
90209022
);
90219023
submit_tx(&http_origin, &transfer_tx);
90229024

9023-
loop {
9024-
let blocks_processed = coord_channel
9025-
.lock()
9026-
.expect("Mutex poisoned")
9027-
.get_stacks_blocks_processed();
9028-
if blocks_processed > blocks_processed_before {
9029-
break;
9030-
}
9031-
thread::sleep(Duration::from_millis(100));
9032-
}
9033-
9034-
let info = get_chain_info_result(&naka_conf).unwrap();
9035-
assert_ne!(info.stacks_tip, last_tip);
9036-
assert_ne!(info.stacks_tip_height, last_tip_height);
9025+
// Wait for the interim block to be mock-mined
9026+
info!("Waiting for the interim block {interim_block_ix} of tenure {tenure_ix} to be mock-mined");
9027+
wait_for(30, || {
9028+
Ok(follower_mined_blocks.load(Ordering::SeqCst) > follower_mined_before)
9029+
})
9030+
.expect("Failed to process the submitted transfer tx in a new nakamoto block");
90379031

9038-
last_tip = info.stacks_tip;
9039-
last_tip_height = info.stacks_tip_height;
9032+
// Unstall p2p broadcast so that miner broadcasts the block and both
9033+
// nodes can process it.
9034+
TEST_P2P_BROADCAST_STALL.set(false);
9035+
wait_for(30, || {
9036+
Ok(get_chain_info(&naka_conf).stacks_tip_height > height_before
9037+
&& get_chain_info(&follower_conf).stacks_tip_height > follower_height_before)
9038+
})
9039+
.expect("Failed to advanced to the interim block");
90409040
}
90419041

9042-
let miner_node_info = get_chain_info(&naka_conf);
9043-
let follower_node_info = get_chain_info(&follower_conf);
9044-
info!("Node heights"; "miner" => miner_node_info.stacks_tip_height, "follower" => follower_node_info.stacks_tip_height);
9045-
9046-
// Wait for at least 2 blocks to be mined by the mock-miner
9047-
// This is to ensure that the mock miner has mined the tenure change
9048-
// block and at least one interim block.
9049-
wait_for(60, || {
9050-
Ok(follower_naka_mined_blocks.load(Ordering::SeqCst)
9051-
> follower_naka_mined_blocks_before + 1)
9052-
})
9053-
.unwrap_or_else(|_| {
9054-
panic!(
9055-
"Timed out waiting for mock miner block {}",
9056-
follower_naka_mined_blocks_before + 2
9057-
)
9058-
});
9059-
90609042
wait_for(20, || {
90619043
Ok(commits_submitted.load(Ordering::SeqCst) > commits_before)
90629044
})
9063-
.unwrap_or_else(|_| {
9064-
panic!(
9065-
"Timed out waiting for mock miner block {}",
9066-
follower_naka_mined_blocks_before + 1
9067-
)
9068-
});
9069-
}
9070-
9071-
// load the chain tip, and assert that it is a nakamoto block and at least 30 blocks have advanced in epoch 3
9072-
let tip = NakamotoChainState::get_canonical_block_header(chainstate.db(), &sortdb)
9073-
.unwrap()
9074-
.unwrap();
9075-
info!(
9076-
"Latest tip";
9077-
"height" => tip.stacks_block_height,
9078-
"is_nakamoto" => tip.anchored_header.as_stacks_nakamoto().is_some(),
9079-
);
9080-
9081-
let expected_blocks_mined = (inter_blocks_per_tenure + 1) * tenure_count;
9082-
let expected_tip_height = block_height_pre_3_0 + expected_blocks_mined;
9083-
assert!(tip.anchored_header.as_stacks_nakamoto().is_some());
9084-
assert_eq!(
9085-
tip.stacks_block_height, expected_tip_height,
9086-
"Should have mined (1 + interim_blocks_per_tenure) * tenure_count nakamoto blocks"
9087-
);
9088-
9089-
// Check follower's mock miner
9090-
let mock_mining_blocks_end = follower_naka_mined_blocks.load(Ordering::SeqCst);
9091-
let blocks_mock_mined = mock_mining_blocks_end - mock_mining_blocks_start;
9092-
assert!(
9093-
blocks_mock_mined >= tenure_count,
9094-
"Should have mock mined at least `tenure_count` nakamoto blocks. Mined = {blocks_mock_mined}. Expected = {tenure_count}"
9095-
);
9096-
9097-
// wait for follower to reach the chain tip
9098-
loop {
9099-
sleep_ms(1000);
9100-
let follower_node_info = get_chain_info(&follower_conf);
9101-
9102-
info!(
9103-
"Follower tip is now {}/{}",
9104-
&follower_node_info.stacks_tip_consensus_hash, &follower_node_info.stacks_tip
9105-
);
9106-
if follower_node_info.stacks_tip_consensus_hash == tip.consensus_hash
9107-
&& follower_node_info.stacks_tip == tip.anchored_header.block_hash()
9108-
{
9109-
break;
9110-
}
9045+
.expect("Timed out waiting for the block commit to be submitted");
91119046
}
91129047

91139048
coord_channel

0 commit comments

Comments
 (0)