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:
push:
branches: [ "main" ]
branches: [ "main", "dev" ]
pull_request:
branches: [ "main" ]

View file

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

View file

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

2
.gitignore vendored
View file

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

View file

@ -571,8 +571,10 @@ impl App {
app.tab = app.state.gupax.tab;
// 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
info!("App Init | Checking if saved remote node still exists...");
app.state.p2pool.node = RemoteNode::check_exists(&app.state.p2pool.node);

View file

@ -128,14 +128,17 @@ impl crate::app::App {
wants_input,
);
}
Tab::Xvb => self.xvb_run_actions(
ui,
height,
xvb_is_waiting,
xvb_is_alive,
key,
wants_input,
),
Tab::Xvb => {
self.xvb_submenu(ui, size);
self.xvb_run_actions(
ui,
height,
xvb_is_waiting,
xvb_is_alive,
key,
wants_input,
)
}
Tab::About => {}
}
});
@ -552,91 +555,26 @@ 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,
) {
fn xvb_submenu(&mut self, ui: &mut Ui, size: Vec2) {
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,
);
}
let width = size.x / 1.5;
let size = vec2(width, size.y);
if ui
.add_sized(
size,
SelectableLabel::new(!self.state.xvb.simple, "Advanced"),
)
.clicked()
{
self.state.xvb.simple = false;
}
ui.separator();
if ui
.add_sized(size, SelectableLabel::new(self.state.xvb.simple, "Simple"))
.clicked()
{
self.state.xvb.simple = true;
}
});
}
@ -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) {

View file

@ -176,7 +176,7 @@ path_xmr: {:#?}\n
}
Tab::Xvb => {
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::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::regex::num_lines;
use crate::utils::constants::{
GREEN, LIGHT_GRAY, ORANGE, RED, XVB_DONATED_1H_FIELD, XVB_DONATED_24H_FIELD, XVB_FAILURE_FIELD,
XVB_HELP, XVB_HERO_SELECT, XVB_ROUND_TYPE_FIELD, XVB_TOKEN_FIELD, XVB_TOKEN_LEN, XVB_URL_RULES,
XVB_WINNER_FIELD,
GREEN, LIGHT_GRAY, ORANGE, RED, XVB_DONATED_1H_FIELD, XVB_DONATED_24H_FIELD,
XVB_DONATION_LEVEL_DONOR_HELP, XVB_DONATION_LEVEL_MEGA_DONOR_HELP,
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::regex::Regexes;
@ -23,6 +30,7 @@ use crate::{
impl crate::disk::state::Xvb {
#[inline(always)] // called once
#[allow(clippy::too_many_arguments)]
pub fn show(
&mut self,
size: Vec2,
@ -30,230 +38,368 @@ impl crate::disk::state::Xvb {
_ctx: &egui::Context,
ui: &mut egui::Ui,
api: &Arc<Mutex<PubXvbApi>>,
private_stats: bool,
gui_api_xmrig: &Arc<Mutex<PubXmrigApi>>,
is_alive: bool,
) {
let website_height = size.y / 10.0;
let width = size.x;
let height = size.y;
let space_h = height / 48.0;
egui::ScrollArea::vertical().show(ui, |ui| {
// logo and website link
ui.vertical_centered(|ui| {
ui.add_sized(
[width, website_height],
Image::from_bytes("bytes:/xvb.png", BYTES_XVB),
);
ui.style_mut().override_text_style = Some(TextStyle::Heading);
ui.add_space(space_h);
ui.hyperlink_to("XMRvsBeast", XVB_URL);
ui.add_space(space_h);
});
// console output for log
debug!("XvB Tab | Rendering [Console]");
ui.group(|ui| {
let text = &lock!(api).output;
let nb_lines = num_lines(text);
let height = size.y / 2.8;
let width = size.x - (space_h / 2.0);
egui::Frame::none().fill(DARK_GRAY).show(ui, |ui| {
ui.style_mut().override_text_style = Some(Name("MonospaceSmall".into()));
egui::ScrollArea::vertical()
.stick_to_bottom(true)
.max_width(width)
.max_height(height)
.auto_shrink([false; 2])
// .show_viewport(ui, |ui, _| {
.show_rows(
ui,
ui.text_style_height(&TextStyle::Name("MonospaceSmall".into())),
nb_lines,
|ui, row_range| {
for i in row_range {
if let Some(line) = text.lines().nth(i) {
ui.label(line);
let text_edit = size.y / 25.0;
let website_height = size.y / 10.0;
let width = size.x;
let height = size.y;
let space_h = height / 48.0;
// logo and website link
ui.vertical_centered(|ui| {
ui.add_sized(
[width, website_height],
Image::from_bytes("bytes:/xvb.png", BYTES_XVB),
);
ui.style_mut().override_text_style = Some(TextStyle::Heading);
ui.add_space(space_h);
ui.hyperlink_to("XMRvsBeast", XVB_URL);
ui.add_space(space_h);
});
// console output for log
debug!("XvB Tab | Rendering [Console]");
ui.group(|ui| {
let text = &lock!(api).output;
let nb_lines = num_lines(text);
let height = size.y / 2.8;
let width = size.x - (space_h / 2.0);
egui::Frame::none().fill(DARK_GRAY).show(ui, |ui| {
ui.style_mut().override_text_style = Some(Name("MonospaceSmall".into()));
egui::ScrollArea::vertical()
.stick_to_bottom(true)
.max_width(width)
.max_height(height)
.auto_shrink([false; 2])
// .show_viewport(ui, |ui, _| {
.show_rows(
ui,
ui.text_style_height(&TextStyle::Name("MonospaceSmall".into())),
nb_lines,
|ui, row_range| {
for i in row_range {
if let Some(line) = text.lines().nth(i) {
ui.label(line);
}
}
}
},
);
},
);
});
});
});
// input token
let len_token = format!("{}", self.token.len());
let (text, color) = if self.token.is_empty() {
(
format!("{} [{}/{}] ", XVB_TOKEN_FIELD, len_token, XVB_TOKEN_LEN),
LIGHT_GRAY,
)
} else if self.token.parse::<u32>().is_ok() && self.token.len() < XVB_TOKEN_LEN {
(
format!("{} [{}/{}]", XVB_TOKEN_FIELD, len_token, XVB_TOKEN_LEN),
GREEN,
)
} else if self.token.parse::<u32>().is_ok() && self.token.len() == XVB_TOKEN_LEN {
(format!("{}", XVB_TOKEN_FIELD), GREEN)
} else {
(
format!("{} [{}/{}] ❌", XVB_TOKEN_FIELD, len_token, XVB_TOKEN_LEN),
RED,
)
};
ui.add_space(space_h);
ui.horizontal(|ui| {
// hovering text is difficult because egui doesn't hover over inner widget. But on disabled does.
ui.group(|ui| {
ui.colored_label(color, text)
.on_hover_text(XVB_HELP);
ui.add(
TextEdit::singleline(&mut self.token)
.char_limit(9)
.desired_width(ui.text_style_height(&TextStyle::Body) * 9.0)
.vertical_align(egui::Align::Center),
).on_hover_text(XVB_HELP)
});
// .on_hover_text(XVB_HELP);
ui.add_space(height / 48.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_spacing = space_h;
if ui.checkbox(&mut self.hero, "Hero Mode").on_hover_text(XVB_HERO_SELECT).clicked() {
// input token
let len_token = format!("{}", self.token.len());
let (text, color) = if self.token.is_empty() {
(
format!("{} [{}/{}] ", XVB_TOKEN_FIELD, len_token, XVB_TOKEN_LEN),
LIGHT_GRAY,
)
} else if self.token.parse::<u32>().is_ok() && self.token.len() < XVB_TOKEN_LEN {
(
format!("{} [{}/{}]", XVB_TOKEN_FIELD, len_token, XVB_TOKEN_LEN),
GREEN,
)
} else if self.token.parse::<u32>().is_ok() && self.token.len() == XVB_TOKEN_LEN {
(format!("{}", XVB_TOKEN_FIELD), GREEN)
} else {
(
format!("{} [{}/{}] ❌", XVB_TOKEN_FIELD, len_token, XVB_TOKEN_LEN),
RED,
)
};
ui.add_space(space_h);
ui.horizontal(|ui| {
// hovering text is difficult because egui doesn't hover over inner widget. But on disabled does.
ui.group(|ui| {
ui.colored_label(color, text)
.on_hover_text(XVB_HELP);
ui.add(
TextEdit::singleline(&mut self.token)
.char_limit(9)
.desired_width(ui.text_style_height(&TextStyle::Body) * 9.0)
.vertical_align(egui::Align::Center),
).on_hover_text(XVB_HELP)
});
// .on_hover_text(XVB_HELP);
ui.add_space(height / 48.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_spacing = space_h;
// --------------------------- 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.
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) {
ui.add_space(width / 16.0);
debug!("XvB Tab | Rendering warning text");
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.")
.color(ORANGE));
.color(ORANGE));
});
}
});
// private stats
ui.add_space(space_h);
// ui.add_enabled_ui(private_stats, |ui| {
ui.add_enabled_ui(private_stats, |ui| {
let api = &lock!(api);
let priv_stats = &api.stats_priv;
let current_node = &api.current_node;
let width_stat = (ui.available_width() - SPACE * 4.0) / 5.0;
let height_stat = 0.0;
let size_stat = vec2(width_stat, height_stat);
ui.horizontal(|ui| {
let round = match &priv_stats.round_participate {
Some(r) => r.to_string(),
None => "None".to_string(),
};
ui.add_sized(size_stat, |ui: &mut Ui| {
ui.group(|ui| {
let size_stat = vec2(
ui.available_width(),
0.0, // + ui.spacing().item_spacing.y,
);
ui.add_sized(size_stat, |ui: &mut Ui| {
ui.vertical_centered(|ui| {
ui.label(XVB_FAILURE_FIELD);
ui.label(priv_stats.fails.to_string());
})
.response
});
ui.separator();
ui.add_sized(size_stat, |ui: &mut Ui| {
ui.vertical_centered(|ui| {
ui.label(XVB_DONATED_1H_FIELD);
ui.label(
[
Float::from_3(priv_stats.donor_1hr_avg as f64).to_string(),
" kH/s".to_string(),
]
.concat(),
);
})
.response
});
ui.separator();
ui.add_sized(size_stat, |ui: &mut Ui| {
ui.vertical_centered(|ui| {
ui.label(XVB_DONATED_24H_FIELD);
ui.label(
[
Float::from_3(priv_stats.donor_24hr_avg as f64).to_string(),
" kH/s".to_string(),
]
.concat(),
);
})
.response
});
ui.separator();
ui.add_enabled_ui(priv_stats.round_participate.is_some(), |ui| {
// private stats
ui.add_space(space_h);
// ui.add_enabled_ui(is_alive, |ui| {
ui.add_enabled_ui(is_alive, |ui| {
let api = &lock!(api);
let priv_stats = &api.stats_priv;
let current_node = &api.current_node;
let width_stat = (ui.available_width() - SPACE * 4.0) / 5.0;
let height_stat = 0.0;
let size_stat = vec2(width_stat, height_stat);
ui.horizontal(|ui| {
let round = match &priv_stats.round_participate {
Some(r) => r.to_string(),
None => "None".to_string(),
};
ui.add_sized(size_stat, |ui: &mut Ui| {
ui.group(|ui| {
let size_stat = vec2(
ui.available_width(),
0.0, // + ui.spacing().item_spacing.y,
);
ui.add_sized(size_stat, |ui: &mut Ui| {
ui.vertical_centered(|ui| {
ui.label(XVB_ROUND_TYPE_FIELD);
ui.label(round);
ui.label(XVB_FAILURE_FIELD);
ui.label(priv_stats.fails.to_string());
})
.response
});
ui.separator();
ui.add_sized(size_stat, |ui: &mut Ui| {
ui.vertical_centered(|ui| {
ui.label(XVB_DONATED_1H_FIELD);
ui.label(
[
Float::from_3(priv_stats.donor_1hr_avg as f64).to_string(),
" kH/s".to_string(),
]
.concat(),
);
})
.response
});
ui.separator();
ui.add_sized(size_stat, |ui: &mut Ui| {
ui.vertical_centered(|ui| {
ui.label(XVB_DONATED_24H_FIELD);
ui.label(
[
Float::from_3(priv_stats.donor_24hr_avg as f64).to_string(),
" kH/s".to_string(),
]
.concat(),
);
})
.response
});
ui.separator();
ui.add_enabled_ui(priv_stats.round_participate.is_some(), |ui| {
ui.add_sized(size_stat, |ui: &mut Ui| {
ui.vertical_centered(|ui| {
ui.label(XVB_ROUND_TYPE_FIELD);
ui.label(round);
})
.response
})
.on_disabled_hover_text(
"You do not yet have a share in the PPLNS Window.",
);
});
ui.separator();
ui.add_sized(size_stat, |ui: &mut Ui| {
ui.vertical_centered(|ui| {
ui.label(XVB_WINNER_FIELD);
ui.label(if priv_stats.win_current {
"You are Winning the round !"
} else {
"You are not the winner"
});
})
.response
});
})
.response
});
});
// indicators
ui.horizontal(|ui| {
ui.add_sized(size_stat, |ui: &mut Ui| {
ui.group(|ui| {
let size_stat = vec2(
ui.available_width(),
0.0, // + ui.spacing().item_spacing.y,
);
ui.add_sized(size_stat, |ui: &mut Ui| {
ui.vertical_centered(|ui| {
ui.label(XVB_MINING_ON_FIELD)
.on_hover_text_at_pointer(&priv_stats.msg_indicator);
ui.label(
current_node
.as_ref()
.map_or("No where".to_string(), |n| n.to_string()),
)
.on_hover_text_at_pointer(&priv_stats.msg_indicator);
ui.label(Uptime::from(priv_stats.time_switch_node).to_string())
.on_hover_text_at_pointer(&priv_stats.msg_indicator)
})
.response
})
.on_disabled_hover_text(
"You do not yet have a share in the PPLNS Window.",
);
});
ui.separator();
ui.add_sized(size_stat, |ui: &mut Ui| {
ui.vertical_centered(|ui| {
ui.label(XVB_WINNER_FIELD);
ui.label(if priv_stats.win_current {
"You are Winning the round !"
} else {
"You are not the winner"
});
})
.response
});
})
.response
.on_disabled_hover_text("Algorithm is not running.")
})
.response
// currently mining on
});
});
// indicators
ui.horizontal(|ui| {
ui.add_sized(size_stat, |ui: &mut Ui| {
ui.group(|ui| {
let size_stat = vec2(
ui.available_width(),
0.0, // + ui.spacing().item_spacing.y,
);
ui.add_sized(size_stat, |ui: &mut Ui| {
ui.vertical_centered(|ui| {
ui.label(XVB_MINING_ON_FIELD)
.on_hover_text_at_pointer(&priv_stats.msg_indicator);
ui.label(
current_node
.as_ref()
.map_or("No where".to_string(), |n| n.to_string()),
)
.on_hover_text_at_pointer(&priv_stats.msg_indicator);
ui.label(Uptime::from(priv_stats.time_switch_node).to_string())
.on_hover_text_at_pointer(&priv_stats.msg_indicator)
})
.response
})
})
.response
.on_disabled_hover_text("Algorithm is not running.")
})
// currently mining on
// Rules link help
ui.horizontal_centered(|ui| {
// can't have horizontal and vertical centering work together so fix by this.
ui.add_space((width / 2.0) - (ui.text_style_height(&TextStyle::Heading) * 1.5));
ui.style_mut().override_text_style = Some(TextStyle::Heading);
ui.hyperlink_to("Rules", XVB_URL_RULES)
.on_hover_text("Click here to read the rules and understand how the raffle works.");
});
});
// Rules link help
ui.horizontal_centered(|ui| {
// can't have horizontal and vertical centering work together so fix by this.
ui.add_space((width / 2.0) - (ui.text_style_height(&TextStyle::Heading) * 1.5));
ui.style_mut().override_text_style = Some(TextStyle::Heading);
ui.hyperlink_to("Rules", XVB_URL_RULES)
.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 simple: bool,
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)]
@ -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 {
fn default() -> Self {
Self {

View file

@ -125,6 +125,13 @@ mod test {
redirect_local_xmrig = true
[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 = ""
hero = false
node = "Europe"

View file

@ -491,13 +491,15 @@ impl Helper {
// 4. Loop as watchdog
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!");
loop {
// Set timer
let now = Instant::now();
debug!("P2Pool Watchdog | ----------- Start of loop -----------");
lock!(gui_api).tick += 1;
lock!(gui_api).tick_status += 1;
lock!(gui_api).tick = (last_p2pool_request.elapsed().as_secs() % 60) as u8;
// Check if the process is secretly died without us knowing :)
if check_died(
@ -541,7 +543,13 @@ impl Helper {
}
}
// 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");
if let (Ok(network_api), Ok(pool_api)) = (
Self::path_to_string(&api_path_network, ProcessName::P2pool),
@ -552,11 +560,15 @@ impl Helper {
PrivP2poolPoolApi::from_str(&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
{
debug!("P2Pool Watchdog | Reading status output of p2pool node");
@ -572,7 +584,7 @@ impl Helper {
if let Err(e) = stdin.flush() {
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)
@ -663,9 +675,6 @@ pub struct PubP2poolApi {
// Tick. Every loop this gets incremented.
// At 60, it indicated we should read the below API files.
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
pub monero_difficulty: HumanNumber, // e.g: [15,000,000]
pub monero_hashrate: HumanNumber, // e.g: [1.000 GH/s]
@ -716,7 +725,6 @@ impl PubP2poolApi {
current_effort: HumanNumber::unknown(),
connections: HumanNumber::unknown(),
tick: 0,
tick_status: 0,
user_p2pool_hashrate_u64: 0,
p2pool_difficulty_u64: 0,
monero_difficulty_u64: 0,
@ -755,7 +763,6 @@ impl PubP2poolApi {
*gui_api = Self {
output,
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_ehr: std::mem::take(&mut gui_api.sidechain_ehr),
..pub_api.clone()
@ -993,66 +1000,66 @@ impl PubP2poolApi {
// let blanks = " ".repeat(60 - (self.tick - 1));
// [use crate::PubP2poolApi;use crate::PubP2poolApi;"[", &stars, &blanks, "]"].concat().as_str()
match self.tick {
1 => "[ ]",
2 => "[* ]",
3 => "[** ]",
4 => "[*** ]",
5 => "[**** ]",
6 => "[***** ]",
7 => "[****** ]",
8 => "[******* ]",
9 => "[******** ]",
10 => "[********* ]",
11 => "[********** ]",
12 => "[*********** ]",
13 => "[************ ]",
14 => "[************* ]",
15 => "[************** ]",
16 => "[*************** ]",
17 => "[**************** ]",
18 => "[***************** ]",
19 => "[****************** ]",
20 => "[******************* ]",
21 => "[******************** ]",
22 => "[********************* ]",
23 => "[********************** ]",
24 => "[*********************** ]",
25 => "[************************ ]",
26 => "[************************* ]",
27 => "[************************** ]",
28 => "[*************************** ]",
29 => "[**************************** ]",
30 => "[***************************** ]",
31 => "[****************************** ]",
32 => "[******************************* ]",
33 => "[******************************** ]",
34 => "[********************************* ]",
35 => "[********************************** ]",
36 => "[*********************************** ]",
37 => "[************************************ ]",
38 => "[************************************* ]",
39 => "[************************************** ]",
40 => "[*************************************** ]",
41 => "[**************************************** ]",
42 => "[***************************************** ]",
43 => "[****************************************** ]",
44 => "[******************************************* ]",
45 => "[******************************************** ]",
46 => "[********************************************* ]",
47 => "[********************************************** ]",
48 => "[*********************************************** ]",
49 => "[************************************************ ]",
50 => "[************************************************* ]",
51 => "[************************************************** ]",
52 => "[*************************************************** ]",
53 => "[**************************************************** ]",
54 => "[***************************************************** ]",
55 => "[****************************************************** ]",
56 => "[******************************************************* ]",
57 => "[******************************************************** ]",
58 => "[********************************************************* ]",
59 => "[********************************************************** ]",
60 => "[*********************************************************** ]",
0 => "[ ]",
1 => "[* ]",
2 => "[** ]",
3 => "[*** ]",
4 => "[**** ]",
5 => "[***** ]",
6 => "[****** ]",
7 => "[******* ]",
8 => "[******** ]",
9 => "[********* ]",
10 => "[********** ]",
11 => "[*********** ]",
12 => "[************ ]",
13 => "[************* ]",
14 => "[************** ]",
15 => "[*************** ]",
16 => "[**************** ]",
17 => "[***************** ]",
18 => "[****************** ]",
19 => "[******************* ]",
20 => "[******************** ]",
21 => "[********************* ]",
22 => "[********************** ]",
23 => "[*********************** ]",
24 => "[************************ ]",
25 => "[************************* ]",
26 => "[************************** ]",
27 => "[*************************** ]",
28 => "[**************************** ]",
29 => "[***************************** ]",
30 => "[****************************** ]",
31 => "[******************************* ]",
32 => "[******************************** ]",
33 => "[********************************* ]",
34 => "[********************************** ]",
35 => "[*********************************** ]",
36 => "[************************************ ]",
37 => "[************************************* ]",
38 => "[************************************** ]",
39 => "[*************************************** ]",
40 => "[**************************************** ]",
41 => "[***************************************** ]",
42 => "[****************************************** ]",
43 => "[******************************************* ]",
44 => "[******************************************** ]",
45 => "[********************************************* ]",
46 => "[********************************************** ]",
47 => "[*********************************************** ]",
48 => "[************************************************ ]",
49 => "[************************************************* ]",
50 => "[************************************************** ]",
51 => "[*************************************************** ]",
52 => "[**************************************************** ]",
53 => "[***************************************************** ]",
54 => "[****************************************************** ]",
55 => "[******************************************************* ]",
56 => "[******************************************************** ]",
57 => "[********************************************************* ]",
58 => "[********************************************************** ]",
59 => "[*********************************************************** ]",
_ => "[************************************************************]",
}
}

View file

@ -1,9 +1,11 @@
#[cfg(test)]
mod test {
use crate::helper::xrig::xmrig_proxy::PubXmrigProxyApi;
use crate::helper::xvb::algorithm::Algorithm;
use crate::helper::{
p2pool::{PrivP2poolLocalApi, PrivP2poolNetworkApi},
xvb::{algorithm::calcul_donated_time, rounds::round_type},
xvb::{priv_stats::RuntimeDonationLevel, priv_stats::RuntimeMode},
Helper, Process, ProcessName, ProcessState,
};
@ -509,9 +511,8 @@ Uptime = 0h 2m 4s
use crate::{
disk::state::P2pool,
helper::{p2pool::PubP2poolApi, xrig::xmrig::PubXmrigApi, xvb::rounds::XvbRound},
helper::{p2pool::PubP2poolApi, xrig::xmrig::PubXmrigApi},
macros::lock,
XVB_TIME_ALGO,
};
use crate::helper::xvb::{public_stats::XvbPubStats, PubXvbApi};
@ -527,254 +528,230 @@ Uptime = 0h 2m 4s
async fn corr(client: &Client) -> XvbPubStats {
XvbPubStats::request_api(client).await.unwrap()
}
#[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_p2pool = Arc::new(Mutex::new(PubP2poolApi::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();
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;
// 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_xvb).stats_priv.donor_1hr_avg = 0.0;
lock!(gui_api_xmrig).hashrate_raw_15m = 5000.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,
lock!(gui_api_xmrig).hashrate_raw_15m = 10000.0;
lock!(gui_api_xvb).stats_priv.runtime_mode = RuntimeMode::ManualXvb;
lock!(gui_api_xvb).stats_priv.runtime_manual_amount = 1000.0;
let algo = Algorithm::new(
&client,
&pub_api,
&gui_api_xvb,
&state_p2pool,
);
// 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_xmrig,
&gui_api_xp,
&gui_api_p2pool,
&gui_api_xvb,
token_xmrig,
&state_p2pool,
share,
&time_donated,
rig,
xp_alive,
);
assert_eq!(given_time, 45);
// 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 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
lock!(gui_api_xvb).stats_priv.donor_1hr_avg = 0.0;
lock!(gui_api_xmrig).hashrate_raw_15m = 8000.0;
lock!(gui_api_xvb).stats_priv.runtime_hero_mode = false;
let given_time = calcul_donated_time(
lock!(gui_api_xmrig).hashrate_raw_15m,
assert_eq!(algo.stats.target_donation_hashrate, 1000.0);
}
#[test]
fn test_manual_p2pool_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_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 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_xvb,
token_xmrig,
&state_p2pool,
share,
&time_donated,
rig,
xp_alive,
);
// verify that default mode will give x seconds
assert_eq!(given_time, 75);
// 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::Donor));
// 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,
assert_eq!(algo.stats.target_donation_hashrate, 9000.0);
}
#[test]
fn test_manual_donor_level_mode_donor() {
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_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 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::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_xvb,
token_xmrig,
&state_p2pool,
share,
&time_donated,
rig,
xp_alive,
);
assert_eq!(given_time, 253);
// 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::Donor));
// 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
lock!(gui_api_xvb).stats_priv.donor_1hr_avg = 0.0;
lock!(gui_api_xmrig).hashrate_raw_15m = 19000.0;
lock!(gui_api_xvb).stats_priv.runtime_hero_mode = false;
let given_time = calcul_donated_time(
lock!(gui_api_xmrig).hashrate_raw_15m,
assert_eq!(algo.stats.target_donation_hashrate, 1000.0);
}
#[test]
fn test_auto_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_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 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_xvb,
token_xmrig,
&state_p2pool,
share,
&time_donated,
rig,
xp_alive,
);
// verify that default mode will give x seconds
assert_eq!(given_time, 316);
// 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::DonorVip));
// 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,
assert_eq!(algo.stats.target_donation_hashrate, 10000.0);
lock!(gui_api_p2pool).p2pool_difficulty_u64 = 95_000_000;
lock!(gui_api_xmrig).hashrate_raw_15m = 10000.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_xvb,
token_xmrig,
&state_p2pool,
share,
&time_donated,
rig,
xp_alive,
);
assert_eq!(given_time, 454);
// 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::DonorVip));
// 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
lock!(gui_api_xvb).stats_priv.donor_1hr_avg = 0.0;
lock!(gui_api_xmrig).hashrate_raw_15m = 105000.0;
lock!(gui_api_xvb).stats_priv.runtime_hero_mode = false;
let given_time = calcul_donated_time(
lock!(gui_api_xmrig).hashrate_raw_15m,
assert_eq!(algo.stats.target_donation_hashrate, 1000.0);
}
#[test]
fn test_hero_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_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 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_xvb,
token_xmrig,
&state_p2pool,
share,
&time_donated,
rig,
xp_alive,
);
// verify that default mode will give x seconds
assert_eq!(given_time, 572);
// 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::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,
assert_eq!(algo.stats.target_donation_hashrate, 15382.1);
lock!(gui_api_p2pool).sidechain_ehr = 25000.0;
let algo = Algorithm::new(
&client,
&pub_api,
&gui_api_xvb,
&gui_api_xmrig,
&gui_api_xp,
&gui_api_p2pool,
&gui_api_xvb,
token_xmrig,
&state_p2pool,
share,
&time_donated,
rig,
xp_alive,
);
assert_eq!(given_time, 573);
// 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::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));
assert_eq!(algo.stats.target_donation_hashrate, 20000.0);
}
}

View file

@ -70,7 +70,11 @@ impl Helper {
// updating current node to None, will stop sending signal of FailedNode until new node is set
// send signal to update node.
warn!("XMRig PTY Parse | node is offline, sending signal to update nodes.");
lock!(process_xvb).signal = ProcessSignal::UpdateNodes(current_node);
// 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!(pub_api_xvb).current_node = None;
}
}

View file

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

View file

@ -1,7 +1,6 @@
use crate::helper::xrig::xmrig_proxy::PubXmrigProxyApi;
use crate::helper::xvb::api_url_xmrig;
use crate::helper::xvb::current_controllable_hr;
use crate::helper::ProcessName;
use crate::miscs::output_console;
use crate::miscs::output_console_without_time;
use std::{
@ -9,8 +8,7 @@ use std::{
time::Duration,
};
use log::{debug, info, warn};
use readable::num::Float;
use log::{info, warn};
use reqwest::Client;
use tokio::time::sleep;
@ -18,7 +16,7 @@ use crate::{
helper::{
p2pool::PubP2poolApi,
xrig::{update_xmrig_config, xmrig::PubXmrigApi},
xvb::nodes::XvbNode,
xvb::{nodes::XvbNode, priv_stats::RuntimeMode},
},
macros::lock,
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,
};
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)]
pub(crate) async fn algorithm(
client: &Client,
pub_api: &Arc<Mutex<PubXvbApi>>,
gui_api_xvb: &Arc<Mutex<PubXvbApi>>,
gui_api_xmrig: &Arc<Mutex<PubXmrigApi>>,
gui_api_xp: &Arc<Mutex<PubXmrigProxyApi>>,
@ -272,146 +41,524 @@ pub(crate) async fn algorithm(
rig: &str,
xp_alive: bool,
) {
debug!("Xvb Process | Algorithm is started");
output_console(
&mut lock!(gui_api_xvb).output,
"Algorithm of distribution HR started for the next ten minutes.",
ProcessName::Xvb,
let mut algorithm = Algorithm::new(
client,
pub_api,
gui_api_xvb,
gui_api_xmrig,
gui_api_xp,
gui_api_p2pool,
token_xmrig,
state_p2pool,
share,
time_donated,
rig,
xp_alive,
);
// 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
algorithm.run().await;
}
output_console(
&mut lock!(gui_api_xvb).output,
"At least one share is in current PPLNS window.",
ProcessName::Xvb,
);
#[allow(dead_code)]
pub struct Algorithm<'a> {
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,
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);
*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,
&api_url,
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();
}
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;
}
// sleep 10m less spared time then request XMrig to mine on XvB
sleep_then_update_node_xmrig(
time_donated,
client,
&api_url,
token_xmrig,
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,
)
.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),
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
);
lock!(gui_api_xvb)
.xvb_sent_last_hour_samples
.0
.push_back(hashrate_xmrig * (time_donated as f32 / XVB_TIME_ALGO as f32));
} else {
// no share, so we mine on p2pool. We update xmrig only if it was still mining on XvB.
if lock!(gui_api_xvb).current_node != Some(XvbNode::P2pool) {
info!("Xvb Process | request {msg_xmrig_or_xp}to mine on p2pool");
if let Err(err) = update_xmrig_config(
client,
&api_url,
token_xmrig,
self.client,
&self.stats.api_url,
self.token_xmrig,
&XvbNode::P2pool,
address,
rig,
&self.stats.address,
self.rig,
)
.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(
&mut lock!(gui_api_xvb).output,
&mut lock!(self.gui_api_xvb).output,
&format!(
"Failure to update {msg_xmrig_or_xp}config with HTTP API.\nError: {}",
err
"Failure to update {} config with HTTP API.\nError: {}",
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 !",
ProcessName::Xvb,
}
async fn target_xvb_node(&self) {
let node = lock!(self.gui_api_xvb).stats_priv.node;
info!(
"Algorithm | request {} to mine on XvB",
self.stats.msg_xmrig_or_xp
);
output_console(
&mut lock!(gui_api_xvb).output,
"Mining on P2pool for the next ten minutes.",
ProcessName::Xvb,
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(
&mut lock!(self.gui_api_xvb).output,
&format!(
"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;
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
.0
.push_back(hr);
lock!(gui_api_xvb)
.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);
}
// algorithm has run, so do not retry but run normally
// put a space to mark the difference with the next run.
output_console_without_time(&mut lock!(gui_api_xvb).output, "", ProcessName::Xvb);
async fn send_all_xvb(&self) {
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
if first_loop {
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.
if check_state_outcauses_xvb(
@ -234,11 +236,11 @@ impl Helper {
{
continue;
}
// check signal
debug!("XvB | check signal");
if signal_interrupt(
process,
if xp_alive { process_xp } else { process_xmrig },
start.into(),
&client,
pub_api,
@ -317,7 +319,8 @@ impl Helper {
}
}
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.
*lock!(retry) = false;
@ -336,6 +339,7 @@ impl Helper {
};
algorithm(
&client,
&pub_api,
&gui_api,
&gui_api_xmrig,
&gui_api_xp,
@ -351,7 +355,7 @@ impl Helper {
} 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 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
}
}
@ -368,9 +372,9 @@ impl Helper {
// show this message only once before the start of algo
if *lock!(retry) && !msg_retry_done {
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 {
"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);
msg_retry_done = true;
@ -441,11 +445,14 @@ impl PubXvbApi {
if !buf.is_empty() {
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 {
output,
stats_priv: XvbPrivStats {
runtime_hero_mode,
runtime_mode,
runtime_manual_amount,
..pub_api.stats_priv.clone()
},
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);
ProcessState::Syncing
} 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
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)]
fn signal_interrupt(
process: &Arc<Mutex<Process>>,
process_xrig: &Arc<Mutex<Process>>,
start: Instant,
client: &Client,
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 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 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.
lock!(process).state = ProcessState::Waiting;
lock!(process).signal = ProcessSignal::None;
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");
match node {
XvbNode::NorthAmerica|XvbNode::Europe if was_alive => {
@ -774,42 +781,42 @@ fn signal_interrupt(
// 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.
// Need to set XMRig to P2Pool if it wasn't. XMRig should have populated this value at his start.
if lock!(gui_api).current_node != Some(XvbNode::P2pool) {
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);
warn!("update xmrig to use node ?");
if let Err(err) = update_xmrig_config(
&client,
&url_api,
&token_xmrig,
&XvbNode::P2pool,
&address,
&rig
)
.await {
let msg_xmrig_or_proxy = if xp_alive {
"XMRig-Proxy"
} else {
"XMRig"
};
output_console(
&mut lock!(gui_api).output,
&format!(
"Failure to update {msg_xmrig_or_proxy} config with HTTP API.\nError: {}",
err
), ProcessName::Xvb
);
// but if xmrig didn't start, don't update it.
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{
let url_api = api_url_xmrig(xp_alive, true);
warn!("update xmrig to use node ?");
if let Err(err) = update_xmrig_config(
&client,
&url_api,
&token_xmrig,
&XvbNode::P2pool,
&address,
&rig
)
.await {
let msg_xmrig_or_proxy = if xp_alive {
"XMRig-Proxy"
} else {
// update node xmrig
if xp_alive {
lock!(gui_api_xp).node = XvbNode::P2pool.to_string();
} else {
lock!(gui_api_xmrig).node = XvbNode::P2pool.to_string();
};
}
"XMRig"
};
output_console(
&mut lock!(gui_api).output,
&format!(
"Failure to update {msg_xmrig_or_proxy} config with HTTP API.\nError: {}",
err
), ProcessName::Xvb
);
} else {
// update node xmrig
if xp_alive {
lock!(gui_api_xp).node = XvbNode::P2pool.to_string();
} else {
lock!(gui_api_xmrig).node = XvbNode::P2pool.to_string();
};
}
));}
}
));}
},
_ => {}
} } ),
@ -823,14 +830,17 @@ fn signal_interrupt(
}
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 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);
*lock!(pub_api) = PubXvbApi::new();
*lock!(gui_api) = PubXvbApi::new();
// to keep the value modified by xmrig even if xvb is dead.
lock!(pub_api).current_node = current_node;
// 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.
// lock!(pub_api).output = output;
}
@ -849,6 +859,7 @@ fn update_indicator_algo(
Some(XvbNode::P2pool) if time_donated > 0 => {
// algo is mining on p2pool but will switch to XvB after
// show time remaining on p2pool
lock!(pub_api).stats_priv.time_switch_node = XVB_TIME_ALGO
.checked_sub(last_algorithm.lock().unwrap().elapsed().as_secs() as u32)
.unwrap_or_default()

View file

@ -125,7 +125,7 @@ impl XvbNode {
&format!("XvB node ping, {} is selected as the fastest.", node),
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
// or by the start of xvb
// 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 crate::{
disk::state::ManualDonationLevel,
helper::{xvb::output_console, Process, ProcessName, ProcessState},
macros::lock,
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};
#[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)]
pub struct XvbPrivStats {
pub fails: u8,
@ -36,7 +71,11 @@ pub struct XvbPrivStats {
pub msg_indicator: String,
#[serde(skip)]
// 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 {
@ -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
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_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_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()
pub const UNKNOWN_DATA: &str = "???";
// Time PPLNS WINDOW in seconds