diff --git a/.gitignore b/.gitignore index 363d497ac..d0672e4ed 100644 --- a/.gitignore +++ b/.gitignore @@ -20,6 +20,7 @@ /dhtd /darkfid /darkfid2 +/darkfi-mmproxy /darkotc /dnetview /drk diff --git a/Cargo.lock b/Cargo.lock index b07017ee5..a8a71ca2d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1596,6 +1596,24 @@ dependencies = [ "syn 2.0.29", ] +[[package]] +name = "darkfi-mmproxy" +version = "0.4.1" +dependencies = [ + "darkfi", + "darkfi-serial", + "easy-parallel", + "log", + "serde", + "signal-hook", + "signal-hook-async-std", + "simplelog", + "smol", + "structopt", + "structopt-toml", + "url", +] + [[package]] name = "darkfi-money-contract" version = "0.4.1" diff --git a/Cargo.toml b/Cargo.toml index db45004be..1ef44782d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -22,6 +22,7 @@ members = [ "bin/zkas", "bin/darkfid", "bin/darkfid2", + "bin/darkfi-mmproxy", #"bin/drk", "bin/faucetd", #"bin/fud/fu", diff --git a/bin/darkfi-mmproxy/Cargo.toml b/bin/darkfi-mmproxy/Cargo.toml new file mode 100644 index 000000000..3fb024e40 --- /dev/null +++ b/bin/darkfi-mmproxy/Cargo.toml @@ -0,0 +1,31 @@ +[package] +name = "darkfi-mmproxy" +version = "0.4.1" +homepage = "https://dark.fi" +description = "Proxy server for DarkFi/Monero merge mining" +authors = ["Dyne.org foundation "] +repository = "https://github.com/darkrenaissance/darkfi" +license = "AGPL-3.0-only" +edition = "2021" + +[dependencies] +darkfi = {path = "../../", features = ["async-daemonize", "async-serial", "system", "util", "rpc"]} +darkfi-serial = {path = "../../src/serial", features = ["async"]} + +# Misc +log = "0.4.20" + +# Encoding +url = "2.4.1" + +# Daemon +easy-parallel = "3.3.0" +signal-hook-async-std = "0.2.2" +signal-hook = "0.3.17" +simplelog = "0.12.1" +smol = "1.3.0" + +# Argument parsing +serde = {version = "1.0.188", features = ["derive"]} +structopt = "0.3.26" +structopt-toml = "0.5.1" diff --git a/bin/darkfi-mmproxy/Makefile b/bin/darkfi-mmproxy/Makefile new file mode 100644 index 000000000..55f20c74f --- /dev/null +++ b/bin/darkfi-mmproxy/Makefile @@ -0,0 +1,34 @@ +.POSIX: + +# Install prefix +PREFIX = $(HOME)/.cargo + +# Cargo binary +CARGO = cargo +nightly + +SRC = \ + Cargo.toml \ + ../../Cargo.toml \ + $(shell find src -type f) \ + $(shell find ../../src -type f) \ + +BIN = ../../darkfi-mmproxy + +all: $(BIN) + +$(BIN): $(SRC) + $(CARGO) build $(TARGET_PRFX)$(RUST_TARGET) --release --package darkfi-mmproxy + cp -f ../../target/$(RUST_TARGET)/release/darkfi-mmproxy $@ + +clean: + rm -f $(BIN) + +install: all + mkdir -p $(DESTDIR)$(PREFIX)/bin + cp -f $(BIN) $(DESTDIR)$(PREFIX)/bin + chmod 755 $(DESTDIR)$(PREFIX)/bin/darkfi-mmproxy + +uninstall: + rm -f $(DESTDIR)$(PREFIX)/bin/darkfi-mmproxy + +.PHONY: all clean install uninstall diff --git a/bin/darkfi-mmproxy/darkfi_mmproxy.toml b/bin/darkfi-mmproxy/darkfi_mmproxy.toml new file mode 100644 index 000000000..e69de29bb diff --git a/bin/darkfi-mmproxy/src/main.rs b/bin/darkfi-mmproxy/src/main.rs new file mode 100644 index 000000000..24ce52925 --- /dev/null +++ b/bin/darkfi-mmproxy/src/main.rs @@ -0,0 +1,101 @@ +use std::{collections::HashSet, sync::Arc}; + +use darkfi::{ + async_daemonize, cli_desc, + rpc::{ + jsonrpc::{ErrorCode, JsonError, JsonRequest, JsonResult}, + server::{listen_and_serve, RequestHandler}, + }, + system::{StoppableTask, StoppableTaskPtr}, + Error, Result, +}; +use darkfi_serial::async_trait; +use log::{debug, error, info}; +use serde::Deserialize; +use smol::{ + lock::{Mutex, MutexGuard}, + stream::StreamExt, + Executor, +}; +use structopt::StructOpt; +use structopt_toml::StructOptToml; +use url::Url; + +mod stratum; + +const CONFIG_FILE: &str = "darkfi_mmproxy.toml"; +const CONFIG_FILE_CONTENTS: &str = include_str!("../darkfi_mmproxy.toml"); + +#[derive(Clone, Debug, Deserialize, StructOpt, StructOptToml)] +#[serde(default)] +#[structopt(name = "darkfi-mmproxy", about = cli_desc!())] +struct Args { + #[structopt(short, parse(from_occurrences))] + /// Increase verbosity (-vvv supported) + verbose: u8, + + #[structopt(short, long)] + /// Configuration file to use + config: Option, + + #[structopt(long, default_value = "tcp://127.0.0.1:3333")] + /// JSON-RPC server listen URL + rpc_listen: Url, + + #[structopt(long)] + /// Set log file output + log: Option, +} + +struct MiningProxy { + /// JSON-RPC connection tracker + rpc_connections: Mutex>, +} + +impl MiningProxy { + fn new() -> Self { + Self { rpc_connections: Mutex::new(HashSet::new()) } + } +} + +#[async_trait] +impl RequestHandler for MiningProxy { + async fn handle_request(&self, req: JsonRequest) -> JsonResult { + error!(target: "mmproxy::rpc", "--> {}", req.stringify().unwrap()); + + match req.method.as_str() { + "ping" => self.pong(req.id, req.params).await, + _ => JsonError::new(ErrorCode::MethodNotFound, None, req.id).into(), + } + } + + async fn connections_mut(&self) -> MutexGuard<'_, HashSet> { + self.rpc_connections.lock().await + } +} + +async_daemonize!(realmain); +async fn realmain(args: Args, ex: Arc>) -> Result<()> { + info!("Starting JSON-RPC server"); + let mmproxy = Arc::new(MiningProxy::new()); + let mmproxy_ = Arc::clone(&mmproxy); + let rpc_task = StoppableTask::new(); + rpc_task.clone().start( + listen_and_serve(args.rpc_listen, mmproxy.clone(), None, ex.clone()), + |res| async move { + match res { + Ok(()) | Err(Error::RpcServerStopped) => mmproxy_.stop_connections().await, + Err(e) => error!("Failed stopping JSON-RPC server: {}", e), + } + }, + Error::RpcServerStopped, + ex.clone(), + ); + + // Signal handling for graceful termination. + let (signals_handler, signals_task) = SignalHandler::new(ex)?; + signals_handler.wait_termination(signals_task).await?; + info!("Caught termination signal, cleaning up and exiting..."); + + Ok(()) +} diff --git a/bin/darkfi-mmproxy/src/stratum.rs b/bin/darkfi-mmproxy/src/stratum.rs new file mode 100644 index 000000000..1e1c346d1 --- /dev/null +++ b/bin/darkfi-mmproxy/src/stratum.rs @@ -0,0 +1,3 @@ +use super::MiningProxy; + +impl MiningProxy {}