Skip to content

Commit ffc1b2e

Browse files
authored
Merge pull request #6203 from obycode/feat/miner-metrics
Miner metrics and mock miner improvements
2 parents 391262c + c015d14 commit ffc1b2e

File tree

9 files changed

+110
-127
lines changed

9 files changed

+110
-127
lines changed

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,9 @@ and this project adheres to the versioning scheme outlined in the [README.md](RE
1010
### Added
1111

1212
- Added a new RPC endpoint `/v3/health` to query the node's health status. The endpoint returns a 200 status code with relevant synchronization information (including the node's current Stacks tip height, the maximum Stacks tip height among its neighbors, and the difference between these two). A user can use the `difference_from_max_peer` value to decide what is a good threshold for them before considering the node out of sync. The endpoint returns a 500 status code if the query cannot retrieve viable data.
13+
- Improve prometheus metrics to gain more insights into the current state of the mempool
14+
- `stacks_node_miner_stop_reason_total`: Counts the number of times the miner stopped mining due to various reasons.
15+
- Always report the number of transactions mined in the last attempt, even if there were 0
1316

1417
- Added a new option `--postcondition-mode [allow, deny]` to `blockstack-cli publish` command, to set the post-condition mode to allow or deny on the transaction (default is deny)
1518

@@ -20,6 +23,7 @@ and this project adheres to the versioning scheme outlined in the [README.md](RE
2023
### Fixed
2124

2225
- Fixed an issue that prevented the correct usage of anchor mode options (`--microblock-only`, `--block-only`) when using `blockstack-cli publish` command.
26+
- Fix several bugs in the mock-miner that caused it to fail to mine blocks in certain conditions
2327

2428
## [3.1.0.0.12]
2529

stackslib/src/chainstate/nakamoto/miner.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -602,6 +602,7 @@ impl NakamotoBlockBuilder {
602602
}
603603

604604
if builder.txs.is_empty() {
605+
set_last_mined_block_transaction_count(0);
605606
return Err(Error::NoTransactionsToMine);
606607
}
607608

stackslib/src/chainstate/stacks/miner.rs

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,8 @@ use crate::clarity_vm::clarity::{ClarityInstance, Error as clarity_error};
5454
use crate::core::mempool::*;
5555
use crate::core::*;
5656
use crate::monitoring::{
57-
set_last_mined_block_transaction_count, set_last_mined_execution_cost_observed,
57+
increment_miner_stop_reason, set_last_mined_block_transaction_count,
58+
set_last_mined_execution_cost_observed, MinerStopReason,
5859
};
5960
use crate::net::relay::Relayer;
6061

@@ -2801,6 +2802,7 @@ fn select_and_apply_transactions_from_mempool<B: BlockBuilder>(
28012802
(*settings.miner_status.lock().expect("FATAL: mutex poisoned")).is_blocked();
28022803
if blocked {
28032804
info!("Miner stopping due to preemption");
2805+
increment_miner_stop_reason(MinerStopReason::Preempted);
28042806
return Ok(None);
28052807
}
28062808

@@ -2809,6 +2811,7 @@ fn select_and_apply_transactions_from_mempool<B: BlockBuilder>(
28092811

28102812
if block_limit_hit == BlockLimitFunction::LIMIT_REACHED {
28112813
info!("Miner stopping due to limit reached");
2814+
increment_miner_stop_reason(MinerStopReason::LimitReached);
28122815
return Ok(None);
28132816
}
28142817
let time_now = get_epoch_time_ms();
@@ -2817,6 +2820,7 @@ fn select_and_apply_transactions_from_mempool<B: BlockBuilder>(
28172820
"Miner stopping due to mining time exceeded ({} ms)",
28182821
max_miner_time_ms
28192822
);
2823+
increment_miner_stop_reason(MinerStopReason::DeadlineReached);
28202824
return Ok(None);
28212825
}
28222826
if let Some(time_estimate) = txinfo.metadata.time_estimate_ms {
@@ -2926,6 +2930,7 @@ fn select_and_apply_transactions_from_mempool<B: BlockBuilder>(
29262930
{
29272931
info!("Miner stopping due to limit reached");
29282932
block_limit_hit = BlockLimitFunction::LIMIT_REACHED;
2933+
increment_miner_stop_reason(MinerStopReason::LimitReached);
29292934
return Ok(None);
29302935
}
29312936
}

stackslib/src/core/mempool.rs

Lines changed: 7 additions & 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
@@ -1733,6 +1733,9 @@ impl MemPoolDB {
17331733
!start_with_no_estimate,
17341734
),
17351735
None => {
1736+
monitoring::increment_miner_stop_reason(
1737+
monitoring::MinerStopReason::NoTransactions,
1738+
);
17361739
break MempoolIterationStopReason::NoMoreCandidates;
17371740
}
17381741
}
@@ -1749,6 +1752,9 @@ impl MemPoolDB {
17491752
(tx, update_estimate)
17501753
}
17511754
None => {
1755+
monitoring::increment_miner_stop_reason(
1756+
monitoring::MinerStopReason::NoTransactions,
1757+
);
17521758
break MempoolIterationStopReason::NoMoreCandidates;
17531759
}
17541760
}

stackslib/src/monitoring/mod.rs

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -462,6 +462,22 @@ pub fn get_burnchain_signer() -> Option<BurnchainSigner> {
462462
None
463463
}
464464

465+
define_named_enum!(MinerStopReason {
466+
NoTransactions("no_transactions"),
467+
Preempted("preempted"),
468+
LimitReached("limit_reached"),
469+
DeadlineReached("deadline_reached"),
470+
});
471+
472+
// Increment the counter for the given miner stop reason.
473+
#[allow(unused_variables)]
474+
pub fn increment_miner_stop_reason(reason: MinerStopReason) {
475+
#[cfg(feature = "monitoring_prom")]
476+
prometheus::MINER_STOP_REASON_TOTAL
477+
.with_label_values(&[reason.get_name_str()])
478+
.inc();
479+
}
480+
465481
#[derive(Debug)]
466482
pub struct SetGlobalBurnchainSignerError;
467483

stackslib/src/monitoring/prometheus.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -254,6 +254,12 @@ lazy_static! {
254254
"stacks_node_miner_current_median_commitment_low",
255255
"Low 64 bits of a miner's median commitment over the mining commitment window."
256256
)).unwrap();
257+
258+
pub static ref MINER_STOP_REASON_TOTAL: IntCounterVec = register_int_counter_vec!(
259+
"stacks_node_miner_stop_reason_total",
260+
"Total number of times the miner stopped for each reason",
261+
&["reason"]
262+
).unwrap();
257263
}
258264

259265
pub fn new_rpc_call_timer(path: &str) -> HistogramTimer {

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!(

0 commit comments

Comments
 (0)