Skip to content

Commit

Permalink
mmproxy: Stratum login WIP
Browse files Browse the repository at this point in the history
  • Loading branch information
parazyd committed Oct 18, 2023
1 parent 5f053ac commit 4c10ee8
Show file tree
Hide file tree
Showing 5 changed files with 98 additions and 5 deletions.
4 changes: 4 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions bin/darkfi-mmproxy/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ log = "0.4.20"

# Encoding
url = "2.4.1"
uuid = {version = "1.4.1", features = ["v4"]}

# Daemon
easy-parallel = "3.3.0"
Expand Down
2 changes: 2 additions & 0 deletions bin/darkfi-mmproxy/darkfi_mmproxy.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
# List of worker logins, comment out to allow anything.
workers = ["x:x"]
32 changes: 27 additions & 5 deletions bin/darkfi-mmproxy/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,10 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/

use std::{collections::HashSet, sync::Arc};
use std::{
collections::{HashMap, HashSet},
sync::Arc,
};

use darkfi::{
async_daemonize, cli_desc,
Expand Down Expand Up @@ -61,19 +64,27 @@ struct Args {
/// JSON-RPC server listen URL
rpc_listen: Url,

#[structopt(long)]
/// List of worker logins
workers: Vec<String>,

#[structopt(long)]
/// Set log file output
log: Option<String>,
}

struct MiningProxy {
/// Worker logins
logins: HashMap<String, String>,
/// JSON-RPC connection tracker
rpc_connections: Mutex<HashSet<StoppableTaskPtr>>,
/// Main async executor reference
executor: Arc<Executor<'static>>,
}

impl MiningProxy {
fn new() -> Self {
Self { rpc_connections: Mutex::new(HashSet::new()) }
fn new(logins: HashMap<String, String>, executor: Arc<Executor<'static>>) -> Self {
Self { logins, rpc_connections: Mutex::new(HashSet::new()), executor }
}
}

Expand Down Expand Up @@ -136,9 +147,20 @@ impl RequestHandler for MiningProxy {

async_daemonize!(realmain);
async fn realmain(args: Args, ex: Arc<Executor<'static>>) -> Result<()> {
info!("Starting JSON-RPC server");
let mmproxy = Arc::new(MiningProxy::new());
// Parse worker logins
let mut logins = HashMap::new();
for worker in args.workers {
let mut split = worker.split(':');
let user = split.next().unwrap().to_string();
let pass = split.next().unwrap().to_string();
info!("Whitelisting worker \"{}:{}\"", user, pass);
logins.insert(user, pass);
}

let mmproxy = Arc::new(MiningProxy::new(logins, ex.clone()));
let mmproxy_ = Arc::clone(&mmproxy);

info!("Starting JSON-RPC server");
let rpc_task = StoppableTask::new();
rpc_task.clone().start(
listen_and_serve(args.rpc_listen, mmproxy.clone(), None, ex.clone()),
Expand Down
64 changes: 64 additions & 0 deletions bin/darkfi-mmproxy/src/stratum.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,20 +16,84 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/

use std::collections::HashMap;

use darkfi::rpc::{
jsonrpc::{ErrorCode, JsonError, JsonResult},
util::JsonValue,
};
use uuid::Uuid;

use super::MiningProxy;

/// Algo string representing Monero's RandomX
pub const RANDOMX_ALGO: &str = "rx/0";

impl MiningProxy {
/// Stratum login method. `darkfi-mmproxy` will check that it is a valid worker
/// login, and will also search for `RANDOMX_ALGO`.
/// TODO: More proper error codes
pub async fn stratum_login(&self, id: u16, params: JsonValue) -> JsonResult {
let params = params.get::<Vec<JsonValue>>().unwrap();
if params.len() != 1 || !params[0].is_object() {
return JsonError::new(ErrorCode::InvalidParams, None, id).into()
}

let params = params[0].get::<HashMap<String, JsonValue>>().unwrap();

if !params.contains_key("login") ||
!params.contains_key("pass") ||
!params.contains_key("agent") ||
!params.contains_key("algo")
{
return JsonError::new(ErrorCode::InvalidParams, None, id).into()
}

let Some(login) = params["login"].get::<String>() else {
return JsonError::new(ErrorCode::InvalidParams, None, id).into()
};

let Some(pass) = params["pass"].get::<String>() else {
return JsonError::new(ErrorCode::InvalidParams, None, id).into()
};

let Some(agent) = params["agent"].get::<String>() else {
return JsonError::new(ErrorCode::InvalidParams, None, id).into()
};

let Some(algos) = params["algo"].get::<Vec<JsonValue>>() else {
return JsonError::new(ErrorCode::InvalidParams, None, id).into()
};

// We'll only support rx/0 algo.
let mut found_xmr_algo = false;
for algo in algos {
if !algo.is_string() {
return JsonError::new(ErrorCode::InvalidParams, None, id).into()
}

if algo.get::<String>().unwrap() == RANDOMX_ALGO {
found_xmr_algo = true;
break
}
}

if !found_xmr_algo {
return JsonError::new(ErrorCode::InvalidParams, None, id).into()
}

// Check valid login
let Some(known_pass) = self.logins.get(login) else {
return JsonError::new(ErrorCode::InvalidParams, None, id).into()
};

if known_pass != pass {
return JsonError::new(ErrorCode::InvalidParams, None, id).into()
}

// Login success, generate UUID
let uuid = Uuid::new_v4();

todo!()
}

Expand Down

0 comments on commit 4c10ee8

Please sign in to comment.