Skip to content
Merged
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
30 changes: 30 additions & 0 deletions dash-spv/src/client/event_handler.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,36 @@ pub trait EventHandler: Send + Sync + 'static {
/// No-op implementation for consumers that don't need event notifications.
impl EventHandler for () {}

/// Built-in handler that mirrors all events into `tracing` so consumers get
/// log output once they install a tracing subscriber (e.g., via `init_logging`).
///
/// Attached automatically by `DashSpvClient::new` ahead of consumer-supplied
/// handlers. To silence event logs without affecting other subscribers, set a
/// per-target filter such as `dash_spv::client::event_handler=warn`.
pub(crate) struct LoggingEventHandler;

impl EventHandler for LoggingEventHandler {
fn on_sync_event(&self, event: &SyncEvent) {
tracing::info!("SyncEvent: {}", event.description());
}

fn on_network_event(&self, event: &NetworkEvent) {
tracing::info!("NetworkEvent: {}", event.description());
}

fn on_progress(&self, progress: &SyncProgress) {
tracing::info!("SyncProgress: {}", progress);
}

fn on_wallet_event(&self, event: &WalletEvent) {
tracing::info!("WalletEvent: {}", event.description());
}

fn on_error(&self, error: &str) {
tracing::error!("{}", error);
}
}

/// Spawns a task that monitors a broadcast channel and dispatches events to the handler.
///
/// On failure, the error message is sent via `on_failure` so the coordinator can report
Expand Down
5 changes: 5 additions & 0 deletions dash-spv/src/client/lifecycle.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
//! - Genesis block initialization
//! - Wallet data loading

use super::event_handler::LoggingEventHandler;
use super::{ClientConfig, DashSpvClient, EventHandler};
use crate::chain::checkpoints::{mainnet_checkpoints, testnet_checkpoints, CheckpointManager};
use crate::error::{Result, SpvError};
Expand Down Expand Up @@ -36,6 +37,10 @@ impl<W: WalletInterface, N: NetworkManager, S: StorageManager> DashSpvClient<W,
wallet: Arc<RwLock<W>>,
event_handlers: Vec<Arc<dyn EventHandler>>,
) -> Result<Self> {
let event_handlers: Vec<Arc<dyn EventHandler>> =
std::iter::once(Arc::new(LoggingEventHandler) as Arc<dyn EventHandler>)
.chain(event_handlers)
.collect();
Comment thread
QuantumExplorer marked this conversation as resolved.
// Validate configuration
config.validate().map_err(SpvError::Config)?;

Expand Down
24 changes: 24 additions & 0 deletions dash-spv/src/client/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -76,4 +76,28 @@ mod tests {
let wallet_ref = client.wallet();
let _wallet_guard = wallet_ref.read().await;
}

#[tokio::test]
async fn client_attaches_builtin_logging_handler() {
let config = ClientConfig::mainnet()
.without_filters()
.without_masternodes()
.with_mempool_tracking(MempoolStrategy::FetchAll)
.with_storage_path(TempDir::new().unwrap().path());

let network_manager = MockNetworkManager::new();
let storage =
DiskStorageManager::with_temp_dir().await.expect("Failed to create tmp storage");
let wallet = Arc::new(RwLock::new(WalletManager::<ManagedWalletInfo>::new(config.network)));

let client = DashSpvClient::new(config, network_manager, storage, wallet, Vec::new())
.await
.expect("client construction must succeed");

assert_eq!(
client.event_handlers.len(),
1,
"constructor should auto-attach the built-in logging handler",
);
}
}
66 changes: 18 additions & 48 deletions dash-spv/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,9 @@ use std::process;
use std::sync::Arc;

use clap::{Parser, ValueEnum};
use dash_spv::network::NetworkEvent;
use dash_spv::sync::{SyncEvent, SyncProgress};
use dash_spv::{ClientConfig, DashSpvClient, EventHandler, LevelFilter, MempoolStrategy, Network};
use dash_spv::{ClientConfig, DashSpvClient, LevelFilter, MempoolStrategy, Network};
use key_wallet::wallet::managed_wallet_info::ManagedWalletInfo;
use key_wallet_manager::{WalletEvent, WalletManager};
use key_wallet_manager::WalletManager;
use tokio_util::sync::CancellationToken;

/// Network selection for CLI
Expand Down Expand Up @@ -71,31 +69,6 @@ impl From<LogLevelArg> for LevelFilter {
}
}

/// Logs all SPV client events via tracing.
struct LoggingEventHandler;

impl EventHandler for LoggingEventHandler {
fn on_sync_event(&self, event: &SyncEvent) {
tracing::info!("{}", event.description());
}

fn on_network_event(&self, event: &NetworkEvent) {
tracing::info!("{}", event.description());
}

fn on_progress(&self, progress: &SyncProgress) {
tracing::info!("Sync progress: {}", progress);
}

fn on_wallet_event(&self, event: &WalletEvent) {
tracing::info!("Wallet: {}", event.description());
}

fn on_error(&self, error: &str) {
tracing::error!("{}", error);
}
}

/// Dash SPV (Simplified Payment Verification) client
#[derive(Parser, Debug)]
#[command(name = "dash-spv", version = dash_spv::VERSION, about)]
Expand Down Expand Up @@ -326,25 +299,22 @@ async fn run_client<S: dash_spv::storage::StorageManager>(
wallet: Arc<tokio::sync::RwLock<WalletManager<ManagedWalletInfo>>>,
) -> Result<(), Box<dyn std::error::Error>> {
// Create and start the client
let client = match DashSpvClient::<
WalletManager<ManagedWalletInfo>,
dash_spv::network::manager::PeerNetworkManager,
S,
>::new(
config.clone(),
network_manager,
storage_manager,
wallet.clone(),
vec![Arc::new(LoggingEventHandler)],
)
.await
{
Ok(client) => client,
Err(e) => {
eprintln!("Failed to create SPV client: {}", e);
process::exit(1);
}
};
let client =
match DashSpvClient::<
WalletManager<ManagedWalletInfo>,
dash_spv::network::manager::PeerNetworkManager,
S,
>::new(
config.clone(), network_manager, storage_manager, wallet.clone(), Vec::new()
)
.await
{
Ok(client) => client,
Err(e) => {
eprintln!("Failed to create SPV client: {}", e);
process::exit(1);
}
};

let shutdown_token = CancellationToken::new();
let ctrl_c_token = shutdown_token.clone();
Expand Down
Loading