Merge pull request #11 from mostafaei2002/dev
Some checks are pending
CI / ci (macos-latest) (push) Waiting to run
CI / ci (ubuntu-latest) (push) Waiting to run
Rust / fmt (push) Waiting to run
Rust / test (macos-latest) (push) Waiting to run
Rust / test (ubuntu-latest) (push) Waiting to run
Rust / typo (push) Waiting to run
Rust / clippy (macos-latest) (push) Waiting to run
Rust / clippy (ubuntu-latest) (push) Waiting to run
Rust / check (macos-latest) (push) Waiting to run
Rust / check (ubuntu-latest) (push) Waiting to run
Rust / doc (macos-latest) (push) Waiting to run
Rust / doc (ubuntu-latest) (push) Waiting to run
Typo / typo (push) Waiting to run

feat: add XvB options, refactor & improve algorithm
This commit is contained in:
Cyrix126 2024-07-24 21:45:05 +02:00 committed by GitHub
commit b3c0e6e12c
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
19 changed files with 1499 additions and 1000 deletions

View file

@ -2,7 +2,7 @@ name: CI
on: on:
push: push:
branches: [ "main" ] branches: [ "main", "dev" ]
pull_request: pull_request:
branches: [ "main" ] branches: [ "main" ]

View file

@ -2,7 +2,7 @@ name: Rust
on: on:
push: push:
branches: [ "main" ] branches: [ "main", "dev" ]
pull_request: pull_request:
branches: [ "main" ] branches: [ "main" ]

View file

@ -4,7 +4,7 @@ name: Typo
on: on:
push: push:
branches: [ "main" ] branches: [ "main", "dev" ]
pull_request: pull_request:
branches: [ "main" ] branches: [ "main" ]

2
.gitignore vendored
View file

@ -1,3 +1,5 @@
/target /target
/feature /feature
.DS_Store .DS_Store
rustc-ice-*
.vscode/

View file

@ -571,8 +571,10 @@ impl App {
app.tab = app.state.gupax.tab; app.tab = app.state.gupax.tab;
// Set saved Hero mode to runtime. // Set saved Hero mode to runtime.
app.xvb_api.lock().unwrap().stats_priv.runtime_hero_mode = app.state.xvb.hero; debug!("Setting runtime_mode & runtime_manual_amount");
app.xvb_api.lock().unwrap().stats_priv.runtime_mode = app.state.xvb.mode.clone().into();
app.xvb_api.lock().unwrap().stats_priv.runtime_manual_amount =
app.state.xvb.manual_amount_raw;
// Check if [P2pool.node] exists // Check if [P2pool.node] exists
info!("App Init | Checking if saved remote node still exists..."); info!("App Init | Checking if saved remote node still exists...");
app.state.p2pool.node = RemoteNode::check_exists(&app.state.p2pool.node); app.state.p2pool.node = RemoteNode::check_exists(&app.state.p2pool.node);

View file

@ -128,14 +128,17 @@ impl crate::app::App {
wants_input, wants_input,
); );
} }
Tab::Xvb => self.xvb_run_actions( Tab::Xvb => {
self.xvb_submenu(ui, size);
self.xvb_run_actions(
ui, ui,
height, height,
xvb_is_waiting, xvb_is_waiting,
xvb_is_alive, xvb_is_alive,
key, key,
wants_input, wants_input,
), )
}
Tab::About => {} Tab::About => {}
} }
}); });
@ -552,91 +555,26 @@ impl crate::app::App {
} }
}); });
} }
fn xmrig_proxy_run_actions(
&mut self, fn xvb_submenu(&mut self, ui: &mut Ui, size: Vec2) {
ui: &mut Ui,
height: f32,
xmrig_proxy_is_waiting: bool,
xmrig_proxy_is_alive: bool,
key: &KeyPressed,
wants_input: bool,
) {
ui.group(|ui| { ui.group(|ui| {
let width = (ui.available_width() / 3.0) - 5.0; let width = size.x / 1.5;
let size = vec2(width, height); let size = vec2(width, size.y);
if xmrig_proxy_is_waiting { if ui
ui.add_enabled_ui(false, |ui| { .add_sized(
ui.add_sized(size, Button::new("")) size,
.on_disabled_hover_text(XMRIG_PROXY_MIDDLE); SelectableLabel::new(!self.state.xvb.simple, "Advanced"),
ui.add_sized(size, Button::new("")) )
.on_disabled_hover_text(XMRIG_PROXY_MIDDLE);
ui.add_sized(size, Button::new(""))
.on_disabled_hover_text(XMRIG_PROXY_MIDDLE);
});
} else if xmrig_proxy_is_alive {
if key.is_up() && !wants_input
|| ui
.add_sized(size, Button::new(""))
.on_hover_text("Restart XMRig-Proxy")
.clicked() .clicked()
{ {
let _ = lock!(self.og).update_absolute_path(); self.state.xvb.simple = false;
let _ = self.state.update_absolute_path();
Helper::restart_xp(
&self.helper,
&self.state.xmrig_proxy,
&self.state.xmrig,
&self.state.gupax.absolute_xp_path,
);
} }
if key.is_down() && !wants_input ui.separator();
|| ui if ui
.add_sized(size, Button::new("")) .add_sized(size, SelectableLabel::new(self.state.xvb.simple, "Simple"))
.on_hover_text("Stop XMRig-Proxy")
.clicked() .clicked()
{ {
Helper::stop_xp(&self.helper); self.state.xvb.simple = true;
}
ui.add_enabled_ui(false, |ui| {
ui.add_sized(size, Button::new(""))
.on_disabled_hover_text("Start XMRig-Proxy");
});
} else {
ui.add_enabled_ui(false, |ui| {
ui.add_sized(size, Button::new(""))
.on_disabled_hover_text("Restart XMRig-Proxy");
ui.add_sized(size, Button::new(""))
.on_disabled_hover_text("Stop XMRig-Proxy");
});
let mut text = String::new();
let mut ui_enabled = true;
if !Gupax::path_is_file(&self.state.gupax.xmrig_proxy_path) {
ui_enabled = false;
text = format!("Error: {}", XMRIG_PROXY_PATH_NOT_FILE);
} else if !crate::components::update::check_xp_path(
&self.state.gupax.xmrig_proxy_path,
) {
ui_enabled = false;
text = format!("Error: {}", XMRIG_PROXY_PATH_NOT_VALID);
}
ui.set_enabled(ui_enabled);
let color = if ui_enabled { GREEN } else { RED };
if (ui_enabled && key.is_up() && !wants_input)
|| ui
.add_sized(size, Button::new(RichText::new("").color(color)))
.on_hover_text("Start XMRig-Proxy")
.on_disabled_hover_text(text)
.clicked()
{
let _ = lock!(self.og).update_absolute_path();
let _ = self.state.update_absolute_path();
Helper::start_xp(
&self.helper,
&self.state.xmrig_proxy,
&self.state.xmrig,
&self.state.gupax.absolute_xp_path,
);
}
} }
}); });
} }
@ -719,6 +657,96 @@ impl crate::app::App {
} }
}); });
} }
fn xmrig_proxy_run_actions(
&mut self,
ui: &mut Ui,
height: f32,
xmrig_proxy_is_waiting: bool,
xmrig_proxy_is_alive: bool,
key: &KeyPressed,
wants_input: bool,
) {
ui.group(|ui| {
let width = (ui.available_width() / 3.0) - 5.0;
let size = vec2(width, height);
if xmrig_proxy_is_waiting {
ui.add_enabled_ui(false, |ui| {
ui.add_sized(size, Button::new(""))
.on_disabled_hover_text(XMRIG_PROXY_MIDDLE);
ui.add_sized(size, Button::new(""))
.on_disabled_hover_text(XMRIG_PROXY_MIDDLE);
ui.add_sized(size, Button::new(""))
.on_disabled_hover_text(XMRIG_PROXY_MIDDLE);
});
} else if xmrig_proxy_is_alive {
if key.is_up() && !wants_input
|| ui
.add_sized(size, Button::new(""))
.on_hover_text("Restart XMRig-Proxy")
.clicked()
{
let _ = lock!(self.og).update_absolute_path();
let _ = self.state.update_absolute_path();
Helper::restart_xp(
&self.helper,
&self.state.xmrig_proxy,
&self.state.xmrig,
&self.state.gupax.absolute_xp_path,
);
}
if key.is_down() && !wants_input
|| ui
.add_sized(size, Button::new(""))
.on_hover_text("Stop XMRig-Proxy")
.clicked()
{
Helper::stop_xp(&self.helper);
}
ui.add_enabled_ui(false, |ui| {
ui.add_sized(size, Button::new(""))
.on_disabled_hover_text("Start XMRig-Proxy");
});
} else {
ui.add_enabled_ui(false, |ui| {
ui.add_sized(size, Button::new(""))
.on_disabled_hover_text("Restart XMRig-Proxy");
ui.add_sized(size, Button::new(""))
.on_disabled_hover_text("Stop XMRig-Proxy");
});
let mut text = String::new();
let mut ui_enabled = true;
if !Gupax::path_is_file(&self.state.gupax.xmrig_proxy_path) {
ui_enabled = false;
text = format!("Error: {}", XMRIG_PROXY_PATH_NOT_FILE);
} else if !crate::components::update::check_xp_path(
&self.state.gupax.xmrig_proxy_path,
) {
ui_enabled = false;
text = format!("Error: {}", XMRIG_PROXY_PATH_NOT_VALID);
}
ui.set_enabled(ui_enabled);
let color = if ui_enabled { GREEN } else { RED };
if (ui_enabled && key.is_up() && !wants_input)
|| ui
.add_sized(size, Button::new(RichText::new("").color(color)))
.on_hover_text("Start XMRig-Proxy")
.on_disabled_hover_text(text)
.clicked()
{
let _ = lock!(self.og).update_absolute_path();
let _ = self.state.update_absolute_path();
Helper::start_xp(
&self.helper,
&self.state.xmrig_proxy,
&self.state.xmrig,
&self.state.gupax.absolute_xp_path,
);
}
}
});
}
} }
fn status_p2pool(state: ProcessState, ui: &mut Ui, size: Vec2) { fn status_p2pool(state: ProcessState, ui: &mut Ui, size: Vec2) {

View file

@ -176,7 +176,7 @@ path_xmr: {:#?}\n
} }
Tab::Xvb => { Tab::Xvb => {
debug!("App | Entering [XvB] Tab"); debug!("App | Entering [XvB] Tab");
crate::disk::state::Xvb::show(&mut self.state.xvb, self.size, &self.state.p2pool.address, ctx, ui, &self.xvb_api, lock!(self.xvb).state == ProcessState::Alive); crate::disk::state::Xvb::show(&mut self.state.xvb, self.size, &self.state.p2pool.address, ctx, ui, &self.xvb_api, &self.xmrig_api, lock!(self.xvb).state == ProcessState::Alive);
} }
} }
}); });

View file

@ -6,12 +6,19 @@ use log::debug;
use readable::num::Float; use readable::num::Float;
use readable::up::Uptime; use readable::up::Uptime;
use crate::disk::state::{ManualDonationLevel, ManualDonationMetric, XvbMode};
use crate::helper::xrig::xmrig::PubXmrigApi;
use crate::helper::xvb::priv_stats::RuntimeMode;
use crate::helper::xvb::PubXvbApi; use crate::helper::xvb::PubXvbApi;
use crate::regex::num_lines; use crate::regex::num_lines;
use crate::utils::constants::{ use crate::utils::constants::{
GREEN, LIGHT_GRAY, ORANGE, RED, XVB_DONATED_1H_FIELD, XVB_DONATED_24H_FIELD, XVB_FAILURE_FIELD, GREEN, LIGHT_GRAY, ORANGE, RED, XVB_DONATED_1H_FIELD, XVB_DONATED_24H_FIELD,
XVB_HELP, XVB_HERO_SELECT, XVB_ROUND_TYPE_FIELD, XVB_TOKEN_FIELD, XVB_TOKEN_LEN, XVB_URL_RULES, XVB_DONATION_LEVEL_DONOR_HELP, XVB_DONATION_LEVEL_MEGA_DONOR_HELP,
XVB_WINNER_FIELD, XVB_DONATION_LEVEL_VIP_DONOR_HELP, XVB_DONATION_LEVEL_WHALE_DONOR_HELP, XVB_FAILURE_FIELD,
XVB_HELP, XVB_HERO_SELECT, XVB_MANUAL_SLIDER_MANUAL_P2POOL_HELP,
XVB_MANUAL_SLIDER_MANUAL_XVB_HELP, XVB_MODE_MANUAL_DONATION_LEVEL_HELP,
XVB_MODE_MANUAL_P2POOL_HELP, XVB_MODE_MANUAL_XVB_HELP, XVB_ROUND_TYPE_FIELD, XVB_TOKEN_FIELD,
XVB_TOKEN_LEN, XVB_URL_RULES, XVB_WINNER_FIELD,
}; };
use crate::utils::macros::lock; use crate::utils::macros::lock;
use crate::utils::regex::Regexes; use crate::utils::regex::Regexes;
@ -23,6 +30,7 @@ use crate::{
impl crate::disk::state::Xvb { impl crate::disk::state::Xvb {
#[inline(always)] // called once #[inline(always)] // called once
#[allow(clippy::too_many_arguments)]
pub fn show( pub fn show(
&mut self, &mut self,
size: Vec2, size: Vec2,
@ -30,13 +38,17 @@ impl crate::disk::state::Xvb {
_ctx: &egui::Context, _ctx: &egui::Context,
ui: &mut egui::Ui, ui: &mut egui::Ui,
api: &Arc<Mutex<PubXvbApi>>, api: &Arc<Mutex<PubXvbApi>>,
private_stats: bool, gui_api_xmrig: &Arc<Mutex<PubXmrigApi>>,
is_alive: bool,
) { ) {
egui::ScrollArea::vertical().show(ui, |ui| {
let text_edit = size.y / 25.0;
let website_height = size.y / 10.0; let website_height = size.y / 10.0;
let width = size.x; let width = size.x;
let height = size.y; let height = size.y;
let space_h = height / 48.0; let space_h = height / 48.0;
egui::ScrollArea::vertical().show(ui, |ui| {
// logo and website link // logo and website link
ui.vertical_centered(|ui| { ui.vertical_centered(|ui| {
ui.add_sized( ui.add_sized(
@ -48,6 +60,7 @@ impl crate::disk::state::Xvb {
ui.hyperlink_to("XMRvsBeast", XVB_URL); ui.hyperlink_to("XMRvsBeast", XVB_URL);
ui.add_space(space_h); ui.add_space(space_h);
}); });
// console output for log // console output for log
debug!("XvB Tab | Rendering [Console]"); debug!("XvB Tab | Rendering [Console]");
ui.group(|ui| { ui.group(|ui| {
@ -115,26 +128,158 @@ impl crate::disk::state::Xvb {
ui.style_mut().spacing.icon_width_inner = width / 45.0; ui.style_mut().spacing.icon_width_inner = width / 45.0;
ui.style_mut().spacing.icon_width = width / 35.0; ui.style_mut().spacing.icon_width = width / 35.0;
ui.style_mut().spacing.icon_spacing = space_h; ui.style_mut().spacing.icon_spacing = space_h;
if ui.checkbox(&mut self.hero, "Hero Mode").on_hover_text(XVB_HERO_SELECT).clicked() {
// --------------------------- XVB Simple -------------------------------------------
if self.simple {
if ui.checkbox(&mut self.simple_hero_mode, "Hero Mode").on_hover_text(XVB_HERO_SELECT).clicked() {
// also change hero mode of runtime. // also change hero mode of runtime.
lock!(api).stats_priv.runtime_hero_mode = self.hero; lock!(api).stats_priv.runtime_mode = RuntimeMode::Hero;
} else {
lock!(api).stats_priv.runtime_mode = RuntimeMode::Auto;
} }
// need to warn the user if no address is set in p2pool tab }
});
ui.add_space(space_h);
// --------------------------- XVB Advanced -----------------------------------------
if !self.simple {
ui.group(|ui| {
ui.vertical_centered(|ui| {
ui.horizontal(|ui| {
egui::ComboBox::from_label("")
.selected_text(self.mode.to_string())
.show_ui(ui, |ui| {
ui.selectable_value(&mut self.mode, XvbMode::Auto,
XvbMode::Auto.to_string());
ui.selectable_value(&mut self.mode, XvbMode::Hero,
XvbMode::Hero.to_string());
ui.selectable_value(&mut self.mode, XvbMode::ManualXvb,
XvbMode::ManualXvb.to_string())
.on_hover_text(XVB_MODE_MANUAL_XVB_HELP);
ui.selectable_value(&mut self.mode, XvbMode::ManualP2pool,
XvbMode::ManualP2pool.to_string())
.on_hover_text(XVB_MODE_MANUAL_P2POOL_HELP);
ui.selectable_value(&mut self.mode, XvbMode::ManualDonationLevel,
XvbMode::ManualDonationLevel.to_string())
.on_hover_text(XVB_MODE_MANUAL_DONATION_LEVEL_HELP);
});
if self.mode == XvbMode::ManualXvb || self.mode == XvbMode::ManualP2pool {
ui.add_space(space_h);
let default_xmrig_hashrate = match self.manual_donation_metric {
ManualDonationMetric::Hash => 1_000.0,
ManualDonationMetric::Kilo => 1_000_000.0,
ManualDonationMetric::Mega => 1_000_000_000.0
};
let mut hashrate_xmrig = {
if lock!(gui_api_xmrig).hashrate_raw_15m > 0.0 {
lock!(gui_api_xmrig).hashrate_raw_15m
} else if lock!(gui_api_xmrig).hashrate_raw_1m > 0.0 {
lock!(gui_api_xmrig).hashrate_raw_1m
} else if lock!(gui_api_xmrig).hashrate_raw > 0.0 {
lock!(gui_api_xmrig).hashrate_raw
} else {
default_xmrig_hashrate
}
};
// Adjust maximum slider amount based on slider metric
if self.manual_donation_metric == ManualDonationMetric::Kilo {
hashrate_xmrig /= 1000.0;
} else if self.manual_donation_metric == ManualDonationMetric::Mega {
hashrate_xmrig /= 1_000_000.0;
}
let slider_help_text = if self.mode == XvbMode::ManualXvb {
XVB_MANUAL_SLIDER_MANUAL_XVB_HELP
} else {
XVB_MANUAL_SLIDER_MANUAL_P2POOL_HELP
};
ui.horizontal(|ui| {
if ui.add(egui::SelectableLabel::new(self.manual_donation_metric == ManualDonationMetric::Hash, "Hash")).clicked() {
self.manual_donation_metric = ManualDonationMetric::Hash;
self.manual_slider_amount = self.manual_amount_raw;
}
if ui.add(egui::SelectableLabel::new(self.manual_donation_metric == ManualDonationMetric::Kilo, "Kilo")).clicked() {
self.manual_donation_metric = ManualDonationMetric::Kilo;
self.manual_slider_amount = self.manual_amount_raw / 1000.0;
};
if ui.add(egui::SelectableLabel::new(self.manual_donation_metric == ManualDonationMetric::Mega, "Mega")).clicked() {
self.manual_donation_metric = ManualDonationMetric::Mega;
self.manual_slider_amount = self.manual_amount_raw / 1_000_000.0;
};
ui.spacing_mut().slider_width = width * 0.5;
ui.add_sized(
[width, text_edit],
egui::Slider::new(&mut self.manual_slider_amount, 0.0..=(hashrate_xmrig as f64))
.text(self.manual_donation_metric.to_string())
.max_decimals(3)
).on_hover_text(slider_help_text);
});
}
if self.mode == XvbMode::ManualDonationLevel {
ui.radio_value(&mut self.manual_donation_level, ManualDonationLevel::Donor,
ManualDonationLevel::Donor.to_string())
.on_hover_text(XVB_DONATION_LEVEL_DONOR_HELP);
ui.radio_value(&mut self.manual_donation_level, ManualDonationLevel::DonorVIP,
ManualDonationLevel::DonorVIP.to_string())
.on_hover_text(XVB_DONATION_LEVEL_VIP_DONOR_HELP);
ui.radio_value(&mut self.manual_donation_level, ManualDonationLevel::DonorWhale,
ManualDonationLevel::DonorWhale.to_string())
.on_hover_text(XVB_DONATION_LEVEL_WHALE_DONOR_HELP);
ui.radio_value(&mut self.manual_donation_level, ManualDonationLevel::DonorMega,
ManualDonationLevel::DonorMega.to_string())
.on_hover_text(XVB_DONATION_LEVEL_MEGA_DONOR_HELP);
lock!(api).stats_priv.runtime_manual_donation_level = self.manual_donation_level.clone().into();
}
});
});
});
// Update manual_amount_raw based on slider
match self.manual_donation_metric {
ManualDonationMetric::Hash => {
self.manual_amount_raw = self.manual_slider_amount;
},
ManualDonationMetric::Kilo => {
self.manual_amount_raw = self.manual_slider_amount * 1000.0;
},
ManualDonationMetric::Mega => {
self.manual_amount_raw = self.manual_slider_amount * 1_000_000.0;
}
}
// Set runtime_mode & runtime_manual_amount
lock!(api).stats_priv.runtime_mode = self.mode.clone().into();
lock!(api).stats_priv.runtime_manual_amount = self.manual_amount_raw;
}
ui.add_space(space_h);
// need to warn the user if no address is set in p2pool tab
if !Regexes::addr_ok(address) { if !Regexes::addr_ok(address) {
ui.add_space(width / 16.0);
debug!("XvB Tab | Rendering warning text"); debug!("XvB Tab | Rendering warning text");
ui.horizontal_wrapped(|ui|{ ui.horizontal_wrapped(|ui|{
ui.label(RichText::new("You don't have any payout address set in the P2pool Tab ! XvB process needs one to function properly.") ui.label(RichText::new("You don't have any payout address set in the P2pool Tab ! XvB process needs one to function properly.")
.color(ORANGE)); .color(ORANGE));
}); });
} }
});
// private stats // private stats
ui.add_space(space_h); ui.add_space(space_h);
// ui.add_enabled_ui(private_stats, |ui| { // ui.add_enabled_ui(is_alive, |ui| {
ui.add_enabled_ui(private_stats, |ui| { ui.add_enabled_ui(is_alive, |ui| {
let api = &lock!(api); let api = &lock!(api);
let priv_stats = &api.stats_priv; let priv_stats = &api.stats_priv;
let current_node = &api.current_node; let current_node = &api.current_node;
@ -254,6 +399,7 @@ impl crate::disk::state::Xvb {
ui.hyperlink_to("Rules", XVB_URL_RULES) ui.hyperlink_to("Rules", XVB_URL_RULES)
.on_hover_text("Click here to read the rules and understand how the raffle works."); .on_hover_text("Click here to read the rules and understand how the raffle works.");
}); });
}); });
} }
} }

View file

@ -308,10 +308,82 @@ impl Default for XmrigProxy {
} }
} }
#[derive(Clone, Eq, PartialEq, Debug, Deserialize, Serialize, Default)] #[derive(Clone, PartialEq, Debug, Deserialize, Serialize)]
pub struct Xvb { pub struct Xvb {
pub simple: bool,
pub token: String, pub token: String,
pub hero: bool, pub simple_hero_mode: bool,
pub mode: XvbMode,
pub manual_amount_raw: f64,
pub manual_slider_amount: f64,
pub manual_donation_level: ManualDonationLevel,
pub manual_donation_metric: ManualDonationMetric,
}
#[derive(Clone, Eq, PartialEq, Debug, Deserialize, Serialize, Default)]
pub enum XvbMode {
#[default]
Auto,
Hero,
ManualXvb,
ManualP2pool,
ManualDonationLevel,
}
impl Display for XvbMode {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let text = match self {
Self::Auto => "Auto",
Self::Hero => "Hero",
Self::ManualXvb => "Manual Xvb",
Self::ManualP2pool => "Manual P2pool",
Self::ManualDonationLevel => "Manual Donation Level",
};
write!(f, "{}", text)
}
}
#[derive(Clone, Eq, PartialEq, Debug, Deserialize, Serialize, Default)]
pub enum ManualDonationLevel {
#[default]
Donor,
DonorVIP,
DonorWhale,
DonorMega,
}
impl Display for ManualDonationLevel {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let text = match self {
Self::Donor => "Donor",
Self::DonorVIP => "Donor VIP",
Self::DonorWhale => "Donor Whale",
Self::DonorMega => "Donor Mega",
};
write!(f, "{}", text)
}
}
#[derive(Clone, Eq, PartialEq, Debug, Deserialize, Serialize, Default)]
pub enum ManualDonationMetric {
#[default]
Hash,
Kilo,
Mega,
}
impl Display for ManualDonationMetric {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let text = match self {
Self::Hash => "H/s",
Self::Kilo => "KH/s",
Self::Mega => "MH/s",
};
write!(f, "{}", text)
}
} }
#[derive(Clone, Debug, Deserialize, Serialize)] #[derive(Clone, Debug, Deserialize, Serialize)]
@ -434,6 +506,21 @@ impl Default for Xmrig {
} }
} }
impl Default for Xvb {
fn default() -> Self {
Self {
simple: true,
token: String::with_capacity(9),
simple_hero_mode: Default::default(),
mode: Default::default(),
manual_amount_raw: Default::default(),
manual_slider_amount: Default::default(),
manual_donation_level: Default::default(),
manual_donation_metric: Default::default(),
}
}
}
impl Default for Version { impl Default for Version {
fn default() -> Self { fn default() -> Self {
Self { Self {

View file

@ -125,6 +125,13 @@ mod test {
redirect_local_xmrig = true redirect_local_xmrig = true
[xvb] [xvb]
simple = true
simple_hero_mode = true
mode = "Hero"
manual_amount_raw = 1000.0
manual_slider_amount = 1000.0
manual_donation_level = "Donor"
manual_donation_metric = "Hash"
token = "" token = ""
hero = false hero = false
node = "Europe" node = "Europe"

View file

@ -491,13 +491,15 @@ impl Helper {
// 4. Loop as watchdog // 4. Loop as watchdog
let mut first_loop = true; let mut first_loop = true;
let mut last_p2pool_request = tokio::time::Instant::now();
let mut last_status_request = tokio::time::Instant::now();
info!("P2Pool | Entering watchdog mode... woof!"); info!("P2Pool | Entering watchdog mode... woof!");
loop { loop {
// Set timer // Set timer
let now = Instant::now(); let now = Instant::now();
debug!("P2Pool Watchdog | ----------- Start of loop -----------"); debug!("P2Pool Watchdog | ----------- Start of loop -----------");
lock!(gui_api).tick += 1; lock!(gui_api).tick = (last_p2pool_request.elapsed().as_secs() % 60) as u8;
lock!(gui_api).tick_status += 1;
// Check if the process is secretly died without us knowing :) // Check if the process is secretly died without us knowing :)
if check_died( if check_died(
@ -541,7 +543,13 @@ impl Helper {
} }
} }
// If more than 1 minute has passed, read the other API files. // If more than 1 minute has passed, read the other API files.
if lock!(gui_api).tick >= 60 { let last_p2pool_request_expired =
last_p2pool_request.elapsed() >= Duration::from_secs(60);
// need to reload fast to get the first right values after syncing.
if last_p2pool_request_expired
|| (!lock!(pub_api).p2pool_difficulty_u64 > 100_000
&& lock!(process).state == ProcessState::Alive)
{
debug!("P2Pool Watchdog | Attempting [network] & [pool] API file read"); debug!("P2Pool Watchdog | Attempting [network] & [pool] API file read");
if let (Ok(network_api), Ok(pool_api)) = ( if let (Ok(network_api), Ok(pool_api)) = (
Self::path_to_string(&api_path_network, ProcessName::P2pool), Self::path_to_string(&api_path_network, ProcessName::P2pool),
@ -552,11 +560,15 @@ impl Helper {
PrivP2poolPoolApi::from_str(&pool_api), PrivP2poolPoolApi::from_str(&pool_api),
) { ) {
PubP2poolApi::update_from_network_pool(&pub_api, network_api, pool_api); PubP2poolApi::update_from_network_pool(&pub_api, network_api, pool_api);
lock!(gui_api).tick = 0; last_p2pool_request = tokio::time::Instant::now();
} }
} }
} }
if (lock!(gui_api).tick_status >= 60 || first_loop)
let last_status_request_expired =
last_status_request.elapsed() >= Duration::from_secs(60);
if (last_status_request_expired || first_loop)
&& lock!(process).state == ProcessState::Alive && lock!(process).state == ProcessState::Alive
{ {
debug!("P2Pool Watchdog | Reading status output of p2pool node"); debug!("P2Pool Watchdog | Reading status output of p2pool node");
@ -572,7 +584,7 @@ impl Helper {
if let Err(e) = stdin.flush() { if let Err(e) = stdin.flush() {
error!("P2Pool Watchdog | STDIN flush error: {}", e); error!("P2Pool Watchdog | STDIN flush error: {}", e);
} }
lock!(gui_api).tick_status = 0; last_status_request = tokio::time::Instant::now();
} }
// Sleep (only if 900ms hasn't passed) // Sleep (only if 900ms hasn't passed)
@ -663,9 +675,6 @@ pub struct PubP2poolApi {
// Tick. Every loop this gets incremented. // Tick. Every loop this gets incremented.
// At 60, it indicated we should read the below API files. // At 60, it indicated we should read the below API files.
pub tick: u8, pub tick: u8,
// Tick. Every loop this gets incremented.
// At 10, it indicated we should fetch data from status
pub tick_status: u8,
// Network API // Network API
pub monero_difficulty: HumanNumber, // e.g: [15,000,000] pub monero_difficulty: HumanNumber, // e.g: [15,000,000]
pub monero_hashrate: HumanNumber, // e.g: [1.000 GH/s] pub monero_hashrate: HumanNumber, // e.g: [1.000 GH/s]
@ -716,7 +725,6 @@ impl PubP2poolApi {
current_effort: HumanNumber::unknown(), current_effort: HumanNumber::unknown(),
connections: HumanNumber::unknown(), connections: HumanNumber::unknown(),
tick: 0, tick: 0,
tick_status: 0,
user_p2pool_hashrate_u64: 0, user_p2pool_hashrate_u64: 0,
p2pool_difficulty_u64: 0, p2pool_difficulty_u64: 0,
monero_difficulty_u64: 0, monero_difficulty_u64: 0,
@ -755,7 +763,6 @@ impl PubP2poolApi {
*gui_api = Self { *gui_api = Self {
output, output,
tick: std::mem::take(&mut gui_api.tick), tick: std::mem::take(&mut gui_api.tick),
tick_status: std::mem::take(&mut gui_api.tick_status),
sidechain_shares: std::mem::take(&mut gui_api.sidechain_shares), sidechain_shares: std::mem::take(&mut gui_api.sidechain_shares),
sidechain_ehr: std::mem::take(&mut gui_api.sidechain_ehr), sidechain_ehr: std::mem::take(&mut gui_api.sidechain_ehr),
..pub_api.clone() ..pub_api.clone()
@ -993,66 +1000,66 @@ impl PubP2poolApi {
// let blanks = " ".repeat(60 - (self.tick - 1)); // let blanks = " ".repeat(60 - (self.tick - 1));
// [use crate::PubP2poolApi;use crate::PubP2poolApi;"[", &stars, &blanks, "]"].concat().as_str() // [use crate::PubP2poolApi;use crate::PubP2poolApi;"[", &stars, &blanks, "]"].concat().as_str()
match self.tick { match self.tick {
1 => "[ ]", 0 => "[ ]",
2 => "[* ]", 1 => "[* ]",
3 => "[** ]", 2 => "[** ]",
4 => "[*** ]", 3 => "[*** ]",
5 => "[**** ]", 4 => "[**** ]",
6 => "[***** ]", 5 => "[***** ]",
7 => "[****** ]", 6 => "[****** ]",
8 => "[******* ]", 7 => "[******* ]",
9 => "[******** ]", 8 => "[******** ]",
10 => "[********* ]", 9 => "[********* ]",
11 => "[********** ]", 10 => "[********** ]",
12 => "[*********** ]", 11 => "[*********** ]",
13 => "[************ ]", 12 => "[************ ]",
14 => "[************* ]", 13 => "[************* ]",
15 => "[************** ]", 14 => "[************** ]",
16 => "[*************** ]", 15 => "[*************** ]",
17 => "[**************** ]", 16 => "[**************** ]",
18 => "[***************** ]", 17 => "[***************** ]",
19 => "[****************** ]", 18 => "[****************** ]",
20 => "[******************* ]", 19 => "[******************* ]",
21 => "[******************** ]", 20 => "[******************** ]",
22 => "[********************* ]", 21 => "[********************* ]",
23 => "[********************** ]", 22 => "[********************** ]",
24 => "[*********************** ]", 23 => "[*********************** ]",
25 => "[************************ ]", 24 => "[************************ ]",
26 => "[************************* ]", 25 => "[************************* ]",
27 => "[************************** ]", 26 => "[************************** ]",
28 => "[*************************** ]", 27 => "[*************************** ]",
29 => "[**************************** ]", 28 => "[**************************** ]",
30 => "[***************************** ]", 29 => "[***************************** ]",
31 => "[****************************** ]", 30 => "[****************************** ]",
32 => "[******************************* ]", 31 => "[******************************* ]",
33 => "[******************************** ]", 32 => "[******************************** ]",
34 => "[********************************* ]", 33 => "[********************************* ]",
35 => "[********************************** ]", 34 => "[********************************** ]",
36 => "[*********************************** ]", 35 => "[*********************************** ]",
37 => "[************************************ ]", 36 => "[************************************ ]",
38 => "[************************************* ]", 37 => "[************************************* ]",
39 => "[************************************** ]", 38 => "[************************************** ]",
40 => "[*************************************** ]", 39 => "[*************************************** ]",
41 => "[**************************************** ]", 40 => "[**************************************** ]",
42 => "[***************************************** ]", 41 => "[***************************************** ]",
43 => "[****************************************** ]", 42 => "[****************************************** ]",
44 => "[******************************************* ]", 43 => "[******************************************* ]",
45 => "[******************************************** ]", 44 => "[******************************************** ]",
46 => "[********************************************* ]", 45 => "[********************************************* ]",
47 => "[********************************************** ]", 46 => "[********************************************** ]",
48 => "[*********************************************** ]", 47 => "[*********************************************** ]",
49 => "[************************************************ ]", 48 => "[************************************************ ]",
50 => "[************************************************* ]", 49 => "[************************************************* ]",
51 => "[************************************************** ]", 50 => "[************************************************** ]",
52 => "[*************************************************** ]", 51 => "[*************************************************** ]",
53 => "[**************************************************** ]", 52 => "[**************************************************** ]",
54 => "[***************************************************** ]", 53 => "[***************************************************** ]",
55 => "[****************************************************** ]", 54 => "[****************************************************** ]",
56 => "[******************************************************* ]", 55 => "[******************************************************* ]",
57 => "[******************************************************** ]", 56 => "[******************************************************** ]",
58 => "[********************************************************* ]", 57 => "[********************************************************* ]",
59 => "[********************************************************** ]", 58 => "[********************************************************** ]",
60 => "[*********************************************************** ]", 59 => "[*********************************************************** ]",
_ => "[************************************************************]", _ => "[************************************************************]",
} }
} }

View file

@ -1,9 +1,11 @@
#[cfg(test)] #[cfg(test)]
mod test { mod test {
use crate::helper::xrig::xmrig_proxy::PubXmrigProxyApi;
use crate::helper::xvb::algorithm::Algorithm;
use crate::helper::{ use crate::helper::{
p2pool::{PrivP2poolLocalApi, PrivP2poolNetworkApi}, p2pool::{PrivP2poolLocalApi, PrivP2poolNetworkApi},
xvb::{algorithm::calcul_donated_time, rounds::round_type}, xvb::{priv_stats::RuntimeDonationLevel, priv_stats::RuntimeMode},
Helper, Process, ProcessName, ProcessState, Helper, Process, ProcessName, ProcessState,
}; };
@ -509,9 +511,8 @@ Uptime = 0h 2m 4s
use crate::{ use crate::{
disk::state::P2pool, disk::state::P2pool,
helper::{p2pool::PubP2poolApi, xrig::xmrig::PubXmrigApi, xvb::rounds::XvbRound}, helper::{p2pool::PubP2poolApi, xrig::xmrig::PubXmrigApi},
macros::lock, macros::lock,
XVB_TIME_ALGO,
}; };
use crate::helper::xvb::{public_stats::XvbPubStats, PubXvbApi}; use crate::helper::xvb::{public_stats::XvbPubStats, PubXvbApi};
@ -527,254 +528,230 @@ Uptime = 0h 2m 4s
async fn corr(client: &Client) -> XvbPubStats { async fn corr(client: &Client) -> XvbPubStats {
XvbPubStats::request_api(client).await.unwrap() XvbPubStats::request_api(client).await.unwrap()
} }
#[test] #[test]
fn algorithm_time_given() { fn test_manual_xvb_mode() {
let client = reqwest::Client::new();
let pub_api = Arc::new(Mutex::new(PubXvbApi::new()));
let gui_api_xvb = Arc::new(Mutex::new(PubXvbApi::new())); let gui_api_xvb = Arc::new(Mutex::new(PubXvbApi::new()));
let gui_api_p2pool = Arc::new(Mutex::new(PubP2poolApi::new()));
let gui_api_xmrig = Arc::new(Mutex::new(PubXmrigApi::new())); let gui_api_xmrig = Arc::new(Mutex::new(PubXmrigApi::new()));
let gui_api_xp = Arc::new(Mutex::new(PubXmrigProxyApi::new()));
let gui_api_p2pool = Arc::new(Mutex::new(PubP2poolApi::new()));
let token_xmrig = "12345678";
let state_p2pool = P2pool::default(); let state_p2pool = P2pool::default();
lock!(gui_api_p2pool).p2pool_difficulty_u64 = 95000000; let time_donated = Arc::new(Mutex::new(u32::default()));
let rig = "test_rig";
let xp_alive = false;
let share = 1; let share = 1;
// verify that if one share found (enough for vip round) but not enough for donor round, no time will be given to xvb, except if in hero mode.
// 15mn average HR of xmrig is 5kH/s lock!(gui_api_xmrig).hashrate_raw_15m = 10000.0;
lock!(gui_api_xvb).stats_priv.donor_1hr_avg = 0.0; lock!(gui_api_xvb).stats_priv.runtime_mode = RuntimeMode::ManualXvb;
lock!(gui_api_xmrig).hashrate_raw_15m = 5000.0; lock!(gui_api_xvb).stats_priv.runtime_manual_amount = 1000.0;
lock!(gui_api_xvb).stats_priv.runtime_hero_mode = false;
let given_time = calcul_donated_time( let algo = Algorithm::new(
lock!(gui_api_xmrig).hashrate_raw_15m, &client,
&gui_api_p2pool, &pub_api,
&gui_api_xvb, &gui_api_xvb,
&state_p2pool, &gui_api_xmrig,
); &gui_api_xp,
// verify that default mode will give x seconds
assert_eq!(given_time, 0);
// given time should always be less than XVB_TIME_ALGO
assert!(given_time < XVB_TIME_ALGO);
// verify that right round should be detected.
lock!(gui_api_xvb).stats_priv.donor_1hr_avg = ((given_time as f32 / XVB_TIME_ALGO as f32)
* lock!(gui_api_xmrig).hashrate_raw_15m)
/ 1000.0;
lock!(gui_api_xvb).stats_priv.donor_24hr_avg = ((given_time as f32 / XVB_TIME_ALGO as f32)
* lock!(gui_api_xmrig).hashrate_raw_15m)
/ 1000.0;
assert_eq!(round_type(share, &gui_api_xvb), Some(XvbRound::Vip));
// verify that hero mode will give x seconds
lock!(gui_api_xvb).stats_priv.runtime_hero_mode = true;
let given_time = calcul_donated_time(
lock!(gui_api_xmrig).hashrate_raw_15m,
&gui_api_p2pool, &gui_api_p2pool,
&gui_api_xvb, token_xmrig,
&state_p2pool, &state_p2pool,
share,
&time_donated,
rig,
xp_alive,
); );
assert_eq!(given_time, 45);
// verify that right round should be detected. assert_eq!(algo.stats.target_donation_hashrate, 1000.0);
lock!(gui_api_xvb).stats_priv.donor_1hr_avg = ((given_time as f32 / XVB_TIME_ALGO as f32) }
* lock!(gui_api_xmrig).hashrate_raw_15m)
/ 1000.0; #[test]
lock!(gui_api_xvb).stats_priv.donor_24hr_avg = ((given_time as f32 / XVB_TIME_ALGO as f32) fn test_manual_p2pool_mode() {
* lock!(gui_api_xmrig).hashrate_raw_15m) let client = reqwest::Client::new();
/ 1000.0; let pub_api = Arc::new(Mutex::new(PubXvbApi::new()));
assert_eq!(round_type(share, &gui_api_xvb), Some(XvbRound::Vip)); let gui_api_xvb = Arc::new(Mutex::new(PubXvbApi::new()));
// verify that if one share and not enough for donor vip round (should be in donor round), right amount of time will be given to xvb for default and hero mode let gui_api_xmrig = Arc::new(Mutex::new(PubXmrigApi::new()));
lock!(gui_api_xvb).stats_priv.donor_1hr_avg = 0.0; let gui_api_xp = Arc::new(Mutex::new(PubXmrigProxyApi::new()));
lock!(gui_api_xmrig).hashrate_raw_15m = 8000.0; let gui_api_p2pool = Arc::new(Mutex::new(PubP2poolApi::new()));
lock!(gui_api_xvb).stats_priv.runtime_hero_mode = false; let token_xmrig = "12345678";
let given_time = calcul_donated_time( let state_p2pool = P2pool::default();
lock!(gui_api_xmrig).hashrate_raw_15m, let time_donated = Arc::new(Mutex::new(u32::default()));
let rig = "test_rig";
let xp_alive = false;
let share = 1;
lock!(gui_api_xmrig).hashrate_raw_15m = 10000.0;
lock!(gui_api_xvb).stats_priv.runtime_mode = RuntimeMode::ManualP2pool;
lock!(gui_api_xvb).stats_priv.runtime_manual_amount = 1000.0;
let algo = Algorithm::new(
&client,
&pub_api,
&gui_api_xvb,
&gui_api_xmrig,
&gui_api_xp,
&gui_api_p2pool, &gui_api_p2pool,
&gui_api_xvb, token_xmrig,
&state_p2pool, &state_p2pool,
share,
&time_donated,
rig,
xp_alive,
); );
// verify that default mode will give x seconds
assert_eq!(given_time, 75); assert_eq!(algo.stats.target_donation_hashrate, 9000.0);
// given time should always be less than XVB_TIME_ALGO }
assert!(given_time < XVB_TIME_ALGO);
// verify that right round should be detected. #[test]
lock!(gui_api_xvb).stats_priv.donor_1hr_avg = ((given_time as f32 / XVB_TIME_ALGO as f32) fn test_manual_donor_level_mode_donor() {
* lock!(gui_api_xmrig).hashrate_raw_15m) let client = reqwest::Client::new();
/ 1000.0; let pub_api = Arc::new(Mutex::new(PubXvbApi::new()));
lock!(gui_api_xvb).stats_priv.donor_24hr_avg = ((given_time as f32 / XVB_TIME_ALGO as f32) let gui_api_xvb = Arc::new(Mutex::new(PubXvbApi::new()));
* lock!(gui_api_xmrig).hashrate_raw_15m) let gui_api_xmrig = Arc::new(Mutex::new(PubXmrigApi::new()));
/ 1000.0; let gui_api_xp = Arc::new(Mutex::new(PubXmrigProxyApi::new()));
assert_eq!(round_type(share, &gui_api_xvb), Some(XvbRound::Donor)); let gui_api_p2pool = Arc::new(Mutex::new(PubP2poolApi::new()));
// verify that hero mode will give x seconds let token_xmrig = "12345678";
lock!(gui_api_xvb).stats_priv.runtime_hero_mode = true; let state_p2pool = P2pool::default();
let given_time = calcul_donated_time( let time_donated = Arc::new(Mutex::new(u32::default()));
lock!(gui_api_xmrig).hashrate_raw_15m, let rig = "test_rig";
let xp_alive = false;
let share = 1;
lock!(gui_api_xmrig).hashrate_raw_15m = 10000.0;
lock!(gui_api_xvb).stats_priv.runtime_mode = RuntimeMode::ManualDonationLevel;
lock!(gui_api_xvb).stats_priv.runtime_manual_amount = 1000.0;
lock!(gui_api_xvb).stats_priv.runtime_manual_donation_level = RuntimeDonationLevel::Donor;
let algo = Algorithm::new(
&client,
&pub_api,
&gui_api_xvb,
&gui_api_xmrig,
&gui_api_xp,
&gui_api_p2pool, &gui_api_p2pool,
&gui_api_xvb, token_xmrig,
&state_p2pool, &state_p2pool,
share,
&time_donated,
rig,
xp_alive,
); );
assert_eq!(given_time, 253);
// verify that right round should be detected. assert_eq!(algo.stats.target_donation_hashrate, 1000.0);
lock!(gui_api_xvb).stats_priv.donor_1hr_avg = ((given_time as f32 / XVB_TIME_ALGO as f32) }
* lock!(gui_api_xmrig).hashrate_raw_15m)
/ 1000.0; #[test]
lock!(gui_api_xvb).stats_priv.donor_24hr_avg = ((given_time as f32 / XVB_TIME_ALGO as f32) fn test_auto_mode() {
* lock!(gui_api_xmrig).hashrate_raw_15m) let client = reqwest::Client::new();
/ 1000.0; let pub_api = Arc::new(Mutex::new(PubXvbApi::new()));
assert_eq!(round_type(share, &gui_api_xvb), Some(XvbRound::Donor)); let gui_api_xvb = Arc::new(Mutex::new(PubXvbApi::new()));
// verify that if one share and not enough for donor whale round(should be in donor vip), right amount of time will be given to xvb for default and hero mode let gui_api_xmrig = Arc::new(Mutex::new(PubXmrigApi::new()));
lock!(gui_api_xvb).stats_priv.donor_1hr_avg = 0.0; let gui_api_xp = Arc::new(Mutex::new(PubXmrigProxyApi::new()));
lock!(gui_api_xmrig).hashrate_raw_15m = 19000.0; let gui_api_p2pool = Arc::new(Mutex::new(PubP2poolApi::new()));
lock!(gui_api_xvb).stats_priv.runtime_hero_mode = false; let token_xmrig = "12345678";
let given_time = calcul_donated_time( let state_p2pool = P2pool::default();
lock!(gui_api_xmrig).hashrate_raw_15m, let time_donated = Arc::new(Mutex::new(u32::default()));
let rig = "test_rig";
let xp_alive = false;
let share = 1;
lock!(gui_api_p2pool).p2pool_difficulty_u64 = 9_000_000;
lock!(gui_api_xmrig).hashrate_raw_15m = 20000.0;
lock!(gui_api_xvb).stats_priv.runtime_mode = RuntimeMode::Auto;
let algo = Algorithm::new(
&client,
&pub_api,
&gui_api_xvb,
&gui_api_xmrig,
&gui_api_xp,
&gui_api_p2pool, &gui_api_p2pool,
&gui_api_xvb, token_xmrig,
&state_p2pool, &state_p2pool,
share,
&time_donated,
rig,
xp_alive,
); );
// verify that default mode will give x seconds
assert_eq!(given_time, 316); assert_eq!(algo.stats.target_donation_hashrate, 10000.0);
// given time should always be less than XVB_TIME_ALGO
assert!(given_time < XVB_TIME_ALGO); lock!(gui_api_p2pool).p2pool_difficulty_u64 = 95_000_000;
// verify that right round should be detected. lock!(gui_api_xmrig).hashrate_raw_15m = 10000.0;
lock!(gui_api_xvb).stats_priv.donor_1hr_avg = ((given_time as f32 / XVB_TIME_ALGO as f32) lock!(gui_api_xvb).stats_priv.runtime_mode = RuntimeMode::Auto;
* lock!(gui_api_xmrig).hashrate_raw_15m)
/ 1000.0; let algo = Algorithm::new(
lock!(gui_api_xvb).stats_priv.donor_24hr_avg = ((given_time as f32 / XVB_TIME_ALGO as f32) &client,
* lock!(gui_api_xmrig).hashrate_raw_15m) &pub_api,
/ 1000.0; &gui_api_xvb,
assert_eq!(round_type(share, &gui_api_xvb), Some(XvbRound::DonorVip)); &gui_api_xmrig,
// verify that hero mode will give x seconds &gui_api_xp,
lock!(gui_api_xvb).stats_priv.runtime_hero_mode = true;
let given_time = calcul_donated_time(
lock!(gui_api_xmrig).hashrate_raw_15m,
&gui_api_p2pool, &gui_api_p2pool,
&gui_api_xvb, token_xmrig,
&state_p2pool, &state_p2pool,
share,
&time_donated,
rig,
xp_alive,
); );
assert_eq!(given_time, 454);
// verify that right round should be detected. assert_eq!(algo.stats.target_donation_hashrate, 1000.0);
lock!(gui_api_xvb).stats_priv.donor_1hr_avg = ((given_time as f32 / XVB_TIME_ALGO as f32) }
* lock!(gui_api_xmrig).hashrate_raw_15m)
/ 1000.0; #[test]
lock!(gui_api_xvb).stats_priv.donor_24hr_avg = ((given_time as f32 / XVB_TIME_ALGO as f32) fn test_hero_mode() {
* lock!(gui_api_xmrig).hashrate_raw_15m) let client = reqwest::Client::new();
/ 1000.0; let pub_api = Arc::new(Mutex::new(PubXvbApi::new()));
assert_eq!(round_type(share, &gui_api_xvb), Some(XvbRound::DonorVip)); let gui_api_xvb = Arc::new(Mutex::new(PubXvbApi::new()));
// verify that if one share and not enough for donor mega round, right amount of time will be given to xvb for default and hero mode let gui_api_xmrig = Arc::new(Mutex::new(PubXmrigApi::new()));
lock!(gui_api_xvb).stats_priv.donor_1hr_avg = 0.0; let gui_api_xp = Arc::new(Mutex::new(PubXmrigProxyApi::new()));
lock!(gui_api_xmrig).hashrate_raw_15m = 105000.0; let gui_api_p2pool = Arc::new(Mutex::new(PubP2poolApi::new()));
lock!(gui_api_xvb).stats_priv.runtime_hero_mode = false; let token_xmrig = "12345678";
let given_time = calcul_donated_time( let state_p2pool = P2pool::default();
lock!(gui_api_xmrig).hashrate_raw_15m, let time_donated = Arc::new(Mutex::new(u32::default()));
let rig = "test_rig";
let xp_alive = false;
let share = 1;
lock!(gui_api_p2pool).p2pool_difficulty_u64 = 95_000_000;
lock!(gui_api_xmrig).hashrate_raw_15m = 20000.0;
lock!(gui_api_xvb).stats_priv.runtime_mode = RuntimeMode::Hero;
let algo = Algorithm::new(
&client,
&pub_api,
&gui_api_xvb,
&gui_api_xmrig,
&gui_api_xp,
&gui_api_p2pool, &gui_api_p2pool,
&gui_api_xvb, token_xmrig,
&state_p2pool, &state_p2pool,
share,
&time_donated,
rig,
xp_alive,
); );
// verify that default mode will give x seconds
assert_eq!(given_time, 572); assert_eq!(algo.stats.target_donation_hashrate, 15382.1);
// given time should always be less than XVB_TIME_ALGO
assert!(given_time < XVB_TIME_ALGO); lock!(gui_api_p2pool).sidechain_ehr = 25000.0;
// verify that right round should be detected.
lock!(gui_api_xvb).stats_priv.donor_1hr_avg = ((given_time as f32 / XVB_TIME_ALGO as f32) let algo = Algorithm::new(
* lock!(gui_api_xmrig).hashrate_raw_15m) &client,
/ 1000.0; &pub_api,
lock!(gui_api_xvb).stats_priv.donor_24hr_avg = ((given_time as f32 / XVB_TIME_ALGO as f32) &gui_api_xvb,
* lock!(gui_api_xmrig).hashrate_raw_15m) &gui_api_xmrig,
/ 1000.0; &gui_api_xp,
assert_eq!(round_type(share, &gui_api_xvb), Some(XvbRound::DonorWhale));
// verify that hero mode will give x seconds
lock!(gui_api_xvb).stats_priv.runtime_hero_mode = true;
let given_time = calcul_donated_time(
lock!(gui_api_xmrig).hashrate_raw_15m,
&gui_api_p2pool, &gui_api_p2pool,
&gui_api_xvb, token_xmrig,
&state_p2pool, &state_p2pool,
share,
&time_donated,
rig,
xp_alive,
); );
assert_eq!(given_time, 573);
// verify that right round should be detected. assert_eq!(algo.stats.target_donation_hashrate, 20000.0);
lock!(gui_api_xvb).stats_priv.donor_1hr_avg = ((given_time as f32 / XVB_TIME_ALGO as f32)
* lock!(gui_api_xmrig).hashrate_raw_15m)
/ 1000.0;
lock!(gui_api_xvb).stats_priv.donor_24hr_avg = ((given_time as f32 / XVB_TIME_ALGO as f32)
* lock!(gui_api_xmrig).hashrate_raw_15m)
/ 1000.0;
assert_eq!(round_type(share, &gui_api_xvb), Some(XvbRound::DonorWhale));
// verify that if one share and enough for donor mega round, right amount of time will be given to xvb for default and hero mode
lock!(gui_api_xvb).stats_priv.donor_1hr_avg = 0.0;
lock!(gui_api_xmrig).hashrate_raw_15m = 1205000.0;
lock!(gui_api_xvb).stats_priv.runtime_hero_mode = false;
let given_time = calcul_donated_time(
lock!(gui_api_xmrig).hashrate_raw_15m,
&gui_api_p2pool,
&gui_api_xvb,
&state_p2pool,
);
// verify that default mode will give x seconds
assert_eq!(given_time, 498);
// given time should always be less than XVB_TIME_ALGO
assert!(given_time < XVB_TIME_ALGO);
// verify that right round should be detected.
lock!(gui_api_xvb).stats_priv.donor_1hr_avg = ((given_time as f32 / XVB_TIME_ALGO as f32)
* lock!(gui_api_xmrig).hashrate_raw_15m)
/ 1000.0;
lock!(gui_api_xvb).stats_priv.donor_24hr_avg = ((given_time as f32 / XVB_TIME_ALGO as f32)
* lock!(gui_api_xmrig).hashrate_raw_15m)
/ 1000.0;
assert_eq!(round_type(share, &gui_api_xvb), Some(XvbRound::DonorMega));
// verify that hero mode will give x seconds
lock!(gui_api_xvb).stats_priv.runtime_hero_mode = true;
let given_time = calcul_donated_time(
lock!(gui_api_xmrig).hashrate_raw_15m,
&gui_api_p2pool,
&gui_api_xvb,
&state_p2pool,
);
assert_eq!(given_time, 597);
// verify that right round should be detected.
lock!(gui_api_xvb).stats_priv.donor_1hr_avg = ((given_time as f32 / XVB_TIME_ALGO as f32)
* lock!(gui_api_xmrig).hashrate_raw_15m)
/ 1000.0;
lock!(gui_api_xvb).stats_priv.donor_24hr_avg = ((given_time as f32 / XVB_TIME_ALGO as f32)
* lock!(gui_api_xmrig).hashrate_raw_15m)
/ 1000.0;
assert_eq!(round_type(share, &gui_api_xvb), Some(XvbRound::DonorMega));
// verify that if one share and enough for donor vp round if XvB oHR is given, right amount of time will be given to xvb for default and hero mode
lock!(gui_api_xvb).output.clear();
lock!(gui_api_xmrig).hashrate_raw_15m = 12500.0;
lock!(gui_api_xvb).stats_priv.donor_1hr_avg = 5.0;
lock!(gui_api_xvb).stats_priv.runtime_hero_mode = false;
let given_time = calcul_donated_time(
lock!(gui_api_xmrig).hashrate_raw_15m,
&gui_api_p2pool,
&gui_api_xvb,
&state_p2pool,
);
// verify that default mode will give x seconds
assert_eq!(given_time, 240);
// given time should always be less than XVB_TIME_ALGO
assert!(given_time < XVB_TIME_ALGO);
// verify that right round should be detected.
lock!(gui_api_xvb).stats_priv.donor_1hr_avg =
(((given_time as f32 / XVB_TIME_ALGO as f32) * lock!(gui_api_xmrig).hashrate_raw_15m)
+ 5000.0)
/ 1000.0;
lock!(gui_api_xvb).stats_priv.donor_24hr_avg =
(((given_time as f32 / XVB_TIME_ALGO as f32) * lock!(gui_api_xmrig).hashrate_raw_15m)
+ 5000.0)
/ 1000.0;
assert_eq!(round_type(share, &gui_api_xvb), Some(XvbRound::DonorVip));
// verify that hero mode will give x seconds
lock!(gui_api_xvb).stats_priv.donor_1hr_avg = 5.0;
lock!(gui_api_xvb).stats_priv.runtime_hero_mode = true;
let given_time = calcul_donated_time(
lock!(gui_api_xmrig).hashrate_raw_15m,
&gui_api_p2pool,
&gui_api_xvb,
&state_p2pool,
);
assert_eq!(given_time, 378);
// verify that right round should be detected.
lock!(gui_api_xvb).stats_priv.donor_1hr_avg =
(((given_time as f32 / XVB_TIME_ALGO as f32) * lock!(gui_api_xmrig).hashrate_raw_15m)
+ 5000.0)
/ 1000.0;
lock!(gui_api_xvb).stats_priv.donor_24hr_avg =
(((given_time as f32 / XVB_TIME_ALGO as f32) * lock!(gui_api_xmrig).hashrate_raw_15m)
+ 5000.0)
/ 1000.0;
assert_eq!(round_type(share, &gui_api_xvb), Some(XvbRound::DonorVip));
} }
} }

View file

@ -70,7 +70,11 @@ impl Helper {
// updating current node to None, will stop sending signal of FailedNode until new node is set // updating current node to None, will stop sending signal of FailedNode until new node is set
// send signal to update node. // send signal to update node.
warn!("XMRig PTY Parse | node is offline, sending signal to update nodes."); warn!("XMRig PTY Parse | node is offline, sending signal to update nodes.");
// update nodes only if we were not mining on p2pool.
// if xmrig stop, xvb will react in any case.
if current_node != XvbNode::P2pool {
lock!(process_xvb).signal = ProcessSignal::UpdateNodes(current_node); lock!(process_xvb).signal = ProcessSignal::UpdateNodes(current_node);
}
lock!(pub_api_xvb).current_node = None; lock!(pub_api_xvb).current_node = None;
} }
} }

View file

@ -72,7 +72,9 @@ impl Helper {
warn!( warn!(
"XMRig-Proxy PTY Parse | node is offline, sending signal to update nodes." "XMRig-Proxy PTY Parse | node is offline, sending signal to update nodes."
); );
if current_node != XvbNode::P2pool {
lock!(process_xvb).signal = ProcessSignal::UpdateNodes(current_node); lock!(process_xvb).signal = ProcessSignal::UpdateNodes(current_node);
}
lock!(pub_api_xvb).current_node = None; lock!(pub_api_xvb).current_node = None;
} }
} }
@ -212,7 +214,7 @@ impl Helper {
state_xmrig: &Xmrig, state_xmrig: &Xmrig,
path: &Path, path: &Path,
) { ) {
info!("XMRig | Attempting to restart..."); info!("XMRig-Proxy | Attempting to restart...");
lock2!(helper, xmrig_proxy).state = ProcessState::Middle; lock2!(helper, xmrig_proxy).state = ProcessState::Middle;
lock2!(helper, xmrig_proxy).signal = ProcessSignal::Restart; lock2!(helper, xmrig_proxy).signal = ProcessSignal::Restart;
@ -227,10 +229,10 @@ impl Helper {
sleep!(1000); sleep!(1000);
} }
// Ok, process is not alive, start the new one! // Ok, process is not alive, start the new one!
info!("XMRig_proxy | Old process seems dead, starting new one!"); info!("XMRig-Proxy | Old process seems dead, starting new one!");
Self::start_xp(&helper, &state, &state_xmrig, &path); Self::start_xp(&helper, &state, &state_xmrig, &path);
}); });
info!("XMRig | Restart ... OK"); info!("XMRig-Proxy | Restart ... OK");
} }
pub fn start_xp( pub fn start_xp(
helper: &Arc<Mutex<Self>>, helper: &Arc<Mutex<Self>>,
@ -354,7 +356,7 @@ impl Helper {
if let Err(e) = writeln!(stdin, "c") { if let Err(e) = writeln!(stdin, "c") {
error!("P2Pool Watchdog | STDIN error: {}", e); error!("P2Pool Watchdog | STDIN error: {}", e);
} }
info!("XMRig | Entering watchdog mode... woof!"); info!("XMRig-Proxy | Entering watchdog mode... woof!");
loop { loop {
let now = Instant::now(); let now = Instant::now();
debug!("XMRig-Proxy Watchdog | ----------- Start of loop -----------"); debug!("XMRig-Proxy Watchdog | ----------- Start of loop -----------");

View file

@ -1,7 +1,6 @@
use crate::helper::xrig::xmrig_proxy::PubXmrigProxyApi; use crate::helper::xrig::xmrig_proxy::PubXmrigProxyApi;
use crate::helper::xvb::api_url_xmrig; use crate::helper::xvb::api_url_xmrig;
use crate::helper::xvb::current_controllable_hr; use crate::helper::xvb::current_controllable_hr;
use crate::helper::ProcessName;
use crate::miscs::output_console; use crate::miscs::output_console;
use crate::miscs::output_console_without_time; use crate::miscs::output_console_without_time;
use std::{ use std::{
@ -9,8 +8,7 @@ use std::{
time::Duration, time::Duration,
}; };
use log::{debug, info, warn}; use log::{info, warn};
use readable::num::Float;
use reqwest::Client; use reqwest::Client;
use tokio::time::sleep; use tokio::time::sleep;
@ -18,7 +16,7 @@ use crate::{
helper::{ helper::{
p2pool::PubP2poolApi, p2pool::PubP2poolApi,
xrig::{update_xmrig_config, xmrig::PubXmrigApi}, xrig::{update_xmrig_config, xmrig::PubXmrigApi},
xvb::nodes::XvbNode, xvb::{nodes::XvbNode, priv_stats::RuntimeMode},
}, },
macros::lock, macros::lock,
BLOCK_PPLNS_WINDOW_MAIN, BLOCK_PPLNS_WINDOW_MINI, SECOND_PER_BLOCK_P2POOL, XVB_BUFFER, BLOCK_PPLNS_WINDOW_MAIN, BLOCK_PPLNS_WINDOW_MINI, SECOND_PER_BLOCK_P2POOL, XVB_BUFFER,
@ -26,241 +24,12 @@ use crate::{
XVB_ROUND_DONOR_WHALE_MIN_HR, XVB_TIME_ALGO, XVB_ROUND_DONOR_WHALE_MIN_HR, XVB_TIME_ALGO,
}; };
use super::{PubXvbApi, SamplesAverageHour}; use super::{priv_stats::RuntimeDonationLevel, PubXvbApi, SamplesAverageHour};
pub(crate) fn calcul_donated_time(
lhr: f32,
gui_api_p2pool: &Arc<Mutex<PubP2poolApi>>,
gui_api_xvb: &Arc<Mutex<PubXvbApi>>,
state_p2pool: &crate::disk::state::P2pool,
) -> u32 {
let p2pool_ehr = lock!(gui_api_p2pool).sidechain_ehr;
// what if ehr stay still for the next ten minutes ? mHR will augment every ten minutes because it thinks that oHR is decreasing.
//
let avg_hr = calc_last_hour_avg_hash_rate(&lock!(gui_api_xvb).p2pool_sent_last_hour_samples);
let mut p2pool_ohr = p2pool_ehr - avg_hr;
if p2pool_ohr < 0.0 {
p2pool_ohr = 0.0;
}
info!("XvB Process | p2pool sidechain HR - last hour average HR = estimated outside HR\n{p2pool_ehr} - {avg_hr} = {p2pool_ohr}");
let mut min_hr = minimum_hashrate_share(
lock!(gui_api_p2pool).p2pool_difficulty_u64,
state_p2pool.mini,
p2pool_ohr,
);
if min_hr.is_sign_negative() {
info!("XvB Process | if minimum HR is negative, it is 0.");
min_hr = 0.0;
}
info!("Xvb Process | hr {}, min_hr: {} ", lhr, min_hr);
// numbers are divided by a thousands to print kH/s and not H/s
let msg_lhr = format!(
"{} kH/s local HR from Xmrig",
Float::from_3((lhr / 1000.0).into())
);
let msg_mhr = format!(
"{} kH/s minimum required local HR to keep a share in PPLNS window",
Float::from_3((min_hr / 1000.0).into())
);
let msg_ehr = format!(
"{} kH/s estimated sent the last hour for your address on p2pool, including this instance",
Float::from_3((p2pool_ehr / 1000.0).into())
);
output_console(
&mut lock!(gui_api_xvb).output,
&msg_lhr,
crate::helper::ProcessName::Xvb,
);
output_console(
&mut lock!(gui_api_xvb).output,
&msg_mhr,
crate::helper::ProcessName::Xvb,
);
output_console(
&mut lock!(gui_api_xvb).output,
&msg_ehr,
crate::helper::ProcessName::Xvb,
);
// calculate how much time can be spared
let mut spared_time = time_that_could_be_spared(lhr, min_hr);
if spared_time > 0 {
// if not hero option
if !lock!(gui_api_xvb).stats_priv.runtime_hero_mode {
let xvb_chr = lock!(gui_api_xvb).stats_priv.donor_1hr_avg * 1000.0;
info!("current HR on XvB (last hour): {xvb_chr}");
let shr = calc_last_hour_avg_hash_rate(&lock!(gui_api_xvb).xvb_sent_last_hour_samples);
// calculate how much time needed to be spared to be in most round type minimum HR + buffer
spared_time = minimum_time_for_highest_accessible_round(spared_time, lhr, xvb_chr, shr);
}
}
if lock!(gui_api_xvb).stats_priv.runtime_hero_mode {
output_console(
&mut lock!(gui_api_xvb).output,
"Hero mode is enabled for this decision",
crate::helper::ProcessName::Xvb,
);
}
spared_time
}
fn minimum_hashrate_share(difficulty: u64, mini: bool, ohr: f32) -> f32 {
let pws = if mini {
BLOCK_PPLNS_WINDOW_MINI
} else {
BLOCK_PPLNS_WINDOW_MAIN
};
let minimum_hr = ((difficulty / (pws * SECOND_PER_BLOCK_P2POOL)) as f32 * XVB_BUFFER) - ohr;
info!("XvB Process | (difficulty / (window pplns blocks * seconds per p2pool block) * BUFFER) - outside HR = minimum HR to keep a share\n({difficulty} / ({pws} * {SECOND_PER_BLOCK_P2POOL}) * {XVB_BUFFER}) - {ohr} = {minimum_hr}");
minimum_hr
}
fn time_that_could_be_spared(hr: f32, min_hr: f32) -> u32 {
// percent of time minimum
let minimum_time_required_on_p2pool = XVB_TIME_ALGO as f32 / (hr / min_hr);
info!("XvB Process | Time of algo / local hashrate / minimum hashrate = minimum time required on p2pool\n{XVB_TIME_ALGO} / ({hr} / {min_hr}) = {minimum_time_required_on_p2pool}");
let spared_time = XVB_TIME_ALGO as f32 - minimum_time_required_on_p2pool;
info!("XvB Process | Time of algo - minimum time required on p2pool = time that can be spared.\n{XVB_TIME_ALGO} - {minimum_time_required_on_p2pool} = {spared_time}");
// if less than 6 seconds, XMRig could hardly have the time to mine anything.
if spared_time >= 6.0 {
return spared_time as u32;
}
info!(
"XvB Process | sparted time is equal or less than 6 seconds, so everything goes to p2pool."
);
0
}
// spared time, local hr, current 1h average hr already mining on XvB, 1h average local HR sent on XvB.
fn minimum_time_for_highest_accessible_round(st: u32, lhr: f32, chr: f32, shr: f32) -> u32 {
// we remove one second that could possibly be sent, because if the time needed is a float, it will be rounded up.
// this subtraction can not fail because mnimum spared time is >= 6.
let hr_for_xvb = ((st - 1) as f32 / XVB_TIME_ALGO as f32) * lhr;
info!(
"hr for xvb is: ({st} / {}) * {lhr} = {hr_for_xvb}H/s",
XVB_TIME_ALGO
);
let ohr = chr - shr;
info!("ohr is: {chr} - {shr} = {ohr}H/s");
let min_mega = XVB_ROUND_DONOR_MEGA_MIN_HR as f32 - ohr;
info!(
"minimum required HR for mega round is: {} - {ohr} = {min_mega}H/s",
XVB_ROUND_DONOR_MEGA_MIN_HR
);
let min_whale = XVB_ROUND_DONOR_WHALE_MIN_HR as f32 - ohr;
info!(
"minimum required HR for whale round is: {} - {ohr} = {min_whale}H/s",
XVB_ROUND_DONOR_WHALE_MIN_HR
);
let min_donorvip = XVB_ROUND_DONOR_VIP_MIN_HR as f32 - ohr;
info!(
"minimum required HR for donor vip round is: {} - {ohr} = {min_donorvip}H/s",
XVB_ROUND_DONOR_VIP_MIN_HR
);
let min_donor = XVB_ROUND_DONOR_MIN_HR as f32 - ohr;
info!(
"minimum required HR for donor round is: {} - {ohr} = {min_donor}H/s",
XVB_ROUND_DONOR_MIN_HR
);
let min = match hr_for_xvb {
x if x > min_mega => {
info!("trying to get Mega round");
info!(
"minimum second to send = ((({x} - ({x} - {min_mega})) / {lhr}) * {}) ",
XVB_TIME_ALGO
);
min_mega
}
x if x > min_whale => {
info!("trying to get Whale round");
info!(
"minimum second to send = ((({x} - ({x} - {min_whale})) / {lhr}) * {}) ",
XVB_TIME_ALGO
);
min_whale
}
x if x > min_donorvip => {
info!("trying to get Vip Donor round");
info!(
"minimum second to send = ((({x} - ({x} - {min_donorvip})) / {lhr}) * {}) ",
XVB_TIME_ALGO
);
min_donorvip
}
x if x > min_donor => {
info!("trying to get Donor round");
info!(
"minimum second to send = ((({x} - ({x} - {min_donor})) / {lhr}) * {}) ",
XVB_TIME_ALGO
);
min_donor
}
_ => return 0,
};
(((hr_for_xvb - (hr_for_xvb - min)) / lhr) * XVB_TIME_ALGO as f32).ceil() as u32
}
#[allow(clippy::too_many_arguments)]
async fn sleep_then_update_node_xmrig(
spared_time: u32,
client: &Client,
api_uri: &str,
token_xmrig: &str,
address: &str,
gui_api_xvb: &Arc<Mutex<PubXvbApi>>,
gui_api_xmrig: &Arc<Mutex<PubXmrigApi>>,
gui_api_xp: &Arc<Mutex<PubXmrigProxyApi>>,
rig: &str,
xp_alive: bool,
) {
let node = lock!(gui_api_xvb).stats_priv.node;
debug!(
"Xvb Process | algo sleep for {} while mining on P2pool",
XVB_TIME_ALGO - spared_time
);
let msg_xmrig_or_xp = if xp_alive { "XMRig-Proxy" } else { "XMRig" };
sleep(Duration::from_secs((XVB_TIME_ALGO - spared_time).into())).await;
// only update xmrig config if it is actually mining.
if spared_time > 0 {
debug!("Xvb Process | request {msg_xmrig_or_xp} to mine on XvB");
if lock!(gui_api_xvb).current_node.is_none()
|| lock!(gui_api_xvb)
.current_node
.as_ref()
.is_some_and(|n| n == &XvbNode::P2pool)
{
if let Err(err) =
update_xmrig_config(client, api_uri, token_xmrig, &node, address, rig).await
{
// show to console error about updating xmrig config
warn!("Xvb Process | Failed request HTTP API {msg_xmrig_or_xp}");
output_console(
&mut lock!(gui_api_xvb).output,
&format!(
"Failure to update {msg_xmrig_or_xp} config with HTTP API.\nError: {}",
err
),
crate::helper::ProcessName::Xvb,
);
} else {
if xp_alive {
lock!(gui_api_xp).node = node.to_string();
} else {
lock!(gui_api_xmrig).node = node.to_string();
}
debug!("Xvb Process | mining on XvB pool");
}
}
// will not quit the process until it is really done.
// xvb process watch this algo handle to see if process is finished or not.
sleep(Duration::from_secs(spared_time.into())).await;
}
}
// push new value into samples before executing this calcul
fn calc_last_hour_avg_hash_rate(samples: &SamplesAverageHour) -> f32 {
samples.0.iter().sum::<f32>() / samples.0.len() as f32
}
#[allow(clippy::too_many_arguments)] #[allow(clippy::too_many_arguments)]
pub(crate) async fn algorithm( pub(crate) async fn algorithm(
client: &Client, client: &Client,
pub_api: &Arc<Mutex<PubXvbApi>>,
gui_api_xvb: &Arc<Mutex<PubXvbApi>>, gui_api_xvb: &Arc<Mutex<PubXvbApi>>,
gui_api_xmrig: &Arc<Mutex<PubXmrigApi>>, gui_api_xmrig: &Arc<Mutex<PubXmrigApi>>,
gui_api_xp: &Arc<Mutex<PubXmrigProxyApi>>, gui_api_xp: &Arc<Mutex<PubXmrigProxyApi>>,
@ -272,146 +41,524 @@ pub(crate) async fn algorithm(
rig: &str, rig: &str,
xp_alive: bool, xp_alive: bool,
) { ) {
debug!("Xvb Process | Algorithm is started"); let mut algorithm = Algorithm::new(
output_console(
&mut lock!(gui_api_xvb).output,
"Algorithm of distribution HR started for the next ten minutes.",
ProcessName::Xvb,
);
// 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.
let address = &state_p2pool.address;
// request XMrig to mine on P2pool
// if share is in PW,
let msg_xmrig_or_xp = if xp_alive { "XMRig-Proxy" } else { "XMRig" };
info!("xp alive: {:?}", xp_alive);
let api_url = api_url_xmrig(xp_alive, true);
if share > 0 {
debug!("Xvb Process | Algorithm share is in current window");
// calcul minimum HR
output_console(
&mut lock!(gui_api_xvb).output,
"At least one share is in current PPLNS window.",
ProcessName::Xvb,
);
let hashrate_xmrig = current_controllable_hr(xp_alive, gui_api_xp, gui_api_xmrig);
*lock!(time_donated) =
calcul_donated_time(hashrate_xmrig, gui_api_p2pool, gui_api_xvb, state_p2pool);
let time_donated = *lock!(time_donated);
debug!("Xvb Process | Donated time {} ", time_donated);
output_console(
&mut lock!(gui_api_xvb).output,
&format!(
"Mining on P2pool node for {} seconds then on XvB for {} seconds.",
XVB_TIME_ALGO - time_donated,
time_donated
),
ProcessName::Xvb,
);
// p2pool need to be mined if donated time is not equal to xvb_time_algo
if time_donated != XVB_TIME_ALGO && lock!(gui_api_xvb).current_node != Some(XvbNode::P2pool)
{
debug!("Xvb Process | request {msg_xmrig_or_xp} to mine on p2pool");
if let Err(err) = update_xmrig_config(
client, client,
&api_url, pub_api,
token_xmrig,
&XvbNode::P2pool,
address,
rig,
)
.await
{
warn!("Xvb Process | Failed request HTTP API {msg_xmrig_or_xp}");
output_console(
&mut lock!(gui_api_xvb).output,
&format!(
"Failure to update {msg_xmrig_or_xp} config with HTTP API.\nError: {}",
err
),
ProcessName::Xvb,
);
} else if xp_alive {
lock!(gui_api_xmrig).node = XvbNode::P2pool.to_string()
} else {
lock!(gui_api_xmrig).node = XvbNode::P2pool.to_string();
}
}
// sleep 10m less spared time then request XMrig to mine on XvB
sleep_then_update_node_xmrig(
time_donated,
client,
&api_url,
token_xmrig,
address,
gui_api_xvb, gui_api_xvb,
gui_api_xmrig, gui_api_xmrig,
gui_api_xp, gui_api_xp,
"", gui_api_p2pool,
token_xmrig,
state_p2pool,
share,
time_donated,
rig,
xp_alive, xp_alive,
)
.await;
lock!(gui_api_xvb)
.p2pool_sent_last_hour_samples
.0
.push_back(
hashrate_xmrig
* ((XVB_TIME_ALGO as f32 - time_donated as f32) / XVB_TIME_ALGO as f32),
); );
lock!(gui_api_xvb) algorithm.run().await;
.xvb_sent_last_hour_samples }
.0
.push_back(hashrate_xmrig * (time_donated as f32 / XVB_TIME_ALGO as f32)); #[allow(dead_code)]
} else { pub struct Algorithm<'a> {
// no share, so we mine on p2pool. We update xmrig only if it was still mining on XvB. client: &'a Client,
if lock!(gui_api_xvb).current_node != Some(XvbNode::P2pool) { pub_api: &'a Arc<Mutex<PubXvbApi>>,
info!("Xvb Process | request {msg_xmrig_or_xp}to mine on p2pool"); gui_api_xvb: &'a Arc<Mutex<PubXvbApi>>,
gui_api_xmrig: &'a Arc<Mutex<PubXmrigApi>>,
gui_api_xp: &'a Arc<Mutex<PubXmrigProxyApi>>,
gui_api_p2pool: &'a Arc<Mutex<PubP2poolApi>>,
token_xmrig: &'a str,
state_p2pool: &'a crate::disk::state::P2pool,
time_donated: &'a Arc<Mutex<u32>>,
rig: &'a str,
xp_alive: bool,
pub stats: Stats,
}
#[derive(Debug)]
#[allow(dead_code)]
pub struct Stats {
share: u32,
hashrate_xmrig: f32,
pub target_donation_hashrate: f32,
xvb_24h_avg: f32,
xvb_1h_avg: f32,
address: String,
runtime_mode: RuntimeMode,
runtime_donation_level: RuntimeDonationLevel,
runtime_amount: f64,
p2pool_total_hashrate: f32,
avg_last_hour_hashrate: f32,
p2pool_external_hashrate: f32,
share_min_hashrate: f32,
spareable_hashrate: f32,
spared_time: u32,
api_url: String,
msg_xmrig_or_xp: String,
}
impl<'a> Algorithm<'a> {
#[allow(clippy::too_many_arguments)]
pub fn new(
client: &'a Client,
pub_api: &'a Arc<Mutex<PubXvbApi>>,
gui_api_xvb: &'a Arc<Mutex<PubXvbApi>>,
gui_api_xmrig: &'a Arc<Mutex<PubXmrigApi>>,
gui_api_xp: &'a Arc<Mutex<PubXmrigProxyApi>>,
gui_api_p2pool: &'a Arc<Mutex<PubP2poolApi>>,
token_xmrig: &'a str,
state_p2pool: &'a crate::disk::state::P2pool,
share: u32,
time_donated: &'a Arc<Mutex<u32>>,
rig: &'a str,
xp_alive: bool,
) -> Self {
let hashrate_xmrig = current_controllable_hr(xp_alive, gui_api_xp, gui_api_xmrig);
let address = state_p2pool.address.clone();
let runtime_mode = lock!(gui_api_xvb).stats_priv.runtime_mode.clone();
let runtime_donation_level = lock!(gui_api_xvb)
.stats_priv
.runtime_manual_donation_level
.clone();
let runtime_amount = lock!(gui_api_xvb).stats_priv.runtime_manual_amount;
let p2pool_total_hashrate = lock!(gui_api_p2pool).sidechain_ehr;
let avg_last_hour_hashrate =
Self::calc_last_hour_avg_hash_rate(&lock!(gui_api_xvb).p2pool_sent_last_hour_samples);
let mut p2pool_external_hashrate = p2pool_total_hashrate - avg_last_hour_hashrate;
if p2pool_external_hashrate < 0.0 {
p2pool_external_hashrate = 0.0;
}
let share_min_hashrate = Self::minimum_hashrate_share(
lock!(gui_api_p2pool).p2pool_difficulty_u64,
state_p2pool.mini,
p2pool_external_hashrate,
);
let spareable_hashrate = hashrate_xmrig - share_min_hashrate;
let api_url = api_url_xmrig(xp_alive, true);
let msg_xmrig_or_xp = (if xp_alive { "XMRig-Proxy" } else { "XMRig" }).to_string();
info!("xp alive: {:?}", xp_alive);
let xvb_24h_avg = lock!(pub_api).stats_priv.donor_24hr_avg * 1000.0;
let xvb_1h_avg = lock!(pub_api).stats_priv.donor_1hr_avg * 1000.0;
let stats = Stats {
share,
hashrate_xmrig,
xvb_24h_avg,
xvb_1h_avg,
address,
target_donation_hashrate: f32::default(),
runtime_mode,
runtime_donation_level,
runtime_amount,
p2pool_total_hashrate,
avg_last_hour_hashrate,
p2pool_external_hashrate,
share_min_hashrate,
spareable_hashrate,
spared_time: u32::default(),
api_url,
msg_xmrig_or_xp,
};
let mut new_instance = Self {
client,
pub_api,
gui_api_xvb,
gui_api_xmrig,
gui_api_xp,
gui_api_p2pool,
token_xmrig,
state_p2pool,
time_donated,
rig,
xp_alive,
stats,
};
new_instance.stats.target_donation_hashrate = new_instance.get_target_donation_hashrate();
new_instance.stats.spared_time = Self::get_spared_time(
new_instance.stats.target_donation_hashrate,
new_instance.stats.hashrate_xmrig,
);
new_instance
}
fn is_share_fulfilled(&self) -> bool {
let is_criteria_fulfilled = self.stats.share > 0;
info!(
"Algorithm | shares({}) > 0 : {}",
self.stats.share, is_criteria_fulfilled,
);
is_criteria_fulfilled
}
fn is_xvb_24h_fulfilled(&self) -> bool {
let is_criteria_fulfilled = self.stats.xvb_24h_avg > self.stats.target_donation_hashrate;
info!(
"Algorithm | xvb_24h_avg({}) > target_donation_hashrate({}) : {}",
self.stats.xvb_24h_avg, self.stats.target_donation_hashrate, is_criteria_fulfilled
);
is_criteria_fulfilled
}
async fn target_p2pool_node(&self) {
if lock!(self.gui_api_xvb).current_node != Some(XvbNode::P2pool) {
info!(
"Algorithm | request {} to mine on p2pool",
self.stats.msg_xmrig_or_xp
);
if let Err(err) = update_xmrig_config( if let Err(err) = update_xmrig_config(
client, self.client,
&api_url, &self.stats.api_url,
token_xmrig, self.token_xmrig,
&XvbNode::P2pool, &XvbNode::P2pool,
address, &self.stats.address,
rig, self.rig,
) )
.await .await
{ {
warn!("Xvb Process | Failed request HTTP API {msg_xmrig_or_xp}"); warn!(
"Algorithm | Failed request HTTP API {}",
self.stats.msg_xmrig_or_xp
);
output_console( output_console(
&mut lock!(gui_api_xvb).output, &mut lock!(self.gui_api_xvb).output,
&format!( &format!(
"Failure to update {msg_xmrig_or_xp}config with HTTP API.\nError: {}", "Failure to update {} config with HTTP API.\nError: {}",
err self.stats.msg_xmrig_or_xp, err
), ),
ProcessName::Xvb, crate::helper::ProcessName::Xvb,
);
} else {
info!(
"Algorithm | {} mining on p2pool pool",
self.stats.msg_xmrig_or_xp
); );
} }
} }
output_console( }
&mut lock!(gui_api_xvb).output,
"No share in the current PPLNS Window !", async fn target_xvb_node(&self) {
ProcessName::Xvb, let node = lock!(self.gui_api_xvb).stats_priv.node;
info!(
"Algorithm | request {} to mine on XvB",
self.stats.msg_xmrig_or_xp
);
if lock!(self.gui_api_xvb).current_node.is_none()
|| lock!(self.gui_api_xvb)
.current_node
.as_ref()
.is_some_and(|n| n == &XvbNode::P2pool)
{
if let Err(err) = update_xmrig_config(
self.client,
&self.stats.api_url,
self.token_xmrig,
&node,
&self.stats.address,
self.rig,
)
.await
{
// show to console error about updating xmrig config
warn!(
"Algorithm | Failed request HTTP API {}",
self.stats.msg_xmrig_or_xp
); );
output_console( output_console(
&mut lock!(gui_api_xvb).output, &mut lock!(self.gui_api_xvb).output,
"Mining on P2pool for the next ten minutes.", &format!(
ProcessName::Xvb, "Failure to update {} config with HTTP API.\nError: {}",
self.stats.msg_xmrig_or_xp, err
),
crate::helper::ProcessName::Xvb,
);
} else {
if self.xp_alive {
lock!(self.gui_api_xp).node = node.to_string();
} else {
lock!(self.gui_api_xmrig).node = node.to_string();
}
info!(
"Algorithm | {} mining on XvB pool",
self.stats.msg_xmrig_or_xp
);
}
}
}
async fn send_all_p2pool(&self) {
self.target_p2pool_node().await;
info!(
"Algorithm | algo sleep for {} seconds while mining on P2pool",
XVB_TIME_ALGO
); );
sleep(Duration::from_secs(XVB_TIME_ALGO.into())).await; sleep(Duration::from_secs(XVB_TIME_ALGO.into())).await;
let hr = current_controllable_hr(xp_alive, gui_api_xp, gui_api_xmrig);
lock!(gui_api_xvb) lock!(self.gui_api_xvb)
.p2pool_sent_last_hour_samples .p2pool_sent_last_hour_samples
.0 .0
.push_back(hr); .push_back(lock!(self.gui_api_xmrig).hashrate_raw_15m);
lock!(gui_api_xvb) lock!(self.gui_api_xvb)
.xvb_sent_last_hour_samples .xvb_sent_last_hour_samples
.0 .0
.push_back(0.0); .push_back(0.0);
} }
// algorithm has run, so do not retry but run normally
// put a space to mark the difference with the next run. async fn send_all_xvb(&self) {
output_console_without_time(&mut lock!(gui_api_xvb).output, "", ProcessName::Xvb); self.target_xvb_node().await;
info!(
"Algorithm | algo sleep for {} seconds while mining on XvB",
XVB_TIME_ALGO
);
sleep(Duration::from_secs(XVB_TIME_ALGO.into())).await;
lock!(self.gui_api_xvb)
.p2pool_sent_last_hour_samples
.0
.push_back(lock!(self.gui_api_xmrig).hashrate_raw_15m);
lock!(self.gui_api_xvb)
.xvb_sent_last_hour_samples
.0
.push_back(0.0);
}
async fn sleep_then_update_node_xmrig(&self) {
info!(
"Algorithm | algo sleep for {} seconds while mining on P2pool",
XVB_TIME_ALGO - self.stats.spared_time
);
sleep(Duration::from_secs(
(XVB_TIME_ALGO - self.stats.spared_time).into(),
))
.await;
// only update xmrig config if it is actually mining.
info!("Algorithm | request xmrig to mine on XvB");
self.target_xvb_node().await;
// will not quit the process until it is really done.
// xvb process watch this algo handle to see if process is finished or not.
info!(
"Algorithm | algo sleep for {} seconds while mining on P2pool",
self.stats.spared_time
);
sleep(Duration::from_secs(self.stats.spared_time.into())).await;
lock!(self.gui_api_xvb)
.p2pool_sent_last_hour_samples
.0
.push_back(
self.stats.hashrate_xmrig
* ((XVB_TIME_ALGO as f32 - self.stats.spared_time as f32)
/ XVB_TIME_ALGO as f32),
);
lock!(self.gui_api_xvb)
.xvb_sent_last_hour_samples
.0
.push_back(
self.stats.hashrate_xmrig * (self.stats.spared_time as f32 / XVB_TIME_ALGO as f32),
);
}
pub fn get_target_donation_hashrate(&self) -> f32 {
match self.stats.runtime_mode {
RuntimeMode::Auto => self.get_auto_mode_target_donation_hashrate(),
RuntimeMode::Hero => self.get_hero_mode_target_donation_hashrate(),
RuntimeMode::ManualXvb => {
info!(
"Algorithm | ManualXvBMode target_donation_hashrate=runtime_amount({}H/s)",
self.stats.runtime_amount
);
self.stats.runtime_amount as f32
}
RuntimeMode::ManualP2pool => {
let target_donation_hashrate =
self.stats.hashrate_xmrig - (self.stats.runtime_amount as f32);
info!("Algorithm | ManualP2poolMode target_donation_hashrate({})=hashrate_xmrig({})-runtime_amount({})",
target_donation_hashrate,
self.stats.hashrate_xmrig,
self.stats.runtime_amount);
target_donation_hashrate
}
RuntimeMode::ManualDonationLevel => {
let target_donation_hashrate = self.stats.runtime_donation_level.get_hashrate();
info!("Algorithm | ManualDonationLevelMode target_donation_hashrate({})={:#?}.get_hashrate()",
target_donation_hashrate,
self.stats.runtime_donation_level);
target_donation_hashrate
}
}
}
fn get_auto_mode_target_donation_hashrate(&self) -> f32 {
let donation_level = match self.stats.spareable_hashrate {
x if x > (XVB_ROUND_DONOR_MEGA_MIN_HR as f32) => Some(RuntimeDonationLevel::DonorMega),
x if x > (XVB_ROUND_DONOR_WHALE_MIN_HR as f32) => {
Some(RuntimeDonationLevel::DonorWhale)
}
x if x > (XVB_ROUND_DONOR_VIP_MIN_HR as f32) => Some(RuntimeDonationLevel::DonorVIP),
x if x > (XVB_ROUND_DONOR_MIN_HR as f32) => Some(RuntimeDonationLevel::Donor),
_ => None,
};
info!(
"Algorithm | AutoMode target_donation_level detected ({:#?})",
donation_level
);
let target_donation_hashrate = if let Some(level) = donation_level {
level.get_hashrate()
} else {
0.0
};
info!(
"Algorithm | AutoMode target_donation_hashrate ({})",
target_donation_hashrate
);
target_donation_hashrate
}
fn get_hero_mode_target_donation_hashrate(&self) -> f32 {
info!(
"Algorithm | HeroMode target_donation_hashrate=spareable_hashrate({})",
self.stats.spareable_hashrate
);
self.stats.spareable_hashrate
}
// push new value into samples before executing this calcul
fn calc_last_hour_avg_hash_rate(samples: &SamplesAverageHour) -> f32 {
samples.0.iter().sum::<f32>() / samples.0.len() as f32
}
fn minimum_hashrate_share(difficulty: u64, mini: bool, p2pool_external_hashrate: f32) -> f32 {
let pws = if mini {
BLOCK_PPLNS_WINDOW_MINI
} else {
BLOCK_PPLNS_WINDOW_MAIN
};
let mut minimum_hr = ((difficulty / (pws * SECOND_PER_BLOCK_P2POOL)) as f32 * XVB_BUFFER)
- p2pool_external_hashrate;
info!("Algorithm | (difficulty({}) / (window pplns blocks({}) * seconds per p2pool block({})) * BUFFER({})) - outside HR({}H/s) = minimum HR({}H/s) to keep a share.",
difficulty,
pws,
SECOND_PER_BLOCK_P2POOL,
XVB_BUFFER,
p2pool_external_hashrate,
minimum_hr);
if minimum_hr.is_sign_negative() {
info!("Algorithm | if minimum HR is negative, it is 0.");
minimum_hr = 0.0;
}
minimum_hr
}
async fn fulfill_share(&self) {
output_console(
&mut lock!(self.gui_api_xvb).output,
"There are no shares in p2pool. Sending all hashrate to p2pool!",
crate::helper::ProcessName::Xvb,
);
info!("Algorithm | There are no shares in p2pool. Sending all hashrate to p2pool!");
self.send_all_p2pool().await
}
async fn fulfill_xvb_24_avg(&self) {
output_console(
&mut lock!(self.gui_api_xvb).output,
"24H avg XvB target not achieved. Sending all hashrate to XvB!",
crate::helper::ProcessName::Xvb,
);
info!("Algorithm | 24H avg XvB target not achieved. Sending all hashrate to XvB!");
*lock!(self.time_donated) = XVB_TIME_ALGO;
self.send_all_xvb().await
}
async fn fulfill_normal_cycles(&self) {
output_console(
&mut lock!(self.gui_api_xvb).output,
"There is a share in p2pool and 24H avg XvB is achieved. Sending {self.stats.spared_time} to XvB!",
crate::helper::ProcessName::Xvb,
);
info!("Algorithm | There is a share in p2pool and 24H avg XvB is achieved. Sending {} to XvB!", self.stats.spared_time);
*lock!(self.time_donated) = self.stats.spared_time;
self.target_p2pool_node().await;
self.sleep_then_update_node_xmrig().await;
}
pub async fn run(&mut self) {
output_console(
&mut lock!(self.gui_api_xvb).output,
"Algorithm of HR distribution started for the next 10 minutes.",
crate::helper::ProcessName::Xvb,
);
info!("Algorithm | Starting...");
info!("Algorithm | {:#?}", self.stats);
if !self.is_share_fulfilled() {
self.fulfill_share().await
} else if !self.is_xvb_24h_fulfilled() {
self.fulfill_xvb_24_avg().await
} else {
self.fulfill_normal_cycles().await
}
output_console_without_time(
&mut lock!(self.gui_api_xvb).output,
"",
crate::helper::ProcessName::Xvb,
)
}
fn get_spared_time(target_donation_hashrate: f32, hashrate_xmrig: f32) -> u32 {
let spared_time = target_donation_hashrate / hashrate_xmrig * (XVB_TIME_ALGO as f32);
info!("Algorithm | Calculating... spared_time({}seconds)=target_donation_hashrate({})/hashrate_xmrig({})*XVB_TIME_ALGO({})",
spared_time,
target_donation_hashrate,
hashrate_xmrig,
XVB_TIME_ALGO);
spared_time as u32
}
} }

View file

@ -211,6 +211,8 @@ impl Helper {
// check if first loop the state of Xmrig-Proxy // check if first loop the state of Xmrig-Proxy
if first_loop { if first_loop {
xp_alive = lock!(process_xp).state == ProcessState::Alive; xp_alive = lock!(process_xp).state == ProcessState::Alive;
msg_retry_done = false;
*lock!(retry) = false;
} }
// verify if p2pool and xmrig are running, else XvB must be reloaded with another token/address to start verifying the other process. // verify if p2pool and xmrig are running, else XvB must be reloaded with another token/address to start verifying the other process.
if check_state_outcauses_xvb( if check_state_outcauses_xvb(
@ -234,11 +236,11 @@ impl Helper {
{ {
continue; continue;
} }
// check signal // check signal
debug!("XvB | check signal"); debug!("XvB | check signal");
if signal_interrupt( if signal_interrupt(
process, process,
if xp_alive { process_xp } else { process_xmrig },
start.into(), start.into(),
&client, &client,
pub_api, pub_api,
@ -317,7 +319,8 @@ impl Helper {
} }
} }
let hashrate = current_controllable_hr(xp_alive, &gui_api_xp, &gui_api_xmrig); let hashrate = current_controllable_hr(xp_alive, &gui_api_xp, &gui_api_xmrig);
if (first_loop || *lock!(retry)|| is_algo_finished) && hashrate > 0.0 && lock!(process).state == ProcessState::Alive let difficulty_data_is_ready = lock!(gui_api_p2pool).p2pool_difficulty_u64 > 100_000;
if (first_loop || *lock!(retry)|| is_algo_finished) && hashrate > 0.0 && lock!(process).state == ProcessState::Alive && difficulty_data_is_ready
{ {
// if algo was started, it must not retry next loop. // if algo was started, it must not retry next loop.
*lock!(retry) = false; *lock!(retry) = false;
@ -336,6 +339,7 @@ impl Helper {
}; };
algorithm( algorithm(
&client, &client,
&pub_api,
&gui_api, &gui_api,
&gui_api_xmrig, &gui_api_xmrig,
&gui_api_xp, &gui_api_xp,
@ -351,7 +355,7 @@ impl Helper {
} else { } else {
// if xmrig is still at 0 HR but is alive and algorithm is skipped, recheck first 10s of xmrig inside algorithm next time (in one minute). Don't check if algo failed to start because state was not alive after getting private stats. // if xmrig is still at 0 HR but is alive and algorithm is skipped, recheck first 10s of xmrig inside algorithm next time (in one minute). Don't check if algo failed to start because state was not alive after getting private stats.
if current_controllable_hr(xp_alive, &gui_api_xp, &gui_api_xmrig) == 0.0 && lock!(process).state == ProcessState::Alive { if (hashrate == 0.0 || !difficulty_data_is_ready) && lock!(process).state == ProcessState::Alive {
*lock!(retry) = true *lock!(retry) = true
} }
} }
@ -368,9 +372,9 @@ impl Helper {
// show this message only once before the start of algo // show this message only once before the start of algo
if *lock!(retry) && !msg_retry_done { if *lock!(retry) && !msg_retry_done {
let msg = if xp_alive { let msg = if xp_alive {
"Algorithm is waiting for 1 minute average HR of XMRig-Proxy" "Algorithm is waiting for 1 minute average HR of XMRig-Proxy or p2pool data"
} else { } else {
"Algorithm is waiting for 10 seconds average HR of XMRig." "Algorithm is waiting for 10 seconds average HR of XMRig or p2pool data"
}; };
output_console(&mut lock!(gui_api).output, msg, ProcessName::Xvb); output_console(&mut lock!(gui_api).output, msg, ProcessName::Xvb);
msg_retry_done = true; msg_retry_done = true;
@ -441,11 +445,14 @@ impl PubXvbApi {
if !buf.is_empty() { if !buf.is_empty() {
output.push_str(&buf); output.push_str(&buf);
} }
let runtime_hero_mode = std::mem::take(&mut gui_api.stats_priv.runtime_hero_mode); let runtime_mode = std::mem::take(&mut gui_api.stats_priv.runtime_mode);
let runtime_manual_amount = std::mem::take(&mut gui_api.stats_priv.runtime_manual_amount);
*gui_api = Self { *gui_api = Self {
output, output,
stats_priv: XvbPrivStats { stats_priv: XvbPrivStats {
runtime_hero_mode, runtime_mode,
runtime_manual_amount,
..pub_api.stats_priv.clone() ..pub_api.stats_priv.clone()
}, },
p2pool_sent_last_hour_samples: std::mem::take( p2pool_sent_last_hour_samples: std::mem::take(
@ -487,7 +494,7 @@ async fn check_conditions_for_start(
output_console(&mut lock!(gui_api).output, msg, ProcessName::Xvb); output_console(&mut lock!(gui_api).output, msg, ProcessName::Xvb);
ProcessState::Syncing ProcessState::Syncing
} else if lock!(process_xmrig).state != ProcessState::Alive } else if lock!(process_xmrig).state != ProcessState::Alive
|| lock!(process_xp).state != ProcessState::Alive && lock!(process_xp).state != ProcessState::Alive
{ {
// send to console: xmrig process is not running // send to console: xmrig process is not running
warn!("Xvb | Start ... Partially failed because Xmrig or Xmrig-Proxy instance is not running."); warn!("Xvb | Start ... Partially failed because Xmrig or Xmrig-Proxy instance is not running.");
@ -673,6 +680,7 @@ async fn check_state_outcauses_xvb(
#[allow(clippy::too_many_arguments)] #[allow(clippy::too_many_arguments)]
fn signal_interrupt( fn signal_interrupt(
process: &Arc<Mutex<Process>>, process: &Arc<Mutex<Process>>,
process_xrig: &Arc<Mutex<Process>>,
start: Instant, start: Instant,
client: &Client, client: &Client,
pub_api: &Arc<Mutex<PubXvbApi>>, pub_api: &Arc<Mutex<PubXvbApi>>,
@ -741,13 +749,12 @@ fn signal_interrupt(
// if both XvB nodes fail after checking, process will be partially stopped and a new spawn will verify if nodes are again online and so will continue the process completely if that's the case. // if both XvB nodes fail after checking, process will be partially stopped and a new spawn will verify if nodes are again online and so will continue the process completely if that's the case.
// if P2pool, the process has to stop the algo and continue partially. The process will continue completely if the confitions are met again. // if P2pool, the process has to stop the algo and continue partially. The process will continue completely if the confitions are met again.
// if XvB was not alive, then if it is for XvB nodes, it will check and update preferred node and set XMRig to P2pool if that's not the case. // if XvB was not alive, then if it is for XvB nodes, it will check and update preferred node and set XMRig to P2pool if that's not the case.
// if XvB was not alive and update was for P2pool, XvB must ignore. XMRig will stop sending signals because current node will be none. let was_alive = lock!(process).state == ProcessState::Alive;
let was_alive = lock!(process).state != ProcessState::Alive;
// so it won't execute another signal of update nodes if it is already doing it. // so it won't execute another signal of update nodes if it is already doing it.
lock!(process).state = ProcessState::Waiting; lock!(process).state = ProcessState::Waiting;
lock!(process).signal = ProcessSignal::None; lock!(process).signal = ProcessSignal::None;
spawn( spawn(
enc!((node, process, client, gui_api, pub_api, was_alive, address, token_xmrig, gui_api_xmrig, gui_api_xp) async move { enc!((node, process, client, gui_api, pub_api, was_alive, address, token_xmrig, gui_api_xmrig, gui_api_xp,process_xrig) async move {
warn!("in spawn of UpdateNodes"); warn!("in spawn of UpdateNodes");
match node { match node {
XvbNode::NorthAmerica|XvbNode::Europe if was_alive => { XvbNode::NorthAmerica|XvbNode::Europe if was_alive => {
@ -774,8 +781,8 @@ fn signal_interrupt(
// Probably a start. We don't consider XMRig using XvB nodes without algo. // Probably a start. We don't consider XMRig using XvB nodes without algo.
// can update xmrig and check status of state in the same time. // can update xmrig and check status of state in the same time.
// Need to set XMRig to P2Pool if it wasn't. XMRig should have populated this value at his start. // Need to set XMRig to P2Pool if it wasn't. XMRig should have populated this value at his start.
// but if xmrig didn't start, don't update it.
if lock!(gui_api).current_node != Some(XvbNode::P2pool) { if lock!(process_xrig).state == ProcessState::Alive && lock!(gui_api).current_node != Some(XvbNode::P2pool) {
spawn(enc!((client, token_xmrig, address, gui_api_xmrig, gui_api_xp, gui_api) async move{ spawn(enc!((client, token_xmrig, address, gui_api_xmrig, gui_api_xp, gui_api) async move{
let url_api = api_url_xmrig(xp_alive, true); let url_api = api_url_xmrig(xp_alive, true);
warn!("update xmrig to use node ?"); warn!("update xmrig to use node ?");
@ -823,14 +830,17 @@ fn signal_interrupt(
} }
fn reset_data_xvb(pub_api: &Arc<Mutex<PubXvbApi>>, gui_api: &Arc<Mutex<PubXvbApi>>) { fn reset_data_xvb(pub_api: &Arc<Mutex<PubXvbApi>>, gui_api: &Arc<Mutex<PubXvbApi>>) {
let current_node = mem::take(&mut lock!(pub_api).current_node.clone()); let current_node = mem::take(&mut lock!(pub_api).current_node.clone());
let runtime_hero_mode = mem::take(&mut lock!(gui_api).stats_priv.runtime_hero_mode); let runtime_mode = mem::take(&mut lock!(gui_api).stats_priv.runtime_mode);
let runtime_manual_amount = mem::take(&mut lock!(gui_api).stats_priv.runtime_manual_amount);
// let output = mem::take(&mut lock!(gui_api).output); // let output = mem::take(&mut lock!(gui_api).output);
*lock!(pub_api) = PubXvbApi::new(); *lock!(pub_api) = PubXvbApi::new();
*lock!(gui_api) = PubXvbApi::new(); *lock!(gui_api) = PubXvbApi::new();
// to keep the value modified by xmrig even if xvb is dead. // to keep the value modified by xmrig even if xvb is dead.
lock!(pub_api).current_node = current_node; lock!(pub_api).current_node = current_node;
// to not loose the information of runtime hero mode between restart // to not loose the information of runtime hero mode between restart
lock!(gui_api).stats_priv.runtime_hero_mode = runtime_hero_mode; lock!(gui_api).stats_priv.runtime_mode = runtime_mode;
lock!(gui_api).stats_priv.runtime_manual_amount = runtime_manual_amount;
// message while starting must be preserved. // message while starting must be preserved.
// lock!(pub_api).output = output; // lock!(pub_api).output = output;
} }
@ -849,6 +859,7 @@ fn update_indicator_algo(
Some(XvbNode::P2pool) if time_donated > 0 => { Some(XvbNode::P2pool) if time_donated > 0 => {
// algo is mining on p2pool but will switch to XvB after // algo is mining on p2pool but will switch to XvB after
// show time remaining on p2pool // show time remaining on p2pool
lock!(pub_api).stats_priv.time_switch_node = XVB_TIME_ALGO lock!(pub_api).stats_priv.time_switch_node = XVB_TIME_ALGO
.checked_sub(last_algorithm.lock().unwrap().elapsed().as_secs() as u32) .checked_sub(last_algorithm.lock().unwrap().elapsed().as_secs() as u32)
.unwrap_or_default() .unwrap_or_default()

View file

@ -125,7 +125,7 @@ impl XvbNode {
&format!("XvB node ping, {} is selected as the fastest.", node), &format!("XvB node ping, {} is selected as the fastest.", node),
ProcessName::Xvb, ProcessName::Xvb,
); );
info!("ProcessState to Syncing after finding joignable node"); info!("ProcessState to Syncing after finding joinable node");
// could be used by xmrig who signal that a node is not joignable // could be used by xmrig who signal that a node is not joignable
// or by the start of xvb // or by the start of xvb
// next iteration of the loop of XvB process will verify if all conditions are met to be alive. // next iteration of the loop of XvB process will verify if all conditions are met to be alive.

View file

@ -10,13 +10,48 @@ use serde::Deserialize;
use tokio::time::sleep; use tokio::time::sleep;
use crate::{ use crate::{
disk::state::ManualDonationLevel,
helper::{xvb::output_console, Process, ProcessName, ProcessState}, helper::{xvb::output_console, Process, ProcessName, ProcessState},
macros::lock, macros::lock,
XVB_URL, XVB_URL,
}; };
use crate::{
disk::state::XvbMode, XVB_ROUND_DONOR_MEGA_MIN_HR, XVB_ROUND_DONOR_MIN_HR,
XVB_ROUND_DONOR_VIP_MIN_HR, XVB_ROUND_DONOR_WHALE_MIN_HR,
};
use super::{nodes::XvbNode, rounds::XvbRound, PubXvbApi}; use super::{nodes::XvbNode, rounds::XvbRound, PubXvbApi};
#[derive(Debug, Clone, Deserialize, PartialEq, Eq, Default)]
pub enum RuntimeMode {
#[default]
Auto,
ManualXvb,
ManualP2pool,
Hero,
ManualDonationLevel,
}
#[derive(Debug, Clone, Deserialize, PartialEq, Eq, Default)]
pub enum RuntimeDonationLevel {
#[default]
Donor,
DonorVIP,
DonorWhale,
DonorMega,
}
impl RuntimeDonationLevel {
pub fn get_hashrate(&self) -> f32 {
match &self {
Self::Donor => XVB_ROUND_DONOR_MIN_HR as f32,
Self::DonorVIP => XVB_ROUND_DONOR_VIP_MIN_HR as f32,
Self::DonorWhale => XVB_ROUND_DONOR_WHALE_MIN_HR as f32,
Self::DonorMega => XVB_ROUND_DONOR_MEGA_MIN_HR as f32,
}
}
}
#[derive(Debug, Clone, Default, Deserialize)] #[derive(Debug, Clone, Default, Deserialize)]
pub struct XvbPrivStats { pub struct XvbPrivStats {
pub fails: u8, pub fails: u8,
@ -36,7 +71,11 @@ pub struct XvbPrivStats {
pub msg_indicator: String, pub msg_indicator: String,
#[serde(skip)] #[serde(skip)]
// so the hero mode can change between two decision of algorithm without restarting XvB. // so the hero mode can change between two decision of algorithm without restarting XvB.
pub runtime_hero_mode: bool, pub runtime_mode: RuntimeMode,
#[serde(skip)]
pub runtime_manual_amount: f64,
#[serde(skip)]
pub runtime_manual_donation_level: RuntimeDonationLevel,
} }
impl XvbPrivStats { impl XvbPrivStats {
@ -111,3 +150,26 @@ impl XvbPrivStats {
} }
} }
} }
impl From<XvbMode> for RuntimeMode {
fn from(mode: XvbMode) -> Self {
match mode {
XvbMode::Auto => Self::Auto,
XvbMode::ManualXvb => Self::ManualXvb,
XvbMode::ManualP2pool => Self::ManualP2pool,
XvbMode::Hero => Self::Hero,
XvbMode::ManualDonationLevel => Self::ManualDonationLevel,
}
}
}
impl From<ManualDonationLevel> for RuntimeDonationLevel {
fn from(level: ManualDonationLevel) -> Self {
match level {
ManualDonationLevel::Donor => RuntimeDonationLevel::Donor,
ManualDonationLevel::DonorVIP => RuntimeDonationLevel::DonorVIP,
ManualDonationLevel::DonorWhale => RuntimeDonationLevel::DonorWhale,
ManualDonationLevel::DonorMega => RuntimeDonationLevel::DonorMega,
}
}
}

View file

@ -449,6 +449,8 @@ pub const XMRIG_PROXY_URL: &str = "https://github.com/xmrig/xmrig-proxy";
// XvB // XvB
pub const XVB_HELP: &str = "You need to register an account by clicking on the link above to get your token with the same p2pool XMR address you use for payment."; pub const XVB_HELP: &str = "You need to register an account by clicking on the link above to get your token with the same p2pool XMR address you use for payment.";
pub const XVB_MANUAL_SLIDER_MANUAL_XVB_HELP: &str = "Set the hashrate amount to donate to XvB manually, The remaining hashrate will be sent to p2pool. If the selected hashrate is more than your xmrig hashrate it will be overwritten";
pub const XVB_MANUAL_SLIDER_MANUAL_P2POOL_HELP: &str = "Set the hashrate amount to keep on p2pool manually, The remaining hasrate will be donated to xvb. If the selected hashrate is more than your xmrig hashrate it will be overwritten ";
pub const XVB_URL: &str = "https://xmrvsbeast.com"; pub const XVB_URL: &str = "https://xmrvsbeast.com";
pub const XVB_URL_PUBLIC_API: &str = "https://xmrvsbeast.com/p2pool/stats"; pub const XVB_URL_PUBLIC_API: &str = "https://xmrvsbeast.com/p2pool/stats";
@ -477,6 +479,21 @@ pub const XVB_ROUND_DONOR_VIP_MIN_HR: u32 = 10000;
pub const XVB_ROUND_DONOR_WHALE_MIN_HR: u32 = 100000; pub const XVB_ROUND_DONOR_WHALE_MIN_HR: u32 = 100000;
pub const XVB_ROUND_DONOR_MEGA_MIN_HR: u32 = 1000000; pub const XVB_ROUND_DONOR_MEGA_MIN_HR: u32 = 1000000;
// Manual Mode
pub const XVB_MODE_MANUAL_XVB_HELP: &str = "Manually set the amount to donate to XmrVsBeast, If value is more than xmrig hashrate it might be changed";
pub const XVB_MODE_MANUAL_P2POOL_HELP: &str = "Manually set the amount to keep on P2pool, If value is more than xmrig hashrate it might be changed";
pub const XVB_MODE_MANUAL_DONATION_LEVEL_HELP: &str = "Manually set the XvB donation level";
// Manual Donation Levels
pub const XVB_DONATION_LEVEL_DONOR_HELP: &str =
"To qualify at least 1 kH/s will be actively donated (1hr and 24hr avg.)";
pub const XVB_DONATION_LEVEL_VIP_DONOR_HELP: &str =
"To qualify at least 10 kH/s will be actively donated (1hr and 24hr avg.)";
pub const XVB_DONATION_LEVEL_WHALE_DONOR_HELP: &str =
"To qualify at least 100 kH/s will be actively donated (1hr and 24hr avg.)";
pub const XVB_DONATION_LEVEL_MEGA_DONOR_HELP: &str =
"To qualify at least 1000 kH/s will be actively donated (1hr and 24hr avg.)";
// Unknown Data, replace HumanNumlber::unknown() // Unknown Data, replace HumanNumlber::unknown()
pub const UNKNOWN_DATA: &str = "???"; pub const UNKNOWN_DATA: &str = "???";
// Time PPLNS WINDOW in seconds // Time PPLNS WINDOW in seconds