diff --git a/script/research/minerd/src/error.rs b/script/research/minerd/src/error.rs index 91e3ba08a..068baf3e8 100644 --- a/script/research/minerd/src/error.rs +++ b/script/research/minerd/src/error.rs @@ -28,6 +28,7 @@ pub enum RpcError { // Miner errors MiningFailed = -32201, HashingFailed = -32202, + StopFailed = -32203, } fn to_tuple(e: RpcError) -> (i32, String) { @@ -38,6 +39,7 @@ fn to_tuple(e: RpcError) -> (i32, String) { // Miner errors RpcError::MiningFailed => "Mining block failed", RpcError::HashingFailed => "Hashing block failed", + RpcError::StopFailed => "Failed to stop previous request", }; (e as i32, msg.to_string()) diff --git a/script/research/minerd/src/main.rs b/script/research/minerd/src/main.rs index 71ac2e373..25fd009ec 100644 --- a/script/research/minerd/src/main.rs +++ b/script/research/minerd/src/main.rs @@ -19,7 +19,12 @@ use std::{collections::HashSet, sync::Arc}; use log::{error, info}; -use smol::{channel::Receiver, lock::Mutex, stream::StreamExt, Executor}; +use smol::{ + channel::{Receiver, Sender}, + lock::Mutex, + stream::StreamExt, + Executor, +}; use structopt_toml::{serde::Deserialize, structopt::StructOpt, StructOptToml}; use url::Url; @@ -68,6 +73,8 @@ struct Args { pub struct Minerd { /// PoW miner number of threads to use threads: usize, + // Sender to stop miner threads + sender: Sender<()>, // Receiver to stop miner threads stop_signal: Receiver<()>, /// JSON-RPC connection tracker @@ -75,8 +82,8 @@ pub struct Minerd { } impl Minerd { - pub fn new(threads: usize, stop_signal: Receiver<()>) -> Self { - Self { threads, stop_signal, rpc_connections: Mutex::new(HashSet::new()) } + pub fn new(threads: usize, sender: Sender<()>, stop_signal: Receiver<()>) -> Self { + Self { threads, sender, stop_signal, rpc_connections: Mutex::new(HashSet::new()) } } } @@ -84,7 +91,7 @@ async_daemonize!(realmain); async fn realmain(args: Args, ex: Arc>) -> Result<()> { info!(target: "minerd", "Starting DarkFi Mining Daemon..."); let (sender, recvr) = smol::channel::bounded(1); - let minerd = Arc::new(Minerd::new(args.threads, recvr)); + let minerd = Arc::new(Minerd::new(args.threads, sender.clone(), recvr)); info!(target: "minerd", "Starting JSON-RPC server on {}", args.rpc_listen); let minerd_ = Arc::clone(&minerd); diff --git a/script/research/minerd/src/rpc.rs b/script/research/minerd/src/rpc.rs index 961a80cc3..6e1a42b04 100644 --- a/script/research/minerd/src/rpc.rs +++ b/script/research/minerd/src/rpc.rs @@ -29,7 +29,7 @@ use darkfi::{ server::RequestHandler, util::JsonValue, }, - system::StoppableTaskPtr, + system::{sleep, StoppableTaskPtr}, util::encoding::base64, validator::pow::mine_block, }; @@ -88,13 +88,36 @@ impl Minerd { return server_error(RpcError::BlockParseError, id, None) }; + // Check if another request is being processed + if self.stop_signal.receiver_count() > 1 { + info!(target: "minerd::rpc", "Another request is in progress, sending stop signal..."); + // Send stop signal to other worker + if self.sender.send(()).await.is_err() { + error!(target: "minerd::rpc", "Failed to stop previous request"); + return server_error(RpcError::StopFailed, id, None) + } + + // Wait for other worker to terminate + info!(target: "minerd::rpc", "Waiting for request to terminate..."); + while self.stop_signal.receiver_count() > 1 { + sleep(1).await; + } + info!(target: "minerd::rpc", "Previous request terminated!"); + + // Consume channel item so its empty again + if self.stop_signal.recv().await.is_err() { + error!(target: "minerd::rpc", "Failed to cleanup stop signal channel"); + return server_error(RpcError::StopFailed, id, None) + } + } + // Mine provided block let Ok(block_hash) = block.hash() else { error!(target: "minerd::rpc", "Failed to hash block"); return server_error(RpcError::HashingFailed, id, None) }; info!(target: "minerd::rpc", "Mining block {} for target: {}", block_hash, target); - if let Err(e) = mine_block(&target, &mut block, self.threads, &self.stop_signal) { + if let Err(e) = mine_block(&target, &mut block, self.threads, &self.stop_signal.clone()) { error!(target: "minerd::rpc", "Failed mining block {} with error: {}", block_hash, e); return server_error(RpcError::MiningFailed, id, None) }