Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 21 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,7 @@ kaspa-muhash = { version = "0.16.1", path = "crypto/muhash" }
kaspa-notify = { version = "0.16.1", path = "notify" }
kaspa-p2p-flows = { version = "0.16.1", path = "protocol/flows" }
kaspa-p2p-lib = { version = "0.16.1", path = "protocol/p2p" }
kaspa-p2p-mining = { version = "0.16.1", path = "protocol/mining" }
kaspa-perf-monitor = { version = "0.16.1", path = "metrics/perf_monitor" }
kaspa-pow = { version = "0.16.1", path = "consensus/pow" }
kaspa-rpc-core = { version = "0.16.1", path = "rpc/core" }
Expand Down
11 changes: 4 additions & 7 deletions components/consensusmanager/src/session.rs
Original file line number Diff line number Diff line change
Expand Up @@ -249,6 +249,10 @@ impl ConsensusSessionOwned {
self.clone().spawn_blocking(|c| c.get_sink_timestamp()).await
}

pub async fn async_get_sink_daa_score_timestamp(&self) -> DaaScoreTimestamp {
self.clone().spawn_blocking(|c| c.get_sink_daa_score_timestamp()).await
}

pub async fn async_get_current_block_color(&self, hash: Hash) -> Option<bool> {
self.clone().spawn_blocking(move |c| c.get_current_block_color(hash)).await
}
Expand All @@ -262,13 +266,6 @@ impl ConsensusSessionOwned {
self.clone().spawn_blocking(|c| c.estimate_block_count()).await
}

/// Returns whether this consensus is considered synced or close to being synced.
///
/// This info is used to determine if it's ok to use a block template from this node for mining purposes.
pub async fn async_is_nearly_synced(&self) -> bool {
self.clone().spawn_blocking(|c| c.is_nearly_synced()).await
}

pub async fn async_get_virtual_chain_from_block(
&self,
low: Hash,
Expand Down
11 changes: 4 additions & 7 deletions consensus/core/src/api/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,10 @@ pub trait ConsensusApi: Send + Sync {
unimplemented!()
}

fn get_sink_daa_score_timestamp(&self) -> DaaScoreTimestamp {
unimplemented!()
}

fn get_current_block_color(&self, hash: Hash) -> Option<bool> {
unimplemented!()
}
Expand All @@ -151,13 +155,6 @@ pub trait ConsensusApi: Send + Sync {
unimplemented!()
}

/// Returns whether this consensus is considered synced or close to being synced.
///
/// This info is used to determine if it's ok to use a block template from this node for mining purposes.
fn is_nearly_synced(&self) -> bool {
unimplemented!()
}

/// Gets the virtual chain paths from `low` to the `sink` hash, or until `chain_path_added_limit` is reached
///
/// Note:
Expand Down
31 changes: 2 additions & 29 deletions consensus/core/src/config/params.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,7 @@ use crate::{
};
use kaspa_addresses::Prefix;
use kaspa_math::Uint256;
use std::{
cmp::min,
time::{SystemTime, UNIX_EPOCH},
};
use std::cmp::min;

#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
pub struct ForkActivation(u64);
Expand Down Expand Up @@ -136,10 +133,6 @@ pub struct Params {
pub runtime_sig_op_counting: ForkActivation,
}

fn unix_now() -> u64 {
SystemTime::now().duration_since(UNIX_EPOCH).unwrap().as_millis() as u64
}

impl Params {
/// Returns the size of the full blocks window that is inspected to calculate the past median time (legacy)
#[inline]
Expand Down Expand Up @@ -238,7 +231,7 @@ impl Params {
}
}

fn expected_daa_window_duration_in_milliseconds(&self, selected_parent_daa_score: u64) -> u64 {
pub fn expected_daa_window_duration_in_milliseconds(&self, selected_parent_daa_score: u64) -> u64 {
if self.sampling_activation.is_active(selected_parent_daa_score) {
self.target_time_per_block * self.difficulty_sample_rate * self.sampled_difficulty_window_size as u64
} else {
Expand All @@ -264,26 +257,6 @@ impl Params {
min(self.pruning_depth, anticone_finalization_depth)
}

/// Returns whether the sink timestamp is recent enough and the node is considered synced or nearly synced.
pub fn is_nearly_synced(&self, sink_timestamp: u64, sink_daa_score: u64) -> bool {
if self.net.is_mainnet() {
// We consider the node close to being synced if the sink (virtual selected parent) block
// timestamp is within DAA window duration far in the past. Blocks mined over such DAG state would
// enter the DAA window of fully-synced nodes and thus contribute to overall network difficulty
unix_now() < sink_timestamp + self.expected_daa_window_duration_in_milliseconds(sink_daa_score)
} else {
// For testnets we consider the node to be synced if the sink timestamp is within a time range which
// is overwhelmingly unlikely to pass without mined blocks even if net hashrate decreased dramatically.
//
// This period is smaller than the above mainnet calculation in order to ensure that an IBDing miner
// with significant testnet hashrate does not overwhelm the network with deep side-DAGs.
//
// We use DAA duration as baseline and scale it down with BPS (and divide by 3 for mining only when very close to current time on TN11)
let max_expected_duration_without_blocks_in_milliseconds = self.target_time_per_block * NEW_DIFFICULTY_WINDOW_DURATION / 3; // = DAA duration in milliseconds / bps / 3
unix_now() < sink_timestamp + max_expected_duration_without_blocks_in_milliseconds
}
}

pub fn network_name(&self) -> String {
self.net.to_prefixed()
}
Expand Down
13 changes: 6 additions & 7 deletions consensus/src/consensus/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -502,6 +502,12 @@ impl ConsensusApi for Consensus {
self.headers_store.get_timestamp(self.get_sink()).unwrap()
}

fn get_sink_daa_score_timestamp(&self) -> DaaScoreTimestamp {
let sink = self.get_sink();
let compact = self.headers_store.get_compact_header_data(sink).unwrap();
DaaScoreTimestamp { daa_score: compact.daa_score, timestamp: compact.timestamp }
}

fn get_current_block_color(&self, hash: Hash) -> Option<bool> {
let _guard = self.pruning_lock.blocking_read();

Expand Down Expand Up @@ -592,13 +598,6 @@ impl ConsensusApi for Consensus {
BlockCount { header_count, block_count }
}

fn is_nearly_synced(&self) -> bool {
// See comment within `config.is_nearly_synced`
let sink = self.get_sink();
let compact = self.headers_store.get_compact_header_data(sink).unwrap();
self.config.is_nearly_synced(compact.timestamp, compact.daa_score)
}

fn get_virtual_chain_from_block(&self, low: Hash, chain_path_added_limit: Option<usize>) -> ConsensusResult<ChainPath> {
// Calculate chain changes between the given `low` and the current sink hash (up to `limit` amount of block hashes).
// Note:
Expand Down
2 changes: 2 additions & 0 deletions kaspad/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@ kaspa-index-processor.workspace = true
kaspa-mining.workspace = true
kaspa-notify.workspace = true
kaspa-p2p-flows.workspace = true
kaspa-p2p-lib.workspace = true
kaspa-p2p-mining.workspace = true
kaspa-perf-monitor.workspace = true
kaspa-rpc-core.workspace = true
kaspa-rpc-service.workspace = true
Expand Down
15 changes: 15 additions & 0 deletions kaspad/src/daemon.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ use kaspa_database::{
};
use kaspa_grpc_server::service::GrpcService;
use kaspa_notify::{address::tracker::Tracker, subscription::context::SubscriptionContext};
use kaspa_p2p_lib::Hub;
use kaspa_p2p_mining::rule_engine::MiningRuleEngine;
use kaspa_rpc_service::service::RpcCoreService;
use kaspa_txscript::caches::TxScriptCacheCounters;
use kaspa_utils::git;
Expand Down Expand Up @@ -537,13 +539,23 @@ do you confirm? (answer y/n or pass --yes to the Kaspad command line to confirm
let mining_monitor =
Arc::new(MiningMonitor::new(mining_manager.clone(), mining_counters, tx_script_cache_counters.clone(), tick_service.clone()));

let hub = Hub::new();
let mining_rule_engine = Arc::new(MiningRuleEngine::new(
consensus_manager.clone(),
config.clone(),
processing_counters.clone(),
tick_service.clone(),
hub.clone(),
));
let flow_context = Arc::new(FlowContext::new(
consensus_manager.clone(),
address_manager,
config.clone(),
mining_manager.clone(),
tick_service.clone(),
notification_root,
hub.clone(),
mining_rule_engine.clone(),
));
let p2p_service = Arc::new(P2pService::new(
flow_context.clone(),
Expand Down Expand Up @@ -574,6 +586,7 @@ do you confirm? (answer y/n or pass --yes to the Kaspad command line to confirm
p2p_tower_counters.clone(),
grpc_tower_counters.clone(),
system_info,
mining_rule_engine.clone(),
));
let grpc_service_broadcasters: usize = 3; // TODO: add a command line argument or derive from other arg/config/host-related fields
let grpc_service = if !args.disable_grpc {
Expand Down Expand Up @@ -607,6 +620,8 @@ do you confirm? (answer y/n or pass --yes to the Kaspad command line to confirm
async_runtime.register(consensus_monitor);
async_runtime.register(mining_monitor);
async_runtime.register(perf_monitor);
async_runtime.register(mining_rule_engine);

let wrpc_service_tasks: usize = 2; // num_cpus::get() / 2;
// Register wRPC servers based on command line arguments
[
Expand Down
1 change: 1 addition & 0 deletions protocol/flows/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ kaspa-core.workspace = true
kaspa-consensus-core.workspace = true
kaspa-consensus-notify.workspace = true
kaspa-p2p-lib.workspace = true
kaspa-p2p-mining.workspace = true
kaspa-utils.workspace = true
kaspa-utils-tower.workspace = true
kaspa-hashes.workspace = true
Expand Down
18 changes: 14 additions & 4 deletions protocol/flows/src/flow_context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ use kaspa_consensus_notify::{
notification::{Notification, PruningPointUtxoSetOverrideNotification},
root::ConsensusNotificationRoot,
};
use kaspa_consensusmanager::{BlockProcessingBatch, ConsensusInstance, ConsensusManager, ConsensusProxy};
use kaspa_consensusmanager::{BlockProcessingBatch, ConsensusInstance, ConsensusManager, ConsensusProxy, ConsensusSessionOwned};
use kaspa_core::{
debug, info,
kaspad_env::{name, version},
Expand All @@ -35,6 +35,7 @@ use kaspa_p2p_lib::{
pb::{kaspad_message::Payload, InvRelayBlockMessage},
ConnectionInitializer, Hub, KaspadHandshake, PeerKey, PeerProperties, Router,
};
use kaspa_p2p_mining::rule_engine::MiningRuleEngine;
use kaspa_utils::iter::IterExtensions;
use kaspa_utils::networking::PeerId;
use parking_lot::{Mutex, RwLock};
Expand Down Expand Up @@ -231,6 +232,9 @@ pub struct FlowContextInner {
// Orphan parameters
orphan_resolution_range: u32,
max_orphans: usize,

// Mining rule engine
mining_rule_engine: Arc<MiningRuleEngine>,
}

#[derive(Clone)]
Expand Down Expand Up @@ -303,9 +307,9 @@ impl FlowContext {
mining_manager: MiningManagerProxy,
tick_service: Arc<TickService>,
notification_root: Arc<ConsensusNotificationRoot>,
hub: Hub,
mining_rule_engine: Arc<MiningRuleEngine>,
) -> Self {
let hub = Hub::new();

let orphan_resolution_range = BASELINE_ORPHAN_RESOLUTION_RANGE + (config.bps() as f64).log2().ceil() as u32;

// The maximum amount of orphans allowed in the orphans pool. This number is an approximation
Expand All @@ -331,6 +335,7 @@ impl FlowContext {
orphan_resolution_range,
max_orphans,
config,
mining_rule_engine,
}),
}
}
Expand Down Expand Up @@ -556,7 +561,7 @@ impl FlowContext {
}

// Transaction relay is disabled if the node is out of sync and thus not mining
if !consensus.async_is_nearly_synced().await {
if !self.is_nearly_synced(consensus).await {
return;
}

Expand Down Expand Up @@ -595,6 +600,11 @@ impl FlowContext {
}
}

pub async fn is_nearly_synced(&self, session: &ConsensusSessionOwned) -> bool {
let sink_daa_score_and_timestamp = session.async_get_sink_daa_score_timestamp().await;
self.mining_rule_engine.is_nearly_synced(sink_daa_score_and_timestamp)
}

/// Notifies that the UTXO set was reset due to pruning point change via IBD.
pub fn on_pruning_point_utxoset_override(&self) {
// Notifications from the flow context might be ignored if the inner channel is already closing
Expand Down
2 changes: 1 addition & 1 deletion protocol/flows/src/v5/blockrelay/flow.rs
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,7 @@ impl HandleRelayInvsFlow {
}
}

if self.ctx.is_ibd_running() && !session.async_is_nearly_synced().await {
if self.ctx.is_ibd_running() && !self.ctx.is_nearly_synced(&session).await {
// Note: If the node is considered nearly synced we continue processing relay blocks even though an IBD is in progress.
// For instance this means that downloading a side-chain from a delayed node does not interop the normal flow of live blocks.
debug!("Got relay block {} while in IBD and the node is out of sync, continuing...", inv.hash);
Expand Down
2 changes: 1 addition & 1 deletion protocol/flows/src/v5/txrelay/flow.rs
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,7 @@ impl RelayTransactionsFlow {
let session = self.ctx.consensus().unguarded_session();

// Transaction relay is disabled if the node is out of sync and thus not mining
if !session.async_is_nearly_synced().await {
if !self.ctx.is_nearly_synced(&session).await {
continue;
}

Expand Down
23 changes: 23 additions & 0 deletions protocol/mining/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
[package]
name = "kaspa-p2p-mining"
description = "Kaspa p2p mining"
rust-version.workspace = true
version.workspace = true
edition.workspace = true
authors.workspace = true
include.workspace = true
license.workspace = true
repository.workspace = true

[dependencies]
kaspa-core.workspace = true
kaspa-consensus-core.workspace = true
kaspa-consensusmanager.workspace = true
kaspa-mining-errors.workspace = true
kaspa-hashes.workspace = true
kaspa-math.workspace = true
kaspa-p2p-lib.workspace = true
kaspa-utils.workspace = true
kaspa-utils-tower.workspace = true
log.workspace = true
tokio.workspace = true
1 change: 1 addition & 0 deletions protocol/mining/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
pub mod rule_engine;
Loading
Loading