refactor: turn algorithm.rs structure into a struct with implementations

This commit is contained in:
mostafaei2002 2024-06-16 18:59:00 +03:30
parent b34839a793
commit efc156149b
2 changed files with 349 additions and 371 deletions

View file

@ -4,7 +4,6 @@ use std::{
};
use log::{debug, info, warn};
use readable::num::Float;
use reqwest::Client;
use tokio::time::sleep;
@ -24,288 +23,6 @@ use crate::{
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(gui_api_xvb, &msg_lhr);
output_console(gui_api_xvb, &msg_mhr);
output_console(gui_api_xvb, &msg_ehr);
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 can be spared
let mode = lock!(gui_api_xvb).stats_priv.runtime_mode.clone();
let default_spared_time = time_that_could_be_spared(lhr, min_hr);
let mut spared_time = match mode {
RuntimeMode::Auto => {
info!("RuntimeMode::Auto - calculating spared_time");
// calculate how much time needed to be spared to be in most round type minimum HR + buffer
minimum_time_for_highest_accessible_round(default_spared_time, lhr, xvb_chr, shr)
}
RuntimeMode::Hero => {
info!("RuntimeMode::Hero - calculating spared_time lhr:{lhr} min_hr:{min_hr}");
output_console(gui_api_xvb, "Hero mode is enabled for this decision");
default_spared_time
}
RuntimeMode::ManualXvb => {
let donate_hr = lock!(gui_api_xvb).stats_priv.runtime_manual_amount;
info!("RuntimeMode::ManualXvb - lhr:{lhr} donate_hr:{donate_hr}");
XVB_TIME_ALGO * (donate_hr as u32) / (lhr as u32)
}
RuntimeMode::ManualP2pool => {
let keep_hr = lock!(gui_api_xvb).stats_priv.runtime_manual_amount;
info!("RuntimeMode::ManualXvb - lhr:{lhr} keep_hr:{keep_hr}");
XVB_TIME_ALGO - (XVB_TIME_ALGO * (keep_hr as u32) / (lhr as u32))
}
RuntimeMode::ManualDonationLevel => {
let donation_level = lock!(gui_api_xvb)
.stats_priv
.runtime_manual_donation_level
.clone();
info!("RuntimeMode::ManualDonationLevel");
minimum_time_for_manual_round(donation_level, default_spared_time, lhr, xvb_chr, shr)
}
};
info!("Final spared_time is {spared_time}");
if spared_time > XVB_TIME_ALGO {
spared_time = XVB_TIME_ALGO;
}
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
}
fn minimum_time_for_manual_round(
level: RuntimeDonationLevel,
st: u32,
lhr: f32,
chr: f32,
shr: f32,
) -> u32 {
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;
let min = match level {
RuntimeDonationLevel::Donor => {
info!("RuntimeDonationLevel::Donor");
XVB_ROUND_DONOR_MIN_HR as f32 - ohr
}
RuntimeDonationLevel::DonorVIP => {
info!("RuntimeDonationLevel::DonorVIP");
XVB_ROUND_DONOR_VIP_MIN_HR as f32 - ohr
}
RuntimeDonationLevel::DonorWhale => {
info!("RuntimeDonationLevel::DonorWhale");
XVB_ROUND_DONOR_WHALE_MIN_HR as f32 - ohr
}
RuntimeDonationLevel::DonorMega => {
info!("RuntimeDonationLevel::DonorMega");
XVB_ROUND_DONOR_MEGA_MIN_HR as f32 - ohr
}
};
(((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>>,
rig: &str,
) {
let node = lock!(gui_api_xvb).stats_priv.node;
debug!(
"Xvb Process | algo sleep for {} while mining on P2pool",
XVB_TIME_ALGO - spared_time
);
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 xmrig 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) = PrivXmrigApi::update_xmrig_config(
client,
api_uri,
token_xmrig,
&node,
address,
gui_api_xmrig,
rig,
)
.await
{
// show to console error about updating xmrig config
warn!("Xvb Process | Failed request HTTP API Xmrig");
output_console(
gui_api_xvb,
&format!(
"Failure to update xmrig config with HTTP API.\nError: {}",
err
),
);
} else {
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,
@ -318,24 +35,63 @@ pub(crate) async fn algorithm(
time_donated: &Arc<Mutex<u32>>,
rig: &str,
) {
debug!("Xvb Process | Algorithm is started");
output_console(
let mut algorithm = Algorithm::new(
client,
gui_api_xvb,
"Algorithm of distribution HR started for the next ten minutes.",
gui_api_xmrig,
gui_api_p2pool,
token_xmrig,
state_p2pool,
share,
time_donated,
rig,
);
// 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,
if share > 0 {
debug!("Xvb Process | Algorithm share is in current window");
// calcul minimum HR
algorithm.run().await;
}
output_console(
gui_api_xvb,
"At least one share is in current PPLNS window.",
);
struct Algorithm<'a> {
client: &'a Client,
gui_api_xvb: &'a Arc<Mutex<PubXvbApi>>,
gui_api_xmrig: &'a Arc<Mutex<PubXmrigApi>>,
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,
stats: Stats,
}
#[derive(Debug)]
struct Stats {
share: u32,
hashrate_xmrig: f32,
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,
}
impl<'a> Algorithm<'a> {
fn new(
client: &'a Client,
gui_api_xvb: &'a Arc<Mutex<PubXvbApi>>,
gui_api_xmrig: &'a Arc<Mutex<PubXmrigApi>>,
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,
) -> Self {
let hashrate_xmrig = {
if lock!(gui_api_xmrig).hashrate_raw_15m > 0.0 {
lock!(gui_api_xmrig).hashrate_raw_15m
@ -346,87 +102,116 @@ pub(crate) async fn algorithm(
}
};
*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(
gui_api_xvb,
&format!(
"Mining on P2pool node for {} seconds then on XvB for {} seconds.",
XVB_TIME_ALGO - time_donated,
time_donated
),
);
let address = state_p2pool.address.clone();
// 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 xmrig to mine on p2pool");
if let Err(err) = PrivXmrigApi::update_xmrig_config(
client,
XMRIG_CONFIG_URI,
token_xmrig,
&XvbNode::P2pool,
address,
gui_api_xmrig,
rig,
)
.await
{
warn!("Xvb Process | Failed request HTTP API Xmrig");
output_console(
gui_api_xvb,
&format!(
"Failure to update xmrig config with HTTP API.\nError: {}",
err
),
);
}
let xvb_24h_avg = lock!(gui_api_xvb).stats_priv.donor_24hr_avg;
let xvb_1h_avg = lock!(gui_api_xvb).stats_priv.donor_1hr_avg;
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.clone();
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,
XMRIG_CONFIG_URI,
token_xmrig,
let mut share_min_hashrate = Self::minimum_hashrate_share(
lock!(gui_api_p2pool).p2pool_difficulty_u64,
state_p2pool.mini,
p2pool_external_hashrate,
);
if share_min_hashrate.is_sign_negative() {
info!("XvB Process | if minimum HR is negative, it is 0.");
share_min_hashrate = 0.0;
}
let spareable_hashrate = hashrate_xmrig - share_min_hashrate;
// TODO consider printing algorithm stats instead of spreadout print statements
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(),
};
let mut new_instace = Self {
client,
gui_api_xvb,
gui_api_xmrig,
"",
)
.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)
.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) {
gui_api_p2pool,
token_xmrig,
state_p2pool,
time_donated,
rig,
stats,
};
new_instace.stats.target_donation_hashrate = new_instace.get_target_donation_hashrate();
new_instace.stats.spared_time = ((new_instace.stats.target_donation_hashrate as u32)
/ (new_instace.stats.hashrate_xmrig as u32))
* XVB_TIME_ALGO;
info!("XvB Process | Starting Algorithm - Algorithm State:",);
info!("{:#?}", new_instace.stats);
new_instace
}
fn is_share_fulfilled(&self) -> bool {
self.stats.share > 0
}
fn is_xvb_24h_fulfilled(&self) -> bool {
self.stats.xvb_24h_avg > self.stats.target_donation_hashrate
}
fn xvb_1h_fulfilled(&self) -> bool {
self.stats.xvb_1h_avg > self.stats.target_donation_hashrate
}
async fn fulfill_xvb_1h(&self) {
self.mine_p2pool().await;
self.sleep_then_update_node_xmrig().await;
}
async fn mine_p2pool(&self) {
if lock!(self.gui_api_xvb).current_node != Some(XvbNode::P2pool) {
info!("Xvb Process | request xmrig to mine on p2pool");
if let Err(err) = PrivXmrigApi::update_xmrig_config(
client,
self.client,
XMRIG_CONFIG_URI,
token_xmrig,
self.token_xmrig,
&XvbNode::P2pool,
address,
gui_api_xmrig,
rig,
&self.stats.address,
self.gui_api_xmrig,
self.rig,
)
.await
{
warn!("Xvb Process | Failed request HTTP API Xmrig");
output_console(
gui_api_xvb,
self.gui_api_xvb,
&format!(
"Failure to update xmrig config with HTTP API.\nError: {}",
err
@ -434,19 +219,198 @@ pub(crate) async fn algorithm(
);
}
}
output_console(gui_api_xvb, "No share in the current PPLNS Window !");
output_console(gui_api_xvb, "Mining on P2pool for the next ten minutes.");
output_console(self.gui_api_xvb, "No share in the current PPLNS Window !");
output_console(
self.gui_api_xvb,
"Mining on P2pool for the next ten minutes.",
);
sleep(Duration::from_secs(XVB_TIME_ALGO.into())).await;
lock!(gui_api_xvb)
lock!(self.gui_api_xvb)
.p2pool_sent_last_hour_samples
.0
.push_back(lock!(gui_api_xmrig).hashrate_raw_15m);
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(gui_api_xvb, "");
async fn mine_xvb(&self) {
let node = lock!(self.gui_api_xvb).stats_priv.node;
debug!("Xvb Process | request xmrig to mine on 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) = PrivXmrigApi::update_xmrig_config(
self.client,
XMRIG_CONFIG_URI,
self.token_xmrig,
&node,
&self.stats.address,
self.gui_api_xmrig,
self.rig,
)
.await
{
// show to console error about updating xmrig config
warn!("Xvb Process | Failed request HTTP API Xmrig");
output_console(
self.gui_api_xvb,
&format!(
"Failure to update xmrig config with HTTP API.\nError: {}",
err
),
);
} else {
debug!("Xvb Process | mining on XvB pool");
}
}
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) {
let node = lock!(self.gui_api_xvb).stats_priv.node;
debug!(
"Xvb Process | algo sleep for {} 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.
debug!("Xvb Process | request xmrig to mine on 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) = PrivXmrigApi::update_xmrig_config(
self.client,
XMRIG_CONFIG_URI,
self.token_xmrig,
&node,
&self.stats.address,
self.gui_api_xmrig,
self.rig,
)
.await
{
// show to console error about updating xmrig config
warn!("Xvb Process | Failed request HTTP API Xmrig");
output_console(
self.gui_api_xvb,
&format!(
"Failure to update xmrig config with HTTP API.\nError: {}",
err
),
);
} else {
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(self.stats.spared_time.into())).await;
}
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 => self.stats.runtime_amount as f32,
RuntimeMode::ManualP2pool => {
(XVB_TIME_ALGO as f32) - (self.stats.runtime_amount as f32)
}
RuntimeMode::ManualDonationLevel => self.stats.runtime_donation_level.get_hashrate(),
}
}
fn get_auto_mode_target_donation_hashrate(&self) -> f32 {
// TODO fix wrong target hashrate being selected
// TODO consider using xvb_24h_avg for calculations
// TODO consider using dynamic buffer size buffer gets smaller as gupaxx runs for longer to provide more stability
let donation_level = match self.stats.spareable_hashrate {
x if x > (XVB_ROUND_DONOR_MIN_HR as f32) => Some(RuntimeDonationLevel::Donor),
x if x > (XVB_ROUND_DONOR_VIP_MIN_HR as f32) => Some(RuntimeDonationLevel::DonorVIP),
x if x > (XVB_ROUND_DONOR_WHALE_MIN_HR as f32) => {
Some(RuntimeDonationLevel::DonorWhale)
}
x if x > (XVB_ROUND_DONOR_MEGA_MIN_HR as f32) => Some(RuntimeDonationLevel::DonorMega),
_ => None,
};
if let Some(level) = donation_level {
level.get_hashrate()
} else {
0.0
}
}
fn get_hero_mode_target_donation_hashrate(&self) -> f32 {
// TODO improve selection method
// TODO consider using a large buffer size
// TODO consider manually setting the share count to aim for on hero mode
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 minimum_hr = ((difficulty / (pws * SECOND_PER_BLOCK_P2POOL)) as f32 * XVB_BUFFER)
- p2pool_external_hashrate;
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}) - {p2pool_external_hashrate} = {minimum_hr}");
minimum_hr
}
async fn run(&mut self) {
// TODO add console output for each step
if self.is_share_fulfilled() && self.is_xvb_24h_fulfilled() {
output_console(
self.gui_api_xvb,
"There is a share in p2pool and 24H avg XvB is achieved.",
);
output_console(self.gui_api_xvb, "Calculating donation time for XvB...");
self.fulfill_xvb_1h().await
} else if self.is_share_fulfilled() {
output_console(self.gui_api_xvb, "24H avg XvB target not achieved.");
output_console(self.gui_api_xvb, "Sending all hashrate to XvB");
self.mine_xvb().await
} else {
output_console(self.gui_api_xvb, "There are no shares in p2pool");
output_console(self.gui_api_xvb, "Sending all hashrate to p2pool");
self.mine_p2pool().await
}
output_console(self.gui_api_xvb, "")
}
}

View file

@ -9,13 +9,16 @@ use reqwest::{Client, StatusCode};
use serde::Deserialize;
use tokio::time::sleep;
use crate::disk::state::XvbMode;
use crate::{
disk::state::ManualDonationLevel,
helper::{xvb::output_console, Process, 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};
@ -38,6 +41,17 @@ pub enum RuntimeDonationLevel {
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,