فهرست منبع

darkfid: introduce a second rpc handler for mm http requests

skoupidi 1 سال پیش
والد
کامیت
44db85b2f3

+ 9 - 0
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
 

+ 41 - 20
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<Self> {
-        let client = RpcChadClient::new(endpoint.clone(), ex.clone()).await?;
-        Ok(Self { endpoint, ex, client })
-    }
-}
-
 /// Atomic pointer to the DarkFi node
 pub type DarkfiNodePtr = Arc<DarkfiNode>;
 
@@ -88,6 +73,8 @@ pub struct DarkfiNode {
     rpc_connections: Mutex<HashSet<StoppableTaskPtr>>,
     /// JSON-RPC client to execute requests to the miner daemon
     rpc_client: Option<Mutex<MinerRpcClient>>,
+    /// HTTP JSON-RPC connection tracker
+    mm_rpc_connections: Mutex<HashSet<StoppableTaskPtr>>,
 }
 
 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<Url>,
         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::<DefaultRpcHandler>(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) => <DarkfiNode as RequestHandler<DefaultRpcHandler>>::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::<MmRpcHandler>(url.clone(), self.node.clone(), None, executor.clone()),
+                |res| async move {
+                    match res {
+                        Ok(()) | Err(Error::RpcServerStopped) => <DarkfiNode as RequestHandler<MmRpcHandler>>::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!");

+ 7 - 1
bin/darkfid/src/main.rs

@@ -94,6 +94,10 @@ pub struct BlockchainNetwork {
     /// minerd JSON-RPC endpoint
     minerd_endpoint: Option<Url>,
 
+    #[structopt(long)]
+    /// Optional HTTP JSON-RPC listen URL to serve handlers for p2pool merge mining requests
+    mm_rpc_listen: Option<Url>,
+
     #[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<smol::Executor<'static>>) -> 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)?;

+ 54 - 3
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<Self> {
+        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<DefaultRpcHandler> 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" => <DarkfiNode as RequestHandler<DefaultRpcHandler>>::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<MmRpcHandler> 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" => <DarkfiNode as RequestHandler<MmRpcHandler>>::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<StoppableTaskPtr>> {
+        self.mm_rpc_connections.lock().await
+    }
+}
+
 impl DarkfiNode {
     // RPCAPI:
     // Returns current system clock as `u64` (String) timestamp.

+ 2 - 2
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();

+ 3 - 0
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