mirror of
https://github.com/Cyrix126/gupaxx.git
synced 2024-11-16 15:27:46 +00:00
feat: manage selection and fallback nodes of XvB
feat: ping, select nodes of XvB process feat: reload config of xmrig to fallback to backup node fix: status of xmrig node used in real time feat: src readme technical differences with upstream
This commit is contained in:
parent
e1c3fee92c
commit
cfb6d0971c
12 changed files with 401 additions and 147 deletions
|
@ -5,9 +5,6 @@
|
|||
[XvB Bounty](https://bounties.monero.social/posts/105)
|
||||
|
||||
- [x] upgrade deps
|
||||
- [ ] fix clippy
|
||||
- [ ] better organize some new code
|
||||
- [ ] merge commits from upstream
|
||||
- [x] separate logic in smaller modules
|
||||
- [x] new tab XvB
|
||||
- [x] logo
|
||||
|
@ -17,13 +14,17 @@
|
|||
- [x] hero checkbox
|
||||
- [x] log section
|
||||
- [x] state of XvB process
|
||||
- [ ] algorithm decisions
|
||||
- [ ] selected XvB node
|
||||
- [ ] algorithm decisions info
|
||||
- [x] private stats
|
||||
- [x] round type in
|
||||
- [x] win or loose
|
||||
- [ ] fix: remove B symbol for HR
|
||||
- [ ] fix: symbol for HR
|
||||
- [x] new process for XvB
|
||||
- [x] update preferred XvB node based on ping and backup
|
||||
- [x] fix: xmrig will not do anything if node is not responding. Need to parse output of xmrig for error and update nodes.
|
||||
- [x] status process XvB
|
||||
- [x] status process XMRig node in real time.
|
||||
- [x] public information from [API](https://xmrvsbeast.com/p2pool/stats)
|
||||
- [x] stop, start, restart buttons
|
||||
- [x] button to autostart
|
||||
|
@ -44,3 +45,10 @@
|
|||
- [ ] adapt doc for new code
|
||||
- [ ] cargo package metadata
|
||||
- [ ] pgp signatures
|
||||
- [ ] fix clippy
|
||||
- [ ] better organize some new code
|
||||
- [ ] merge commits from upstream
|
||||
- [ ] tests for new functions
|
||||
- [ ] pre-release
|
||||
- [ ] feedback
|
||||
- [ ] release
|
||||
|
|
|
@ -15,6 +15,13 @@
|
|||
- [Registry Edit](#registry-edit)
|
||||
- [Windows vs Unix](#windows-vs-unix)
|
||||
|
||||
## Technical differences with upstream Gupax
|
||||
|
||||
Status of process for Xmrig use for some information an image of data when the process started.
|
||||
The node of xmrig in upstream can not change without a restart of the process.In this fork, the node used by xmrig needs to be updated without restart (using the config HTTP API of xmrig).
|
||||
So Gupaxx need to refresh the value of status tab submenu process for xmrig where before the values could not change without a restart of the process.
|
||||
The field node from ImgXmrig needs to be moved to PubXvbApi. This value must be updated by xmrig at start and by XvB process at runtime.
|
||||
|
||||
## Structure
|
||||
| File/Folder | Purpose |
|
||||
|--------------|---------|
|
||||
|
|
|
@ -605,7 +605,7 @@ fn status_p2pool(state: ProcessState, ui: &mut Ui, size: Vec2) {
|
|||
color = ORANGE;
|
||||
P2POOL_SYNCING
|
||||
}
|
||||
Middle | Waiting | NotMining => {
|
||||
Middle | Waiting | NotMining | OfflineNodesAll => {
|
||||
color = YELLOW;
|
||||
P2POOL_MIDDLE
|
||||
}
|
||||
|
@ -628,7 +628,7 @@ fn status_xmrig(state: ProcessState, ui: &mut Ui, size: Vec2) {
|
|||
color = RED;
|
||||
XMRIG_FAILED
|
||||
}
|
||||
NotMining => {
|
||||
NotMining | OfflineNodesAll => {
|
||||
color = ORANGE;
|
||||
XMRIG_NOT_MINING
|
||||
}
|
||||
|
@ -654,7 +654,7 @@ fn status_xvb(state: ProcessState, ui: &mut Ui, size: Vec2) {
|
|||
color = RED;
|
||||
XVB_FAILED
|
||||
}
|
||||
NotMining | Syncing => {
|
||||
NotMining | Syncing | OfflineNodesAll => {
|
||||
color = ORANGE;
|
||||
XVB_PUBLIC_ONLY
|
||||
}
|
||||
|
|
|
@ -167,14 +167,11 @@ fn p2pool(
|
|||
.on_hover_text(STATUS_P2POOL_SHARES);
|
||||
ui.add_sized(
|
||||
[width, height],
|
||||
Label::new(format!(
|
||||
"{}",
|
||||
if let Some(s) = api.shares_found {
|
||||
Label::new((if let Some(s) = api.shares_found {
|
||||
s.to_string()
|
||||
} else {
|
||||
UNKNOWN_DATA.to_string()
|
||||
}
|
||||
)),
|
||||
}).to_string()),
|
||||
);
|
||||
ui.add_sized(
|
||||
[width, height],
|
||||
|
@ -317,7 +314,7 @@ fn xmrig(
|
|||
),
|
||||
)
|
||||
.on_hover_text(STATUS_XMRIG_CPU);
|
||||
ui.add_sized([width, height], Label::new(format!("{}", api.resources)));
|
||||
ui.add_sized([width, height], Label::new(api.resources.to_string()));
|
||||
ui.add_sized(
|
||||
[width, height],
|
||||
Label::new(
|
||||
|
@ -327,13 +324,13 @@ fn xmrig(
|
|||
),
|
||||
)
|
||||
.on_hover_text(STATUS_XMRIG_HASHRATE);
|
||||
ui.add_sized([width, height], Label::new(format!("{}", api.hashrate)));
|
||||
ui.add_sized([width, height], Label::new(api.hashrate.to_string()));
|
||||
ui.add_sized(
|
||||
[width, height],
|
||||
Label::new(RichText::new("Difficulty").underline().color(BONE)),
|
||||
)
|
||||
.on_hover_text(STATUS_XMRIG_DIFFICULTY);
|
||||
ui.add_sized([width, height], Label::new(format!("{}", api.diff)));
|
||||
ui.add_sized([width, height], Label::new(api.diff.to_string()));
|
||||
ui.add_sized(
|
||||
[width, height],
|
||||
Label::new(RichText::new("Shares").underline().color(BONE)),
|
||||
|
@ -351,7 +348,7 @@ fn xmrig(
|
|||
Label::new(RichText::new("Pool").underline().color(BONE)),
|
||||
)
|
||||
.on_hover_text(STATUS_XMRIG_POOL);
|
||||
ui.add_sized([width, height], Label::new(&lock!(xmrig_img).url));
|
||||
ui.add_sized([width, height], Label::new(api.node.to_string()));
|
||||
ui.add_sized(
|
||||
[width, height],
|
||||
Label::new(RichText::new("Threads").underline().color(BONE)),
|
||||
|
|
|
@ -178,10 +178,8 @@ impl crate::disk::state::Xvb {
|
|||
ui.vertical_centered(|ui| {
|
||||
ui.label(XVB_WINNER_FIELD);
|
||||
ui.label(
|
||||
priv_stats
|
||||
.win_current
|
||||
.then(|| "You are Winning the round !")
|
||||
.unwrap_or("You are not the winner"),
|
||||
if priv_stats
|
||||
.win_current { "You are Winning the round !" } else { "You are not the winner" },
|
||||
);
|
||||
})
|
||||
.response
|
||||
|
|
|
@ -306,16 +306,16 @@ impl NodeData {
|
|||
// This struct leaves out most fields on purpose,
|
||||
// we only need a few to verify the node is ok.
|
||||
#[derive(Debug, serde::Deserialize)]
|
||||
struct GetInfo<'a> {
|
||||
id: &'a str,
|
||||
jsonrpc: &'a str,
|
||||
result: GetInfoResult,
|
||||
pub struct GetInfo<'a> {
|
||||
pub id: &'a str,
|
||||
pub jsonrpc: &'a str,
|
||||
pub result: GetInfoResult,
|
||||
}
|
||||
|
||||
#[derive(Debug, serde::Deserialize)]
|
||||
struct GetInfoResult {
|
||||
mainnet: bool,
|
||||
synchronized: bool,
|
||||
pub struct GetInfoResult {
|
||||
pub mainnet: bool,
|
||||
pub synchronized: bool,
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------------------------------- Ping data
|
||||
|
|
|
@ -247,45 +247,6 @@ pub struct Xmrig {
|
|||
pub struct Xvb {
|
||||
pub token: String,
|
||||
pub hero: bool,
|
||||
pub node: XvbNode,
|
||||
}
|
||||
|
||||
#[derive(Clone, Eq, PartialEq, Debug, Deserialize, Serialize, Default)]
|
||||
pub enum XvbNode {
|
||||
NorthAmerica,
|
||||
#[default]
|
||||
Europe,
|
||||
P2pool,
|
||||
}
|
||||
impl XvbNode {
|
||||
pub fn url(&self) -> String {
|
||||
match self {
|
||||
Self::NorthAmerica => String::from(XVB_NODE_NA),
|
||||
Self::Europe => String::from(XVB_NODE_EU),
|
||||
Self::P2pool => String::from("127.0.0.1:3333"),
|
||||
}
|
||||
}
|
||||
pub fn user(&self, address: &str) -> String {
|
||||
match self {
|
||||
Self::NorthAmerica => address.chars().take(8).collect(),
|
||||
Self::Europe => address.chars().take(8).collect(),
|
||||
Self::P2pool => GUPAX_VERSION_UNDERSCORE.to_string(),
|
||||
}
|
||||
}
|
||||
pub fn tls(&self) -> bool {
|
||||
match self {
|
||||
Self::NorthAmerica => true,
|
||||
Self::Europe => true,
|
||||
Self::P2pool => false,
|
||||
}
|
||||
}
|
||||
pub fn keepalive(&self) -> bool {
|
||||
match self {
|
||||
Self::NorthAmerica => true,
|
||||
Self::Europe => true,
|
||||
Self::P2pool => false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Deserialize, Serialize)]
|
||||
|
|
|
@ -216,11 +216,15 @@ pub enum ProcessState {
|
|||
Middle, // Process is in the middle of something ([re]starting/stopping), YELLOW!
|
||||
Waiting, // Process was successfully killed by a restart, and is ready to be started again, YELLOW!
|
||||
|
||||
// Only for P2Pool, ORANGE.
|
||||
// Only for P2Pool and XvB, ORANGE.
|
||||
// XvB: Xmrig or P2pool are not alive
|
||||
Syncing,
|
||||
|
||||
// Only for XMRig, ORANGE.
|
||||
// Only for XMRig and XvB, ORANGE.
|
||||
// XvB: token or address are invalid even if syntax correct
|
||||
NotMining,
|
||||
// XvB: if node of XvB become unusable (ex: offline).
|
||||
OfflineNodesAll,
|
||||
}
|
||||
|
||||
impl Default for ProcessState {
|
||||
|
@ -235,6 +239,7 @@ pub enum ProcessSignal {
|
|||
Start,
|
||||
Stop,
|
||||
Restart,
|
||||
UpdateNodes,
|
||||
}
|
||||
|
||||
impl Default for ProcessSignal {
|
||||
|
|
|
@ -1126,7 +1126,7 @@ impl PubP2poolApi {
|
|||
if v > *old_shares {
|
||||
// found new share
|
||||
*old_shares = v;
|
||||
return (true, Some(Instant::now()));
|
||||
(true, Some(Instant::now()))
|
||||
} else {
|
||||
// no new share found this last minute, check if last share is still valid
|
||||
if let Some(n) = last_time_found {
|
||||
|
@ -1150,7 +1150,7 @@ impl PubP2poolApi {
|
|||
}
|
||||
} else {
|
||||
// data from p2pool is not ready yet, so no share in pplns window.
|
||||
return (false, None);
|
||||
(false, None)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
use crate::disk::state::XvbNode;
|
||||
use crate::helper::{ProcessName, ProcessSignal, ProcessState};
|
||||
use crate::regex::XMRIG_REGEX;
|
||||
use crate::utils::human::HumanNumber;
|
||||
|
@ -19,15 +18,18 @@ use std::{
|
|||
thread,
|
||||
time::*,
|
||||
};
|
||||
use tokio::spawn;
|
||||
|
||||
use super::xvb::XvbNode;
|
||||
use super::{Helper, Process};
|
||||
impl Helper {
|
||||
#[cold]
|
||||
#[inline(never)]
|
||||
fn read_pty_xmrig(
|
||||
async fn read_pty_xmrig(
|
||||
output_parse: Arc<Mutex<String>>,
|
||||
output_pub: Arc<Mutex<String>>,
|
||||
reader: Box<dyn std::io::Read + Send>,
|
||||
process_xvb: Arc<Mutex<Process>>,
|
||||
) {
|
||||
use std::io::BufRead;
|
||||
let mut stdout = std::io::BufReader::new(reader).lines();
|
||||
|
@ -50,6 +52,50 @@ impl Helper {
|
|||
}
|
||||
|
||||
while let Some(Ok(line)) = stdout.next() {
|
||||
// need to verify if node still working
|
||||
// for that need to catch "connect error"
|
||||
if line.contains("connect error") {
|
||||
let process_xvb_c = process_xvb.clone();
|
||||
// if waiting, it is restarting or already updating nodes, so do not send signal.
|
||||
if lock!(process_xvb_c).state != ProcessState::Waiting {
|
||||
info!("node is offline, switching to backup.");
|
||||
lock!(process_xvb_c).signal = ProcessSignal::UpdateNodes;
|
||||
}
|
||||
// let address = state_p2pool.address.clone();
|
||||
// let token = state_xmrig.token.clone();
|
||||
// let pub_api_xvb_c = pub_api_xvb.clone();
|
||||
// issue because while this future is executing, other connect error could arrive and repeat the process.
|
||||
// spawn(async move {
|
||||
// // need to create client
|
||||
// let client_http = Arc::new(
|
||||
// hyper::Client::builder().build(hyper::client::HttpConnector::new()),
|
||||
// );
|
||||
// // need to spawn and wait update fastest node.
|
||||
// XvbNode::update_fastest_node(&client_http, &pub_api_xvb_c, &process_xvb_c)
|
||||
// .await;
|
||||
// // need to check new value of node.
|
||||
// let node = lock!(pub_api_xvb_c).stats_priv.node.clone();
|
||||
// // send new value to update config.
|
||||
// if let Err(err) = PrivXmrigApi::update_xmrig_config(
|
||||
// &client_http,
|
||||
// XMRIG_CONFIG_URI,
|
||||
// &token,
|
||||
// &node,
|
||||
// &address,
|
||||
// )
|
||||
// .await
|
||||
// {
|
||||
// // show to console error about updating xmrig config
|
||||
// if let Err(e) = writeln!(
|
||||
// lock!(pub_api_xvb_c).output,
|
||||
// "Failure to update xmrig config with HTTP API.\nError: {}",
|
||||
// err
|
||||
// ) {
|
||||
// error!("XvB Watchdog | GUI status write failed: {}", e);
|
||||
// }
|
||||
// }
|
||||
// });
|
||||
}
|
||||
// println!("{}", line); // For debugging.
|
||||
if let Err(e) = writeln!(lock!(output_parse), "{}", line) {
|
||||
error!("XMRig PTY Parse | Output error: {}", e);
|
||||
|
@ -134,7 +180,6 @@ impl Helper {
|
|||
lock2!(helper, xmrig).state = ProcessState::Middle;
|
||||
|
||||
let (args, api_ip_port) = Self::build_xmrig_args_and_mutate_img(helper, state, path);
|
||||
|
||||
// Print arguments & user settings to console
|
||||
crate::disk::print_dash(&format!("XMRig | Launch arguments: {:#?}", args));
|
||||
info!("XMRig | Using path: [{}]", path.display());
|
||||
|
@ -143,8 +188,10 @@ impl Helper {
|
|||
let process = Arc::clone(&lock!(helper).xmrig);
|
||||
let gui_api = Arc::clone(&lock!(helper).gui_api_xmrig);
|
||||
let pub_api = Arc::clone(&lock!(helper).pub_api_xmrig);
|
||||
let process_xvb = Arc::clone(&lock!(helper).xvb);
|
||||
let path = path.to_path_buf();
|
||||
let token = state.token.clone();
|
||||
let img_xmrig = Arc::clone(&lock!(helper).img_xmrig);
|
||||
thread::spawn(move || {
|
||||
Self::spawn_xmrig_watchdog(
|
||||
process,
|
||||
|
@ -155,6 +202,8 @@ impl Helper {
|
|||
sudo,
|
||||
api_ip_port,
|
||||
&token,
|
||||
process_xvb,
|
||||
&img_xmrig,
|
||||
);
|
||||
});
|
||||
}
|
||||
|
@ -210,6 +259,8 @@ impl Helper {
|
|||
threads: state.current_threads.to_string(),
|
||||
url: "127.0.0.1:3333 (Local P2Pool)".to_string(),
|
||||
};
|
||||
|
||||
lock2!(helper, pub_api_xmrig).node = "127.0.0.1:3333 (Local P2Pool)".to_string();
|
||||
api_ip = "127.0.0.1".to_string();
|
||||
api_port = "18088".to_string();
|
||||
|
||||
|
@ -286,9 +337,10 @@ impl Helper {
|
|||
args.push(state.pause.to_string());
|
||||
} // Pause on active
|
||||
*lock2!(helper, img_xmrig) = ImgXmrig {
|
||||
url,
|
||||
url: url.clone(),
|
||||
threads: state.current_threads.to_string(),
|
||||
};
|
||||
lock2!(helper, pub_api_xmrig).node = url;
|
||||
}
|
||||
}
|
||||
args.push(format!("--http-access-token={}", state.token)); // HTTP API Port
|
||||
|
@ -329,6 +381,8 @@ impl Helper {
|
|||
sudo: Arc<Mutex<SudoState>>,
|
||||
mut api_ip_port: String,
|
||||
token: &str,
|
||||
process_xvb: Arc<Mutex<Process>>,
|
||||
img_xmrig: &Arc<Mutex<ImgXmrig>>,
|
||||
) {
|
||||
// 1a. Create PTY
|
||||
debug!("XMRig | Creating PTY...");
|
||||
|
@ -383,8 +437,8 @@ impl Helper {
|
|||
debug!("XMRig | Spawning PTY read thread...");
|
||||
let output_parse = Arc::clone(&lock!(process).output_parse);
|
||||
let output_pub = Arc::clone(&lock!(process).output_pub);
|
||||
thread::spawn(move || {
|
||||
Self::read_pty_xmrig(output_parse, output_pub, reader);
|
||||
spawn(async move {
|
||||
Self::read_pty_xmrig(output_parse, output_pub, reader, process_xvb).await;
|
||||
});
|
||||
let output_parse = Arc::clone(&lock!(process).output_parse);
|
||||
let output_pub = Arc::clone(&lock!(process).output_pub);
|
||||
|
@ -403,7 +457,8 @@ impl Helper {
|
|||
// Reset stats before loop
|
||||
*lock!(pub_api) = PubXmrigApi::new();
|
||||
*lock!(gui_api) = PubXmrigApi::new();
|
||||
|
||||
// node used for process Status tab
|
||||
lock!(gui_api).node = lock!(img_xmrig).url.clone();
|
||||
// 5. Loop as watchdog
|
||||
info!("XMRig | Entering watchdog mode... woof!");
|
||||
loop {
|
||||
|
@ -627,6 +682,7 @@ pub struct PubXmrigApi {
|
|||
pub rejected: String,
|
||||
pub hashrate_raw: f32,
|
||||
pub hashrate_raw_15m: f32,
|
||||
pub node: String,
|
||||
}
|
||||
|
||||
impl Default for PubXmrigApi {
|
||||
|
@ -648,15 +704,18 @@ impl PubXmrigApi {
|
|||
rejected: UNKNOWN_DATA.to_string(),
|
||||
hashrate_raw: 0.0,
|
||||
hashrate_raw_15m: 0.0,
|
||||
node: UNKNOWN_DATA.to_string(),
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub(super) fn combine_gui_pub_api(gui_api: &mut Self, pub_api: &mut Self) {
|
||||
let output = std::mem::take(&mut gui_api.output);
|
||||
let node = std::mem::take(&mut gui_api.node);
|
||||
let buf = std::mem::take(&mut pub_api.output);
|
||||
*gui_api = Self {
|
||||
output,
|
||||
node,
|
||||
..std::mem::take(pub_api)
|
||||
};
|
||||
if !buf.is_empty() {
|
||||
|
@ -767,14 +826,15 @@ impl PrivXmrigApi {
|
|||
let body = hyper::body::to_bytes(response?.body_mut()).await?;
|
||||
Ok(serde_json::from_slice::<Self>(&body)?)
|
||||
}
|
||||
// #[inline]
|
||||
#[inline]
|
||||
// // Replace config with new node
|
||||
pub async fn update_xmrig_config(
|
||||
client: &hyper::Client<hyper::client::HttpConnector>,
|
||||
api_uri: &str,
|
||||
token: &str,
|
||||
node: XvbNode,
|
||||
node: &XvbNode,
|
||||
address: &str,
|
||||
gui_api_xmrig: Arc<Mutex<PubXmrigApi>>,
|
||||
) -> Result<()> {
|
||||
// get config
|
||||
let request = hyper::Request::builder()
|
||||
|
@ -791,14 +851,15 @@ impl PrivXmrigApi {
|
|||
// deserialize to json
|
||||
let mut config = serde_json::from_slice::<Value>(&body)?;
|
||||
// modify node configuration
|
||||
let uri = [node.url(), ":".to_string(), node.port()].concat();
|
||||
info!("replace xmrig config with node {}", uri);
|
||||
*config
|
||||
.pointer_mut("/pools/0/url")
|
||||
.ok_or_else(|| anyhow!("pools/0/url does not exist in xmrig config"))? =
|
||||
node.url().into();
|
||||
.ok_or_else(|| anyhow!("pools/0/url does not exist in xmrig config"))? = uri.into();
|
||||
*config
|
||||
.pointer_mut("/pools/0/user")
|
||||
.ok_or_else(|| anyhow!("pools/0/user does not exist in xmrig config"))? =
|
||||
node.user(&address).into();
|
||||
node.user(address).into();
|
||||
*config
|
||||
.pointer_mut("/pools/0/tls")
|
||||
.ok_or_else(|| anyhow!("pools/0/tls does not exist in xmrig config"))? =
|
||||
|
@ -813,6 +874,7 @@ impl PrivXmrigApi {
|
|||
let request = hyper::Request::builder()
|
||||
.method("PUT")
|
||||
.header("Authorization", ["Bearer ", token].concat())
|
||||
.header("Content-Type", "application/json")
|
||||
.uri(api_uri)
|
||||
.body(body)?;
|
||||
tokio::time::timeout(
|
||||
|
@ -820,6 +882,8 @@ impl PrivXmrigApi {
|
|||
client.request(request),
|
||||
)
|
||||
.await??;
|
||||
// update process status
|
||||
lock!(gui_api_xmrig).node = node.to_string();
|
||||
anyhow::Ok(())
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,7 +2,7 @@ use anyhow::{bail, Result};
|
|||
use bytes::Bytes;
|
||||
use derive_more::Display;
|
||||
use hyper::client::HttpConnector;
|
||||
use hyper::{Client, StatusCode};
|
||||
use hyper::{Client, Request, StatusCode};
|
||||
use hyper_tls::HttpsConnector;
|
||||
use log::{debug, error, info, warn};
|
||||
use readable::up::Uptime;
|
||||
|
@ -17,11 +17,12 @@ use std::{
|
|||
use tokio::spawn;
|
||||
use tokio::time::sleep_until;
|
||||
|
||||
use crate::disk::state::XvbNode;
|
||||
use crate::components::node::{GetInfo, TIMEOUT_NODE_PING};
|
||||
use crate::helper::xmrig::PrivXmrigApi;
|
||||
use crate::utils::constants::{
|
||||
BLOCK_PPLNS_WINDOW_MAIN, BLOCK_PPLNS_WINDOW_MINI, SECOND_PER_BLOCK_P2POOL, XMRIG_CONFIG_URI,
|
||||
XVB_BUFFER, XVB_PUBLIC_ONLY, XVB_ROUND_DONOR_MEGA_MIN_HR, XVB_ROUND_DONOR_MIN_HR,
|
||||
BLOCK_PPLNS_WINDOW_MAIN, BLOCK_PPLNS_WINDOW_MINI, GUPAX_VERSION_UNDERSCORE,
|
||||
SECOND_PER_BLOCK_P2POOL, XMRIG_CONFIG_URI, XVB_BUFFER, XVB_NODE_EU, XVB_NODE_NA, XVB_NODE_PORT,
|
||||
XVB_NODE_RPC, XVB_PUBLIC_ONLY, XVB_ROUND_DONOR_MEGA_MIN_HR, XVB_ROUND_DONOR_MIN_HR,
|
||||
XVB_ROUND_DONOR_VIP_MIN_HR, XVB_ROUND_DONOR_WHALE_MIN_HR, XVB_TIME_ALGO, XVB_URL,
|
||||
};
|
||||
use crate::{
|
||||
|
@ -133,11 +134,15 @@ impl Helper {
|
|||
gui_api_xmrig: Arc<Mutex<PubXmrigApi>>,
|
||||
process_xmrig: Arc<Mutex<Process>>,
|
||||
) {
|
||||
// client for http and one for https, both will be valid for the thread scope.
|
||||
let https = HttpsConnector::new();
|
||||
let client = hyper::Client::builder().build(https);
|
||||
let client_https = hyper::Client::builder().build(https);
|
||||
// client http should be created only if process completely started, because it's not useful otherwise, but it would possibly be unitiliazed.
|
||||
let client_http =
|
||||
Arc::new(hyper::Client::builder().build(hyper::client::HttpConnector::new()));
|
||||
info!("XvB | verify address and token");
|
||||
if let Err(err) =
|
||||
XvbPrivStats::request_api(&client, &state_p2pool.address, &state_xvb.token).await
|
||||
XvbPrivStats::request_api(&client_https, &state_p2pool.address, &state_xvb.token).await
|
||||
{
|
||||
// send to console: token non existent for address on XvB server
|
||||
warn!("Xvb | Start ... Partially failed because token and associated address are not existent on XvB server: {}\n", err);
|
||||
|
@ -191,6 +196,13 @@ impl Helper {
|
|||
} else {
|
||||
info!("XvB Fully started");
|
||||
lock!(process).state = ProcessState::Alive;
|
||||
let pub_api_c = pub_api.clone();
|
||||
let client_http_c = client_http.clone();
|
||||
let process_c = process.clone();
|
||||
// will check which pool to use, will send NotMining if
|
||||
spawn(async move {
|
||||
XvbNode::update_fastest_node(&client_http_c, &pub_api_c, &process_c).await
|
||||
});
|
||||
if let Err(e) = writeln!(lock!(gui_api).output, "XvB started\n") {
|
||||
error!("XvB Watchdog | GUI status write failed: {}", e);
|
||||
}
|
||||
|
@ -235,7 +247,7 @@ impl Helper {
|
|||
} else {
|
||||
// verify if the state is changing because p2pool is not alive anymore.
|
||||
if lock!(process).state != ProcessState::Syncing {
|
||||
info!("XvB | stop partially because p2pool is not alive anymore.");
|
||||
info!("XvB | stopped partially because p2pool is not alive anymore.");
|
||||
*lock!(pub_api) = PubXvbApi::new();
|
||||
*lock!(gui_api) = PubXvbApi::new();
|
||||
lock!(process).state = ProcessState::Syncing;
|
||||
|
@ -248,11 +260,20 @@ impl Helper {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Set timer
|
||||
let now = Instant::now();
|
||||
// check signal
|
||||
debug!("XvB | check signal");
|
||||
if signal_interrupt(process.clone(), start, gui_api.clone()) {
|
||||
if signal_interrupt(
|
||||
process.clone(),
|
||||
start,
|
||||
&client_http,
|
||||
&gui_api.clone(),
|
||||
&gui_api_xmrig,
|
||||
state_p2pool,
|
||||
state_xmrig,
|
||||
) {
|
||||
break;
|
||||
}
|
||||
// verify if
|
||||
|
@ -261,7 +282,7 @@ impl Helper {
|
|||
let since = lock!(gui_api).tick;
|
||||
if since >= 60 || since == 0 {
|
||||
debug!("XvB Watchdog | Attempting HTTP public API request...");
|
||||
match XvbPubStats::request_api(&client).await {
|
||||
match XvbPubStats::request_api(&client_https).await {
|
||||
Ok(new_data) => {
|
||||
debug!("XvB Watchdog | HTTP API request OK");
|
||||
lock!(&pub_api).stats_pub = new_data;
|
||||
|
@ -288,7 +309,7 @@ impl Helper {
|
|||
debug!("XvB Watchdog | Attempting HTTP private API request...");
|
||||
// reload private stats
|
||||
match XvbPrivStats::request_api(
|
||||
&client,
|
||||
&client_https,
|
||||
&state_p2pool.address,
|
||||
&state_xvb.token,
|
||||
)
|
||||
|
@ -386,31 +407,38 @@ impl Helper {
|
|||
// the first 15 minutes, the HR of xmrig will be 0.0, so xmrig will always mine on p2pool for 15m.
|
||||
if start_algorithm.elapsed() >= Duration::from_secs(XVB_TIME_ALGO.into()) {
|
||||
info!("Xvb Process | Algorithm is started");
|
||||
// the time that takes the algorithm do decide the next ten minutes could means less p2pool mining. It is solved by the buffer.
|
||||
// the time that takes the algorithm do decide the next ten minutes could means less p2pool mining. It is solved by the buffer and spawning requests.
|
||||
start_algorithm = tokio::time::Instant::now();
|
||||
// request XMrig to mine on P2pool
|
||||
info!("Xvb Process | request to mine on p2pool");
|
||||
let client: hyper::Client<hyper::client::HttpConnector> =
|
||||
hyper::Client::builder().build(hyper::client::HttpConnector::new());
|
||||
let api_uri = ["http://127.0.0.1:18088/", XMRIG_CONFIG_URI].concat();
|
||||
if let Err(err) = PrivXmrigApi::update_xmrig_config(
|
||||
&client,
|
||||
&api_uri,
|
||||
&state_xmrig.token,
|
||||
XvbNode::P2pool,
|
||||
&state_p2pool.address,
|
||||
)
|
||||
.await
|
||||
{
|
||||
// show to console error about updating xmrig config
|
||||
if let Err(e) = writeln!(
|
||||
lock!(gui_api).output,
|
||||
"Failure to update xmrig config with HTTP API.\nError: {}",
|
||||
err
|
||||
) {
|
||||
error!("XvB Watchdog | GUI status write failed: {}", e);
|
||||
let client_http_c = client_http.clone();
|
||||
let gui_api_c = gui_api.clone();
|
||||
let token_xmrig = Arc::new(state_xmrig.token.clone());
|
||||
let token_xmrig_c = token_xmrig.clone();
|
||||
let address = Arc::new(state_p2pool.address.clone());
|
||||
let address_c = address.clone();
|
||||
let gui_api_xmrig_c = gui_api_xmrig.clone();
|
||||
spawn(async move {
|
||||
if let Err(err) = PrivXmrigApi::update_xmrig_config(
|
||||
&client_http_c,
|
||||
XMRIG_CONFIG_URI,
|
||||
&token_xmrig_c,
|
||||
&XvbNode::P2pool,
|
||||
&address_c,
|
||||
gui_api_xmrig_c,
|
||||
)
|
||||
.await
|
||||
{
|
||||
// show to console error about updating xmrig config
|
||||
if let Err(e) = writeln!(
|
||||
lock!(gui_api_c).output,
|
||||
"Failure to update xmrig config with HTTP API.\nError: {}",
|
||||
err
|
||||
) {
|
||||
error!("XvB Watchdog | GUI status write failed: {}", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// if share is in PW,
|
||||
if share {
|
||||
|
@ -437,23 +465,22 @@ impl Helper {
|
|||
}
|
||||
info!("Xvb Process | spared time {} ", spared_time);
|
||||
// sleep 10m less spared time then request XMrig to mine on XvB
|
||||
let was_instant = start_algorithm.clone();
|
||||
let node = state_xvb.node.clone();
|
||||
let token = state_xmrig.token.clone();
|
||||
let address = state_p2pool.address.clone();
|
||||
let gui_api = gui_api.clone();
|
||||
let was_instant = start_algorithm;
|
||||
let gui_api_c = gui_api.clone();
|
||||
let client_http_c = client_http.clone();
|
||||
let gui_api_xmrig_c = gui_api_xmrig.clone();
|
||||
spawn(async move {
|
||||
Helper::sleep_then_update_node_xmrig(
|
||||
was_instant,
|
||||
&was_instant,
|
||||
spared_time,
|
||||
&client,
|
||||
&api_uri,
|
||||
&token,
|
||||
node,
|
||||
&client_http_c,
|
||||
XMRIG_CONFIG_URI,
|
||||
&token_xmrig,
|
||||
&address,
|
||||
gui_api,
|
||||
gui_api_c,
|
||||
gui_api_xmrig_c,
|
||||
)
|
||||
.await;
|
||||
.await
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -509,19 +536,27 @@ impl Helper {
|
|||
}
|
||||
}
|
||||
async fn sleep_then_update_node_xmrig(
|
||||
was_instant: tokio::time::Instant,
|
||||
was_instant: &tokio::time::Instant,
|
||||
spared_time: u32,
|
||||
client: &Client<HttpConnector>,
|
||||
api_uri: &str,
|
||||
token_xmrig: &str,
|
||||
node: XvbNode,
|
||||
address: &str,
|
||||
gui_api: Arc<Mutex<PubXvbApi>>,
|
||||
gui_api_xmrig: Arc<Mutex<PubXmrigApi>>,
|
||||
) {
|
||||
let node = lock!(gui_api).stats_priv.node.clone();
|
||||
info!("Xvb Process | for now mine on p2pol ");
|
||||
sleep_until(was_instant + Duration::from_secs((XVB_TIME_ALGO - spared_time) as u64)).await;
|
||||
if let Err(err) =
|
||||
PrivXmrigApi::update_xmrig_config(client, api_uri, token_xmrig, node, address).await
|
||||
sleep_until(*was_instant + Duration::from_secs((XVB_TIME_ALGO - spared_time) as u64)).await;
|
||||
if let Err(err) = PrivXmrigApi::update_xmrig_config(
|
||||
client,
|
||||
api_uri,
|
||||
token_xmrig,
|
||||
&node,
|
||||
address,
|
||||
gui_api_xmrig,
|
||||
)
|
||||
.await
|
||||
{
|
||||
// show to console error about updating xmrig config
|
||||
if let Err(e) = writeln!(
|
||||
|
@ -571,6 +606,19 @@ pub struct XvbPubStats {
|
|||
pub reward_yearly: Vec<f64>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Default, Deserialize)]
|
||||
pub struct XvbPrivStats {
|
||||
pub fails: u8,
|
||||
pub donor_1hr_avg: f32,
|
||||
pub donor_24hr_avg: f32,
|
||||
#[serde(skip)]
|
||||
pub win_current: bool,
|
||||
#[serde(skip)]
|
||||
pub round_participate: Option<XvbRound>,
|
||||
#[serde(skip)]
|
||||
pub node: XvbNode,
|
||||
}
|
||||
|
||||
impl XvbPubStats {
|
||||
#[inline]
|
||||
// Send an HTTP request to XvB's API, serialize it into [Self] and return it
|
||||
|
@ -622,17 +670,6 @@ impl XvbPrivStats {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Default, Deserialize)]
|
||||
pub struct XvbPrivStats {
|
||||
pub fails: u8,
|
||||
pub donor_1hr_avg: f32,
|
||||
pub donor_24hr_avg: f32,
|
||||
#[serde(skip)]
|
||||
pub win_current: bool,
|
||||
#[serde(skip)]
|
||||
pub round_participate: Option<XvbRound>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Default, Display, Deserialize)]
|
||||
pub enum XvbRound {
|
||||
#[default]
|
||||
|
@ -652,6 +689,138 @@ pub enum XvbRound {
|
|||
DonorMega,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Default, PartialEq, Display)]
|
||||
pub enum XvbNode {
|
||||
#[display(fmt = "XvB North America Node")]
|
||||
NorthAmerica,
|
||||
#[default]
|
||||
#[display(fmt = "XvB North European Node")]
|
||||
Europe,
|
||||
#[display(fmt = "Local P2pool")]
|
||||
P2pool,
|
||||
}
|
||||
impl XvbNode {
|
||||
pub fn url(&self) -> String {
|
||||
match self {
|
||||
Self::NorthAmerica => String::from(XVB_NODE_NA),
|
||||
Self::Europe => String::from(XVB_NODE_EU),
|
||||
Self::P2pool => String::from("127.0.0.1"),
|
||||
}
|
||||
}
|
||||
pub fn port(&self) -> String {
|
||||
match self {
|
||||
Self::NorthAmerica | Self::Europe => String::from(XVB_NODE_PORT),
|
||||
Self::P2pool => String::from("3333"),
|
||||
}
|
||||
}
|
||||
pub fn user(&self, address: &str) -> String {
|
||||
match self {
|
||||
Self::NorthAmerica => address.chars().take(8).collect(),
|
||||
Self::Europe => address.chars().take(8).collect(),
|
||||
Self::P2pool => GUPAX_VERSION_UNDERSCORE.to_string(),
|
||||
}
|
||||
}
|
||||
pub fn tls(&self) -> bool {
|
||||
match self {
|
||||
Self::NorthAmerica => true,
|
||||
Self::Europe => true,
|
||||
Self::P2pool => false,
|
||||
}
|
||||
}
|
||||
pub fn keepalive(&self) -> bool {
|
||||
match self {
|
||||
Self::NorthAmerica => true,
|
||||
Self::Europe => true,
|
||||
Self::P2pool => false,
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn update_fastest_node(
|
||||
client: &Arc<Client<HttpConnector>>,
|
||||
pub_api_xvb: &Arc<Mutex<PubXvbApi>>,
|
||||
process_xvb: &Arc<Mutex<Process>>,
|
||||
) {
|
||||
let client_eu = client.clone();
|
||||
let client_na = client.clone();
|
||||
let ms_eu = spawn(async move { XvbNode::ping(&XvbNode::Europe.url(), &client_eu).await });
|
||||
let ms_na =
|
||||
spawn(async move { XvbNode::ping(&XvbNode::NorthAmerica.url(), &client_na).await });
|
||||
let node = if let Ok(ms_eu) = ms_eu.await {
|
||||
if let Ok(ms_na) = ms_na.await {
|
||||
// if two nodes are up, compare ping latency and return fastest.
|
||||
if ms_na != TIMEOUT_NODE_PING && ms_eu != TIMEOUT_NODE_PING {
|
||||
if ms_na < ms_eu {
|
||||
XvbNode::NorthAmerica
|
||||
} else {
|
||||
XvbNode::Europe
|
||||
}
|
||||
} else
|
||||
// if only na is online, return it.
|
||||
if ms_na != TIMEOUT_NODE_PING && ms_eu == TIMEOUT_NODE_PING {
|
||||
XvbNode::NorthAmerica
|
||||
} else
|
||||
// if only eu is online, return it.
|
||||
if ms_na == TIMEOUT_NODE_PING && ms_eu != TIMEOUT_NODE_PING {
|
||||
XvbNode::Europe
|
||||
} else {
|
||||
// if P2pool is returned, it means none of the two nodes are available.
|
||||
XvbNode::P2pool
|
||||
}
|
||||
} else {
|
||||
error!("ping has failed !");
|
||||
XvbNode::P2pool
|
||||
}
|
||||
} else {
|
||||
error!("ping has failed !");
|
||||
XvbNode::P2pool
|
||||
};
|
||||
if node == XvbNode::P2pool {
|
||||
// if both nodes are dead, then the state of the process must be NodesOffline
|
||||
info!("XvB node ping, all offline or ping failed, switching back to p2pool",);
|
||||
lock!(process_xvb).state = ProcessState::OfflineNodesAll;
|
||||
} else {
|
||||
// if node is up and because update_fastest is used only if token/address is valid, it means XvB process is Alive.
|
||||
info!("XvB node ping, both online and best is {}", node.url());
|
||||
lock!(process_xvb).state = ProcessState::Alive;
|
||||
}
|
||||
lock!(pub_api_xvb).stats_priv.node = node;
|
||||
}
|
||||
async fn ping(ip: &str, client: &Client<HttpConnector>) -> u128 {
|
||||
let request = Request::builder()
|
||||
.method("POST")
|
||||
.uri("http://".to_string() + ip + ":" + XVB_NODE_RPC + "/json_rpc")
|
||||
.body(hyper::Body::from(
|
||||
r#"{"jsonrpc":"2.0","id":"0","method":"get_info"}"#,
|
||||
))
|
||||
.expect("hyper request should build.");
|
||||
let ms;
|
||||
let now = Instant::now();
|
||||
match tokio::time::timeout(Duration::from_secs(5), client.request(request)).await {
|
||||
Ok(Ok(json_rpc)) => {
|
||||
// Attempt to convert to JSON-RPC.
|
||||
match hyper::body::to_bytes(json_rpc.into_body()).await {
|
||||
Ok(b) => match serde_json::from_slice::<GetInfo<'_>>(&b) {
|
||||
Ok(rpc) => {
|
||||
if rpc.result.mainnet && rpc.result.synchronized {
|
||||
ms = now.elapsed().as_millis();
|
||||
} else {
|
||||
ms = TIMEOUT_NODE_PING;
|
||||
warn!("Ping | {ip} responded with valid get_info but is not in sync, remove this node!");
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
ms = TIMEOUT_NODE_PING;
|
||||
warn!("Ping | {ip} responded but with invalid get_info, remove this node!");
|
||||
}
|
||||
},
|
||||
_ => ms = TIMEOUT_NODE_PING,
|
||||
};
|
||||
}
|
||||
_ => ms = TIMEOUT_NODE_PING,
|
||||
};
|
||||
ms
|
||||
}
|
||||
}
|
||||
impl PubXvbApi {
|
||||
pub fn new() -> Self {
|
||||
Self::default()
|
||||
|
@ -680,7 +849,11 @@ impl PubXvbApi {
|
|||
fn signal_interrupt(
|
||||
process: Arc<Mutex<Process>>,
|
||||
start: Instant,
|
||||
gui_api: Arc<Mutex<PubXvbApi>>,
|
||||
client_http: &Arc<Client<HttpConnector>>,
|
||||
gui_api: &Arc<Mutex<PubXvbApi>>,
|
||||
gui_api_xmrig: &Arc<Mutex<PubXmrigApi>>,
|
||||
state_p2pool: &crate::disk::state::P2pool,
|
||||
state_xmrig: &crate::disk::state::Xmrig,
|
||||
) -> bool {
|
||||
// Check SIGNAL
|
||||
// check if STOP or RESTART Signal is given.
|
||||
|
@ -718,6 +891,46 @@ fn signal_interrupt(
|
|||
debug!("XvB Watchdog | Restart SIGNAL done, breaking");
|
||||
lock!(process).state = ProcessState::Waiting;
|
||||
return true;
|
||||
// Check UPDATE NODES
|
||||
} else if lock!(process).signal == ProcessSignal::UpdateNodes
|
||||
&& lock!(process).state != ProcessState::Waiting
|
||||
{
|
||||
info!("XvB Watchdog | Signal has been given to ping and reselect Nodes.");
|
||||
// if signal is waiting, he is restarting or already updating nodes.
|
||||
// A signal has been given to ping the nodes and select the fastest.
|
||||
let gui_api_c = gui_api.clone();
|
||||
let gui_api_xmrig_c = gui_api_xmrig.clone();
|
||||
let client_http_c = client_http.clone();
|
||||
let process_c = process.clone();
|
||||
let token_xmrig = state_xmrig.token.clone();
|
||||
let address = state_p2pool.address.clone();
|
||||
lock!(process).state = ProcessState::Waiting;
|
||||
let node = lock!(gui_api).stats_priv.node.clone();
|
||||
spawn(async move {
|
||||
XvbNode::update_fastest_node(&client_http_c, &gui_api_c, &process_c).await;
|
||||
|
||||
if let Err(err) = PrivXmrigApi::update_xmrig_config(
|
||||
&client_http_c,
|
||||
XMRIG_CONFIG_URI,
|
||||
&token_xmrig,
|
||||
&node,
|
||||
&address,
|
||||
gui_api_xmrig_c,
|
||||
)
|
||||
.await
|
||||
{
|
||||
// show to console error about updating xmrig config
|
||||
if let Err(e) = writeln!(
|
||||
lock!(&gui_api_c).output,
|
||||
"Failure to update xmrig config with HTTP API.\nError: {}",
|
||||
err
|
||||
) {
|
||||
error!("XvB Watchdog | GUI status write failed: {}", e);
|
||||
}
|
||||
}
|
||||
});
|
||||
lock!(process).signal = ProcessSignal::None;
|
||||
// the state will be Offline or Alive after update_fastest_node is done, meanwhile Signal will be None so not re-treated before update_fastest is done.
|
||||
}
|
||||
false
|
||||
}
|
||||
|
@ -745,7 +958,6 @@ mod test {
|
|||
let client = hyper::Client::builder().build(https);
|
||||
let new_data = thread::spawn(move || corr(client)).join().unwrap();
|
||||
assert!(!new_data.reward_yearly.is_empty());
|
||||
dbg!(new_data);
|
||||
}
|
||||
#[tokio::main]
|
||||
async fn corr(client: Client<HttpsConnector<hyper::client::HttpConnector>>) -> XvbPubStats {
|
||||
|
|
|
@ -86,7 +86,7 @@ pub const P2POOL_API_PATH_NETWORK: &str = "network/stats";
|
|||
#[cfg(target_family = "unix")]
|
||||
pub const P2POOL_API_PATH_POOL: &str = "pool/stats";
|
||||
pub const XMRIG_API_URI: &str = "1/summary"; // The default relative URI of XMRig's API
|
||||
pub const XMRIG_CONFIG_URI: &str = "1/config"; // The default relative URI of XMRig's API config
|
||||
pub const XMRIG_CONFIG_URI: &str = "http://127.0.0.1:18088/1/config"; // The default relative URI of XMRig's API config
|
||||
|
||||
// Process state tooltips (online, offline, etc)
|
||||
pub const P2POOL_ALIVE: &str = "P2Pool is online and fully synchronized";
|
||||
|
@ -413,8 +413,10 @@ pub const XVB_HELP: &str = "You need to register an account by clicking on the l
|
|||
pub const XVB_URL: &str = "https://xmrvsbeast.com";
|
||||
|
||||
pub const XVB_URL_PUBLIC_API: &str = "https://xmrvsbeast.com/p2pool/stats";
|
||||
pub const XVB_NODE_EU: &str = "eu.xmrvsbeast.com:4247";
|
||||
pub const XVB_NODE_NA: &str = "na.xmrvsbeast.com:4247";
|
||||
pub const XVB_NODE_PORT: &str = "4247";
|
||||
pub const XVB_NODE_EU: &str = "eu.xmrvsbeast.com";
|
||||
pub const XVB_NODE_NA: &str = "na.xmrvsbeast.com";
|
||||
pub const XVB_NODE_RPC: &str = "18089";
|
||||
pub const XVB_URL_RULES: &str = "https://xmrvsbeast.com/p2pool/rules.html";
|
||||
// buffer in percentage of HR to have plus the requirement.
|
||||
pub const XVB_BUFFER: f32 = 1.05;
|
||||
|
|
Loading…
Reference in a new issue