darkfid: introduce a second rpc handler for mm http requests

This commit is contained in:
skoupidi
2024-12-05 17:27:58 +02:00
parent bc22307e8b
commit 44db85b2f3
6 changed files with 116 additions and 26 deletions

View File

@@ -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

View File

@@ -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!");

View File

@@ -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)?;

View File

@@ -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.

View File

@@ -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();

View File

@@ -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