2022-10-14 21:13:38 +00:00
|
|
|
// Gupax - GUI Uniting P2Pool And XMRig
|
|
|
|
//
|
|
|
|
// Copyright (c) 2022 hinto-janaiyo
|
|
|
|
//
|
|
|
|
// This program is free software: you can redistribute it and/or modify
|
|
|
|
// it under the terms of the GNU General Public License as published by
|
|
|
|
// the Free Software Foundation, either version 3 of the License, or
|
|
|
|
// (at your option) any later version.
|
|
|
|
//
|
|
|
|
// This program is distributed in the hope that it will be useful,
|
|
|
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
// GNU General Public License for more details.
|
|
|
|
//
|
|
|
|
// You should have received a copy of the GNU General Public License
|
|
|
|
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
|
|
|
|
|
|
use serde_derive::{Serialize,Deserialize};
|
|
|
|
use std::time::{Instant,Duration};
|
|
|
|
use std::collections::HashMap;
|
|
|
|
use std::error::Error;
|
|
|
|
use std::thread;
|
|
|
|
use egui::Color32;
|
2022-10-15 15:24:02 +00:00
|
|
|
use rand::Rng;
|
2022-10-14 21:13:38 +00:00
|
|
|
use log::*;
|
|
|
|
|
|
|
|
// Community Monerod nodes. All of these have ZMQ on 18083.
|
|
|
|
// Adding/removing nodes will need changes to pretty
|
|
|
|
// much all the code in this file, and the code that
|
|
|
|
// handles the actual Enum selector in the P2Pool tab.
|
|
|
|
pub const C3POOL: &'static str = "node.c3pool.com:18081";
|
|
|
|
pub const CAKE: &'static str = "xmr-node.cakewallet.com:18081";
|
|
|
|
pub const CAKE_EU: &'static str = "xmr-node-eu.cakewallet.com:18081";
|
|
|
|
pub const CAKE_UK: &'static str = "xmr-node-uk.cakewallet.com:18081";
|
|
|
|
pub const CAKE_US: &'static str = "xmr-node-usa-east.cakewallet.com:18081";
|
|
|
|
pub const MONERUJO: &'static str = "nodex.monerujo.io:18081";
|
|
|
|
pub const RINO: &'static str = "node.community.rino.io:18081";
|
|
|
|
pub const SELSTA: &'static str = "selsta1.featherwallet.net:18081";
|
|
|
|
pub const SETH: &'static str = "node.sethforprivacy.com:18089";
|
|
|
|
pub const SUPPORTXMR: &'static str = "node.supportxmr.com:18081";
|
|
|
|
pub const SUPPORTXMR_IR: &'static str = "node.supportxmr.ir:18081";
|
|
|
|
pub const XMRVSBEAST: &'static str = "p2pmd.xmrvsbeast.com:18081";
|
|
|
|
|
2022-10-16 21:29:24 +00:00
|
|
|
pub const NODE_IPS: [&'static str; 12] = [
|
|
|
|
C3POOL,CAKE,CAKE_EU,CAKE_UK,CAKE_US,MONERUJO,RINO,
|
|
|
|
SELSTA,SETH,SUPPORTXMR,SUPPORTXMR_IR,XMRVSBEAST,
|
|
|
|
];
|
|
|
|
|
2022-10-14 21:13:38 +00:00
|
|
|
#[derive(Debug)]
|
|
|
|
pub struct NodeStruct {
|
|
|
|
c3pool: Data, cake: Data, cake_eu: Data, cake_uk: Data, cake_us: Data, monerujo: Data,
|
|
|
|
rino: Data, selsta: Data, seth: Data, supportxmr: Data, supportxmr_ir: Data, xmrvsbeast: Data,
|
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(Debug)]
|
|
|
|
pub struct Data {
|
|
|
|
pub ms: u128,
|
|
|
|
pub color: Color32,
|
|
|
|
pub id: NodeEnum,
|
2022-10-16 21:29:24 +00:00
|
|
|
pub ip: &'static str,
|
2022-10-14 21:13:38 +00:00
|
|
|
}
|
|
|
|
|
2022-10-15 19:15:27 +00:00
|
|
|
#[derive(Copy,Clone,Eq,PartialEq,Debug,Deserialize,Serialize)]
|
2022-10-14 21:13:38 +00:00
|
|
|
pub enum NodeEnum {
|
|
|
|
C3pool, Cake, CakeEu, CakeUk, CakeUs, Monerujo, Rino,
|
|
|
|
Selsta, Seth, SupportXmr, SupportXmrIr, XmrVsBeast,
|
|
|
|
}
|
|
|
|
|
2022-10-15 19:15:27 +00:00
|
|
|
impl std::fmt::Display for NodeEnum {
|
|
|
|
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
|
|
|
|
write!(f, "{:#?}", self)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-10-14 21:13:38 +00:00
|
|
|
#[derive(Debug)]
|
|
|
|
pub struct PingResult {
|
2022-10-16 21:29:24 +00:00
|
|
|
pub nodes: NodeStruct,
|
2022-10-14 21:13:38 +00:00
|
|
|
pub fastest: NodeEnum,
|
|
|
|
}
|
|
|
|
|
2022-10-16 21:29:24 +00:00
|
|
|
use crate::NodeEnum::*;
|
2022-10-14 21:13:38 +00:00
|
|
|
impl NodeStruct {
|
|
|
|
pub fn default() -> Self {
|
2022-10-15 15:24:02 +00:00
|
|
|
let ms = 0;
|
|
|
|
let color = Color32::GRAY;
|
2022-10-14 21:13:38 +00:00
|
|
|
Self {
|
2022-10-16 21:29:24 +00:00
|
|
|
c3pool: Data { ms, color, id: C3pool, ip: C3POOL, },
|
|
|
|
cake: Data { ms, color, id: Cake, ip: CAKE, },
|
|
|
|
cake_eu: Data { ms, color, id: CakeEu, ip: CAKE_EU, },
|
|
|
|
cake_uk: Data { ms, color, id: CakeUk, ip: CAKE_UK, },
|
|
|
|
cake_us: Data { ms, color, id: CakeUs, ip: CAKE_US, },
|
|
|
|
monerujo: Data { ms, color, id: Monerujo, ip: MONERUJO, },
|
|
|
|
rino: Data { ms, color, id: Rino, ip: RINO, },
|
|
|
|
selsta: Data { ms, color, id: Selsta, ip: SELSTA, },
|
|
|
|
seth: Data { ms, color, id: Seth, ip: SETH, },
|
|
|
|
supportxmr: Data { ms, color, id: SupportXmr, ip: SUPPORTXMR, },
|
|
|
|
supportxmr_ir: Data { ms, color, id: SupportXmrIr, ip: SUPPORTXMR_IR, },
|
|
|
|
xmrvsbeast: Data { ms, color, id: XmrVsBeast, ip: XMRVSBEAST, },
|
2022-10-14 21:13:38 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// This is for pinging the community nodes to
|
|
|
|
// find the fastest/slowest one for the user.
|
|
|
|
// The process:
|
2022-10-15 15:24:02 +00:00
|
|
|
// - Send [get_info] JSON-RPC requests over HTTP
|
2022-10-25 02:58:42 +00:00
|
|
|
// - To prevent fingerprinting, randomly send [2-4] calls
|
2022-10-14 21:13:38 +00:00
|
|
|
// - Measure each request in milliseconds as [u128]
|
|
|
|
// - Timeout on requests over 5 seconds
|
|
|
|
// - Calculate average time
|
|
|
|
// - Add data to appropriate struct
|
|
|
|
// - Sort fastest to lowest
|
|
|
|
// - Return [PingResult(NodeStruct, NodeEnum)] (data and fastest node)
|
2022-10-18 19:26:21 +00:00
|
|
|
//
|
2022-10-14 21:13:38 +00:00
|
|
|
// This is done linearly since per IP since
|
|
|
|
// multi-threading might affect performance.
|
|
|
|
//
|
|
|
|
// <300ms = GREEN
|
|
|
|
// <1000ms = YELLOW
|
|
|
|
// >1000ms = RED
|
|
|
|
// timeout = BLACK
|
|
|
|
// default = GRAY
|
|
|
|
pub fn ping() -> PingResult {
|
|
|
|
info!("Starting community node pings...");
|
2022-10-25 02:58:42 +00:00
|
|
|
// Get node list
|
2022-10-16 21:29:24 +00:00
|
|
|
let mut nodes = NodeStruct::default();
|
2022-10-25 02:58:42 +00:00
|
|
|
|
|
|
|
// Create JSON request
|
2022-10-14 21:13:38 +00:00
|
|
|
let mut get_info = HashMap::new();
|
|
|
|
get_info.insert("jsonrpc", "2.0");
|
|
|
|
get_info.insert("id", "0");
|
|
|
|
get_info.insert("method", "get_info");
|
2022-10-25 02:58:42 +00:00
|
|
|
|
|
|
|
// Misc Settings
|
2022-10-14 21:13:38 +00:00
|
|
|
let mut vec: Vec<(u128, NodeEnum)> = Vec::new();
|
2022-10-25 02:58:42 +00:00
|
|
|
|
|
|
|
// Create HTTP Client
|
2022-10-14 21:13:38 +00:00
|
|
|
let timeout_sec = Duration::from_millis(5000);
|
2022-10-25 02:58:42 +00:00
|
|
|
let client = reqwest::blocking::ClientBuilder::new();
|
|
|
|
let client = reqwest::blocking::ClientBuilder::timeout(client, timeout_sec);
|
|
|
|
let client = reqwest::blocking::ClientBuilder::build(client).unwrap();
|
2022-10-14 21:13:38 +00:00
|
|
|
|
2022-10-16 21:29:24 +00:00
|
|
|
for ip in NODE_IPS.iter() {
|
2022-10-25 02:58:42 +00:00
|
|
|
// Match IP
|
2022-10-14 21:13:38 +00:00
|
|
|
let id = match *ip {
|
|
|
|
C3POOL => C3pool,
|
|
|
|
CAKE => Cake,
|
|
|
|
CAKE_EU => CakeEu,
|
|
|
|
CAKE_UK => CakeUk,
|
|
|
|
CAKE_US => CakeUs,
|
|
|
|
MONERUJO => Monerujo,
|
|
|
|
RINO => Rino,
|
|
|
|
SELSTA => Selsta,
|
|
|
|
SETH => Seth,
|
|
|
|
SUPPORTXMR => SupportXmr,
|
|
|
|
SUPPORTXMR_IR => SupportXmrIr,
|
|
|
|
_ => XmrVsBeast,
|
|
|
|
};
|
2022-10-25 02:58:42 +00:00
|
|
|
// Misc
|
2022-10-14 21:13:38 +00:00
|
|
|
let mut timeout = false;
|
|
|
|
let mut mid = Duration::new(0, 0);
|
2022-10-25 02:58:42 +00:00
|
|
|
let max = rand::thread_rng().gen_range(2..4);
|
|
|
|
|
|
|
|
// Start JSON-RPC request
|
2022-10-14 21:13:38 +00:00
|
|
|
for i in 1..=max {
|
|
|
|
let now = Instant::now();
|
2022-10-25 02:58:42 +00:00
|
|
|
let http = "http://".to_owned() + &**ip + "/json_rpc";
|
2022-10-14 21:13:38 +00:00
|
|
|
match client.post(http).json(&get_info).send() {
|
2022-10-25 02:58:42 +00:00
|
|
|
Ok(_) => mid += now.elapsed(),
|
2022-10-14 21:13:38 +00:00
|
|
|
Err(err) => {
|
2022-10-25 02:58:42 +00:00
|
|
|
error!("Timeout on [{:#?}: {}] (over 5 seconds) | {}", id, ip, err);
|
2022-10-14 21:13:38 +00:00
|
|
|
mid += timeout_sec;
|
|
|
|
timeout = true;
|
|
|
|
},
|
|
|
|
};
|
|
|
|
}
|
2022-10-25 02:58:42 +00:00
|
|
|
|
|
|
|
// Calculate average
|
2022-10-14 21:13:38 +00:00
|
|
|
let ms = mid.as_millis() / 3;
|
|
|
|
vec.push((ms, id));
|
2022-10-15 15:24:02 +00:00
|
|
|
info!("{}ms ... {} calls ... {}", ms, max, ip);
|
2022-10-14 21:13:38 +00:00
|
|
|
let color: Color32;
|
|
|
|
if timeout == true {
|
|
|
|
color = Color32::BLACK
|
|
|
|
} else if ms >= 1000 {
|
|
|
|
color = Color32::LIGHT_RED
|
|
|
|
} else if ms >= 300 {
|
|
|
|
color = Color32::LIGHT_YELLOW
|
|
|
|
} else {
|
|
|
|
color = Color32::LIGHT_GREEN
|
|
|
|
}
|
|
|
|
match id {
|
2022-10-16 21:29:24 +00:00
|
|
|
C3pool => { nodes.c3pool.ms = ms; nodes.c3pool.color = color; },
|
|
|
|
Cake => { nodes.cake.ms = ms; nodes.cake.color = color; },
|
|
|
|
CakeEu => { nodes.cake_eu.ms = ms; nodes.cake_eu.color = color; },
|
|
|
|
CakeUk => { nodes.cake_uk.ms = ms; nodes.cake_uk.color = color; },
|
|
|
|
CakeUs => { nodes.cake_us.ms = ms; nodes.cake_us.color = color; },
|
|
|
|
Monerujo => { nodes.monerujo.ms = ms; nodes.monerujo.color = color; },
|
|
|
|
Rino => { nodes.rino.ms = ms; nodes.rino.color = color; },
|
|
|
|
Selsta => { nodes.selsta.ms = ms; nodes.selsta.color = color; },
|
|
|
|
Seth => { nodes.seth.ms = ms; nodes.seth.color = color; },
|
|
|
|
SupportXmr => { nodes.supportxmr.ms = ms; nodes.supportxmr.color = color; },
|
|
|
|
SupportXmrIr => { nodes.supportxmr_ir.ms = ms; nodes.supportxmr_ir.color = color; },
|
|
|
|
XmrVsBeast => { nodes.xmrvsbeast.ms = ms; nodes.xmrvsbeast.color = color; },
|
2022-10-14 21:13:38 +00:00
|
|
|
}
|
|
|
|
}
|
2022-10-25 02:58:42 +00:00
|
|
|
|
|
|
|
// Calculate fastest out of all nodes
|
2022-10-14 21:13:38 +00:00
|
|
|
let mut best_ms: u128 = vec[0].0;
|
|
|
|
let mut fastest: NodeEnum = vec[0].1;
|
|
|
|
for (ms, id) in vec.iter() {
|
|
|
|
if ms < &best_ms {
|
|
|
|
fastest = *id;
|
|
|
|
best_ms = *ms;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// These values have weird behavior.
|
|
|
|
// The values don't update if not printed beforehand,
|
|
|
|
// so the match below on [fastest] gets funky.
|
|
|
|
info!("Fastest node ... {:#?} @ {:#?}ms", fastest, best_ms);
|
|
|
|
info!("Community node ping ... OK");
|
2022-10-16 21:29:24 +00:00
|
|
|
PingResult { nodes, fastest, }
|
2022-10-14 21:13:38 +00:00
|
|
|
}
|
|
|
|
}
|