From 44db85b2f3ffe579e9ddb64f1bd2edba2123a054 Mon Sep 17 00:00:00 2001 From: skoupidi Date: Thu, 5 Dec 2024 17:27:58 +0200 Subject: [PATCH] darkfid: introduce a second rpc handler for mm http requests --- bin/darkfid/darkfid_config.toml | 9 +++ bin/darkfid/src/lib.rs | 61 +++++++++++++------ bin/darkfid/src/main.rs | 8 ++- bin/darkfid/src/rpc.rs | 57 ++++++++++++++++- bin/darkfid/src/tests/mod.rs | 4 +- .../localnet/darkfid-single-node/darkfid.toml | 3 + 6 files changed, 116 insertions(+), 26 deletions(-) diff --git a/bin/darkfid/darkfid_config.toml b/bin/darkfid/darkfid_config.toml index b9c0f7854..56be710a9 100644 --- a/bin/darkfid/darkfid_config.toml +++ b/bin/darkfid/darkfid_config.toml @@ -23,6 +23,9 @@ threshold = 3 # minerd JSON-RPC endpoint minerd_endpoint = "tcp://127.0.0.1:28467" +# Optional HTTP JSON-RPC listen URL to serve handlers for p2pool merge mining requests +#mm_rpc_listen = "http+tcp://127.0.0.1:8241" + # PoW block production target, in seconds pow_target = 10 @@ -129,6 +132,9 @@ threshold = 6 # minerd JSON-RPC endpoint #minerd_endpoint = "tcp://127.0.0.1:28467" +# Optional HTTP JSON-RPC listen URL to serve handlers for p2pool merge mining requests +#mm_rpc_listen = "http+tcp://127.0.0.1:8241" + # PoW block production target, in seconds pow_target = 90 @@ -234,6 +240,9 @@ threshold = 11 # minerd JSON-RPC endpoint #minerd_endpoint = "tcp://127.0.0.1:28467" +# Optional HTTP JSON-RPC listen URL to serve handlers for p2pool merge mining requests +#mm_rpc_listen = "http+tcp://127.0.0.1:8241" + # PoW block production target, in seconds pow_target = 90 diff --git a/bin/darkfid/src/lib.rs b/bin/darkfid/src/lib.rs index ddb2e78fb..994936d71 100644 --- a/bin/darkfid/src/lib.rs +++ b/bin/darkfid/src/lib.rs @@ -28,7 +28,6 @@ use url::Url; use darkfi::{ net::settings::Settings, rpc::{ - client::RpcChadClient, jsonrpc::JsonSubscriber, server::{listen_and_serve, RequestHandler}, }, @@ -45,6 +44,7 @@ use error::{server_error, RpcError}; /// JSON-RPC requests handler and methods mod rpc; +use rpc::{DefaultRpcHandler, MinerRpcClient, MmRpcHandler}; mod rpc_blockchain; mod rpc_tx; @@ -56,21 +56,6 @@ use task::{consensus::ConsensusInitTaskConfig, consensus_init_task}; mod proto; use proto::{DarkfidP2pHandler, DarkfidP2pHandlerPtr}; -/// Structure to hold a JSON-RPC client and its config, -/// so we can recreate it in case of an error. -pub struct MinerRpcClient { - endpoint: Url, - ex: ExecutorPtr, - client: RpcChadClient, -} - -impl MinerRpcClient { - pub async fn new(endpoint: Url, ex: ExecutorPtr) -> Result { - let client = RpcChadClient::new(endpoint.clone(), ex.clone()).await?; - Ok(Self { endpoint, ex, client }) - } -} - /// Atomic pointer to the DarkFi node pub type DarkfiNodePtr = Arc; @@ -88,6 +73,8 @@ pub struct DarkfiNode { rpc_connections: Mutex>, /// JSON-RPC client to execute requests to the miner daemon rpc_client: Option>, + /// HTTP JSON-RPC connection tracker + mm_rpc_connections: Mutex>, } impl DarkfiNode { @@ -105,6 +92,7 @@ impl DarkfiNode { subscribers, rpc_connections: Mutex::new(HashSet::new()), rpc_client, + mm_rpc_connections: Mutex::new(HashSet::new()), }) } } @@ -120,6 +108,8 @@ pub struct Darkfid { dnet_task: StoppableTaskPtr, /// JSON-RPC background task rpc_task: StoppableTaskPtr, + /// HTTP JSON-RPC background task + mm_rpc_task: StoppableTaskPtr, /// Consensus protocol background task consensus_task: StoppableTaskPtr, } @@ -182,11 +172,12 @@ impl Darkfid { // Generate the background tasks let dnet_task = StoppableTask::new(); let rpc_task = StoppableTask::new(); + let mm_rpc_task = StoppableTask::new(); let consensus_task = StoppableTask::new(); info!(target: "darkfid::Darkfid::init", "Darkfi daemon initialized successfully!"); - Ok(Arc::new(Self { node, dnet_task, rpc_task, consensus_task })) + Ok(Arc::new(Self { node, dnet_task, rpc_task, mm_rpc_task, consensus_task })) } /// Start the DarkFi daemon in the given executor, using the provided JSON-RPC listen url @@ -195,6 +186,7 @@ impl Darkfid { &self, executor: &ExecutorPtr, rpc_listen: &Url, + mm_rpc_listen: &Option, config: &ConsensusInitTaskConfig, ) -> Result<()> { info!(target: "darkfid::Darkfid::start", "Starting Darkfi daemon..."); @@ -234,10 +226,10 @@ impl Darkfid { info!(target: "darkfid::Darkfid::start", "Starting JSON-RPC server"); let node_ = self.node.clone(); self.rpc_task.clone().start( - listen_and_serve(rpc_listen.clone(), self.node.clone(), None, executor.clone()), + listen_and_serve::(rpc_listen.clone(), self.node.clone(), None, executor.clone()), |res| async move { match res { - Ok(()) | Err(Error::RpcServerStopped) => node_.stop_connections().await, + Ok(()) | Err(Error::RpcServerStopped) => >::stop_connections(&node_).await, Err(e) => error!(target: "darkfid::Darkfid::start", "Failed starting JSON-RPC server: {}", e), } }, @@ -245,6 +237,31 @@ impl Darkfid { executor.clone(), ); + // Start the HTTP JSON-RPC task + if let Some(url) = mm_rpc_listen { + info!(target: "darkfid::Darkfid::start", "Starting HTTP JSON-RPC server"); + let node_ = self.node.clone(); + self.mm_rpc_task.clone().start( + listen_and_serve::(url.clone(), self.node.clone(), None, executor.clone()), + |res| async move { + match res { + Ok(()) | Err(Error::RpcServerStopped) => >::stop_connections(&node_).await, + Err(e) => error!(target: "darkfid::Darkfid::start", "Failed starting HTTP JSON-RPC server: {}", e), + } + }, + Error::RpcServerStopped, + executor.clone(), + ); + } else { + // Create a dummy task + self.mm_rpc_task.clone().start( + async { Ok(()) }, + |_| async { /* Do nothing */ }, + Error::RpcServerStopped, + executor.clone(), + ); + } + // Start the P2P network info!(target: "darkfid::Darkfid::start", "Starting P2P network"); self.node @@ -287,6 +304,10 @@ impl Darkfid { info!(target: "darkfid::Darkfid::stop", "Stopping JSON-RPC server..."); self.rpc_task.stop().await; + // Stop the HTTP JSON-RPC task + info!(target: "darkfid::Darkfid::stop", "Stopping HTTP JSON-RPC server..."); + self.rpc_task.stop().await; + // Stop the P2P network info!(target: "darkfid::Darkfid::stop", "Stopping P2P network protocols handler..."); self.node.p2p_handler.stop().await; @@ -303,7 +324,7 @@ impl Darkfid { // Close the JSON-RPC client, if it was initialized if let Some(ref rpc_client) = self.node.rpc_client { info!(target: "darkfid::Darkfid::stop", "Stopping JSON-RPC client..."); - rpc_client.lock().await.client.stop().await; + rpc_client.lock().await.stop().await; }; info!(target: "darkfid::Darkfid::stop", "Darkfi daemon terminated successfully!"); diff --git a/bin/darkfid/src/main.rs b/bin/darkfid/src/main.rs index 8a4d1892c..cc9055a59 100644 --- a/bin/darkfid/src/main.rs +++ b/bin/darkfid/src/main.rs @@ -94,6 +94,10 @@ pub struct BlockchainNetwork { /// minerd JSON-RPC endpoint minerd_endpoint: Option, + #[structopt(long)] + /// Optional HTTP JSON-RPC listen URL to serve handlers for p2pool merge mining requests + mm_rpc_listen: Option, + #[structopt(long, default_value = "10")] /// PoW block production target, in seconds pow_target: u32, @@ -225,7 +229,9 @@ async fn realmain(args: Args, ex: Arc>) -> Result<()> { user_data: blockchain_config.user_data, bootstrap, }; - daemon.start(&ex, &blockchain_config.rpc_listen, &config).await?; + daemon + .start(&ex, &blockchain_config.rpc_listen, &blockchain_config.mm_rpc_listen, &config) + .await?; // Signal handling for graceful termination. let (signals_handler, signals_task) = SignalHandler::new(ex)?; diff --git a/bin/darkfid/src/rpc.rs b/bin/darkfid/src/rpc.rs index 7bd92f525..874935e53 100644 --- a/bin/darkfid/src/rpc.rs +++ b/bin/darkfid/src/rpc.rs @@ -22,6 +22,7 @@ use async_trait::async_trait; use log::{debug, error, info}; use smol::lock::MutexGuard; use tinyjson::JsonValue; +use url::Url; use darkfi::{ net::P2pPtr, @@ -31,7 +32,7 @@ use darkfi::{ p2p_method::HandlerP2p, server::RequestHandler, }, - system::{sleep, StoppableTaskPtr}, + system::{sleep, ExecutorPtr, StoppableTaskPtr}, util::time::Timestamp, Error, Result, }; @@ -41,9 +42,34 @@ use crate::{ DarkfiNode, }; +/// Default JSON-RPC `RequestHandler` type +pub struct DefaultRpcHandler; +/// HTTP JSON-RPC `RequestHandler` type for p2pool +pub struct MmRpcHandler; + +/// Structure to hold a JSON-RPC client and its config, +/// so we can recreate it in case of an error. +pub struct MinerRpcClient { + endpoint: Url, + ex: ExecutorPtr, + client: RpcChadClient, +} + +impl MinerRpcClient { + pub async fn new(endpoint: Url, ex: ExecutorPtr) -> Result { + let client = RpcChadClient::new(endpoint.clone(), ex.clone()).await?; + Ok(Self { endpoint, ex, client }) + } + + /// Stop the client. + pub async fn stop(&self) { + self.client.stop().await + } +} + #[async_trait] #[rustfmt::skip] -impl RequestHandler<()> for DarkfiNode { +impl RequestHandler for DarkfiNode { async fn handle_request(&self, req: JsonRequest) -> JsonResult { debug!(target: "darkfid::rpc", "--> {}", req.stringify().unwrap()); @@ -51,7 +77,7 @@ impl RequestHandler<()> for DarkfiNode { // ===================== // Miscellaneous methods // ===================== - "ping" => self.pong(req.id, req.params).await, + "ping" => >::pong(self, req.id, req.params).await, "clock" => self.clock(req.id, req.params).await, "ping_miner" => self.ping_miner(req.id, req.params).await, "dnet.switch" => self.dnet_switch(req.id, req.params).await, @@ -94,6 +120,31 @@ impl RequestHandler<()> for DarkfiNode { } } +#[async_trait] +#[rustfmt::skip] +impl RequestHandler for DarkfiNode { + async fn handle_request(&self, req: JsonRequest) -> JsonResult { + debug!(target: "darkfid::mm_rpc", "--> {}", req.stringify().unwrap()); + + match req.method.as_str() { + // ===================== + // Miscellaneous methods + // ===================== + "ping" => >::pong(self, req.id, req.params).await, + "clock" => self.clock(req.id, req.params).await, + + // ============== + // Invalid method + // ============== + _ => JsonError::new(ErrorCode::MethodNotFound, None, req.id).into(), + } + } + + async fn connections_mut(&self) -> MutexGuard<'life0, HashSet> { + self.mm_rpc_connections.lock().await + } +} + impl DarkfiNode { // RPCAPI: // Returns current system clock as `u64` (String) timestamp. diff --git a/bin/darkfid/src/tests/mod.rs b/bin/darkfid/src/tests/mod.rs index 544b6687f..9648af978 100644 --- a/bin/darkfid/src/tests/mod.rs +++ b/bin/darkfid/src/tests/mod.rs @@ -271,13 +271,13 @@ fn darkfid_programmatic_control() -> Result<()> { .unwrap(); // Start it - daemon.start(&ex, &rpc_listen, &consensus_config).await.unwrap(); + daemon.start(&ex, &rpc_listen, &None, &consensus_config).await.unwrap(); // Stop it daemon.stop().await.unwrap(); // Start it again - daemon.start(&ex, &rpc_listen, &consensus_config).await.unwrap(); + daemon.start(&ex, &rpc_listen, &None, &consensus_config).await.unwrap(); // Stop it daemon.stop().await.unwrap(); diff --git a/contrib/localnet/darkfid-single-node/darkfid.toml b/contrib/localnet/darkfid-single-node/darkfid.toml index 6d07ddafe..51ccc459c 100644 --- a/contrib/localnet/darkfid-single-node/darkfid.toml +++ b/contrib/localnet/darkfid-single-node/darkfid.toml @@ -23,6 +23,9 @@ threshold = 1 # minerd JSON-RPC endpoint minerd_endpoint = "tcp://127.0.0.1:48467" +# Optional HTTP JSON-RPC listen URL to serve handlers for p2pool merge mining requests +#mm_rpc_listen = "http+tcp://127.0.0.1:8241" + # PoW block production target, in seconds pow_target = 10