|
| 1 | +use std::sync::{ |
| 2 | + atomic::{AtomicBool, AtomicU8, Ordering}, |
| 3 | + Arc, |
| 4 | +}; |
| 5 | + |
| 6 | +use kaspa_consensus_core::api::counters::ProcessingCountersSnapshot; |
| 7 | +use kaspa_core::{trace, warn}; |
| 8 | + |
| 9 | +use super::{mining_rule::MiningRule, ExtraData}; |
| 10 | + |
| 11 | +/// NoTransactionsRule |
| 12 | +/// Attempt to recover from consistent BadMerkleRoot errors by mining blocks without |
| 13 | +/// any transactions. |
| 14 | +/// |
| 15 | +/// Trigger: |
| 16 | +/// - Submitted blocks resulted in BadMerkleRoot errors and there were no successfully submitted blocks |
| 17 | +/// |
| 18 | +/// Recovery: |
| 19 | +/// - Two cooldown periods have passed, OR |
| 20 | +/// - Any submit block RPC call succeeded |
| 21 | +pub struct NoTransactionsRule { |
| 22 | + pub is_enabled: Arc<AtomicBool>, |
| 23 | + pub cooldown: AtomicU8, |
| 24 | +} |
| 25 | + |
| 26 | +impl NoTransactionsRule { |
| 27 | + pub fn new(is_enabled: Arc<AtomicBool>) -> Self { |
| 28 | + Self { is_enabled, cooldown: AtomicU8::new(0) } |
| 29 | + } |
| 30 | +} |
| 31 | + |
| 32 | +impl MiningRule for NoTransactionsRule { |
| 33 | + fn check_rule(&self, delta: &ProcessingCountersSnapshot, _extra_data: &ExtraData) { |
| 34 | + let cooldown_count = self.cooldown.load(Ordering::SeqCst); |
| 35 | + |
| 36 | + if cooldown_count > 0 { |
| 37 | + // Recovering |
| 38 | + if delta.submit_block_success_count > 0 || self.cooldown.fetch_sub(1, Ordering::SeqCst) == 1 { |
| 39 | + // Recovery condition #1: Any submit block RPC call succeeded in this interval |
| 40 | + // Recovery condition #2: Cooldown period has passed (important for low hashrate miners whose successful blocks are few and far between) |
| 41 | + self.cooldown.store(0, Ordering::SeqCst); |
| 42 | + self.is_enabled.store(false, Ordering::SeqCst); |
| 43 | + warn!("NoTransactionsRule: recovered | Bad Merkle Root Count: {}", delta.submit_block_bad_merkle_root_count); |
| 44 | + } |
| 45 | + } else if delta.submit_block_bad_merkle_root_count > 0 && delta.submit_block_success_count == 0 { |
| 46 | + // Triggered state |
| 47 | + // When submit block BadMerkleRoot errors occurred and there were no successfully submitted blocks |
| 48 | + if let Ok(false) = self.is_enabled.compare_exchange(false, true, Ordering::SeqCst, Ordering::SeqCst) { |
| 49 | + warn!( |
| 50 | + "NoTransactionsRule: triggered | Bad Merkle Root Count: {} | Successfully submitted blocks: {}", |
| 51 | + delta.submit_block_bad_merkle_root_count, delta.submit_block_success_count |
| 52 | + ); |
| 53 | + self.cooldown.store(2, Ordering::Relaxed); |
| 54 | + } |
| 55 | + } else { |
| 56 | + // Normal state |
| 57 | + trace!( |
| 58 | + "NoTransactionsRule: normal | Bad Merkle Root Count: {} | Successfully submitted blocks: {}", |
| 59 | + delta.submit_block_bad_merkle_root_count, |
| 60 | + delta.submit_block_success_count, |
| 61 | + ); |
| 62 | + } |
| 63 | + } |
| 64 | +} |
0 commit comments