mirror of
https://github.com/hinto-janai/gupax.git
synced 2025-03-12 09:31:38 +00:00
Status Submenu: add new API reads in P2Pool watchdog loop
This adds all necessary functions/conversions/serde/tests for the new APIs. It also includes the actual reads inside the watchdog loop. Every loop, [tick] will increment by 1. At [60], the watchdog will attempt to read and parse the [network] & [pool] APIs. Since the loop is [900ms], this means this will occur around every 54 seconds. [tick] gets reset upon successful read/parsing.
This commit is contained in:
parent
2846441049
commit
a6222bfa73
4 changed files with 213 additions and 46 deletions
|
@ -482,7 +482,7 @@ You need [`cargo`](https://www.rust-lang.org/learn/get-started), Rust's build to
|
||||||
|
|
||||||
The `--release` profile in Gupax is set to prefer code performance & small binary sizes over compilation speed (see [`Cargo.toml`](https://github.com/hinto-janaiyo/gupax/blob/main/Cargo.toml)). Gupax itself (with all dependencies already built) takes around 1m30s to build (vs 10s on a normal `--release`) with a Ryzen 5950x.
|
The `--release` profile in Gupax is set to prefer code performance & small binary sizes over compilation speed (see [`Cargo.toml`](https://github.com/hinto-janaiyo/gupax/blob/main/Cargo.toml)). Gupax itself (with all dependencies already built) takes around 1m30s to build (vs 10s on a normal `--release`) with a Ryzen 5950x.
|
||||||
|
|
||||||
There are `24` unit tests throughout the codebase files, you should probably run:
|
There are `25` unit tests throughout the codebase files, you should probably run:
|
||||||
```
|
```
|
||||||
cargo test
|
cargo test
|
||||||
```
|
```
|
||||||
|
|
228
src/helper.rs
228
src/helper.rs
|
@ -59,6 +59,10 @@ const MAX_GUI_OUTPUT_BYTES: usize = 500_000;
|
||||||
// Just a little leeway so a reset will go off before the [String] allocates more memory.
|
// Just a little leeway so a reset will go off before the [String] allocates more memory.
|
||||||
const GUI_OUTPUT_LEEWAY: usize = MAX_GUI_OUTPUT_BYTES - 1000;
|
const GUI_OUTPUT_LEEWAY: usize = MAX_GUI_OUTPUT_BYTES - 1000;
|
||||||
|
|
||||||
|
// Some constants for generating hashrate/difficulty.
|
||||||
|
const MONERO_BLOCK_TIME_IN_SECONDS: u64 = 120;
|
||||||
|
const P2POOL_BLOCK_TIME_IN_SECONDS: u64 = 10;
|
||||||
|
|
||||||
//---------------------------------------------------------------------------------------------------- [Helper] Struct
|
//---------------------------------------------------------------------------------------------------- [Helper] Struct
|
||||||
// A meta struct holding all the data that gets processed in this thread
|
// A meta struct holding all the data that gets processed in this thread
|
||||||
pub struct Helper {
|
pub struct Helper {
|
||||||
|
@ -503,10 +507,12 @@ impl Helper {
|
||||||
|
|
||||||
// 4. Loop as watchdog
|
// 4. Loop as watchdog
|
||||||
info!("P2Pool | Entering watchdog mode... woof!");
|
info!("P2Pool | Entering watchdog mode... woof!");
|
||||||
|
let mut tick = 0;
|
||||||
loop {
|
loop {
|
||||||
// Set timer
|
// Set timer
|
||||||
let now = Instant::now();
|
let now = Instant::now();
|
||||||
debug!("P2Pool Watchdog | ----------- Start of loop -----------");
|
debug!("P2Pool Watchdog | ----------- Start of loop -----------");
|
||||||
|
tick += 1;
|
||||||
|
|
||||||
// Check if the process is secretly died without us knowing :)
|
// Check if the process is secretly died without us knowing :)
|
||||||
if let Ok(Some(code)) = child_pty.lock().unwrap().try_wait() {
|
if let Ok(Some(code)) = child_pty.lock().unwrap().try_wait() {
|
||||||
|
@ -619,23 +625,18 @@ impl Helper {
|
||||||
debug!("P2Pool Watchdog | Attempting [local] API file read");
|
debug!("P2Pool Watchdog | Attempting [local] API file read");
|
||||||
if let Ok(string) = Self::path_to_string(&api_path_local, ProcessName::P2pool) {
|
if let Ok(string) = Self::path_to_string(&api_path_local, ProcessName::P2pool) {
|
||||||
// Deserialize
|
// Deserialize
|
||||||
if let Ok(s) = PrivP2poolLocalApi::from_str(&string) {
|
if let Ok(local_api) = PrivP2poolLocalApi::from_str(&string) {
|
||||||
// Update the structs.
|
// Update the structs.
|
||||||
PubP2poolApi::update_from_local(&pub_api, s);
|
PubP2poolApi::update_from_local(&pub_api, local_api);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// If more than 1 minute has passed, read the other API files.
|
// If more than 1 minute has passed, read the other API files.
|
||||||
if now.elapsed().as_secs() >= 60 {
|
if tick >= 60 {
|
||||||
debug!("P2Pool Watchdog | Attempting [network] API file read");
|
debug!("P2Pool Watchdog | Attempting [network] & [pool] API file read");
|
||||||
if let Ok(string) = Self::path_to_string(&api_path_network, ProcessName::P2pool) {
|
if let (Ok(network_api), Ok(pool_api)) = (Self::path_to_string(&api_path_network, ProcessName::P2pool), Self::path_to_string(&api_path_pool, ProcessName::P2pool)) {
|
||||||
if let Ok(s) = PrivP2poolNetworkApi::from_str(&string) {
|
if let (Ok(network_api), Ok(pool_api)) = (PrivP2poolNetworkApi::from_str(&network_api), PrivP2poolPoolApi::from_str(&pool_api)) {
|
||||||
// PubP2poolApi::update_from_network(&pub_api, s);
|
PubP2poolApi::update_from_network_pool(&pub_api, network_api, pool_api);
|
||||||
}
|
tick = 0;
|
||||||
}
|
|
||||||
debug!("P2Pool Watchdog | Attempting [pool] API file read");
|
|
||||||
if let Ok(string) = Self::path_to_string(&api_path_pool, ProcessName::P2pool) {
|
|
||||||
if let Ok(s) = PrivP2poolPoolApi::from_str(&string) {
|
|
||||||
// PubP2poolApi::update_from_network(&pub_api, s);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -645,10 +646,10 @@ impl Helper {
|
||||||
// Since logic goes off if less than 1000, casting should be safe
|
// Since logic goes off if less than 1000, casting should be safe
|
||||||
if elapsed < 900 {
|
if elapsed < 900 {
|
||||||
let sleep = (900-elapsed) as u64;
|
let sleep = (900-elapsed) as u64;
|
||||||
debug!("P2Pool Watchdog | END OF LOOP - Sleeping for [{}]ms...", sleep);
|
debug!("P2Pool Watchdog | END OF LOOP - Tick: [{}/60] - Sleeping for [{}]ms...", tick, sleep);
|
||||||
std::thread::sleep(std::time::Duration::from_millis(sleep));
|
std::thread::sleep(std::time::Duration::from_millis(sleep));
|
||||||
} else {
|
} else {
|
||||||
debug!("P2Pool Watchdog | END OF LOOP - Not sleeping!");
|
debug!("P2Pool Watchdog | END OF LOOP - Tick: [{}/60] Not sleeping!", tick);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1254,8 +1255,27 @@ pub struct PubP2poolApi {
|
||||||
pub average_effort: HumanNumber,
|
pub average_effort: HumanNumber,
|
||||||
pub current_effort: HumanNumber,
|
pub current_effort: HumanNumber,
|
||||||
pub connections: HumanNumber,
|
pub connections: HumanNumber,
|
||||||
|
// The API below needs a raw int [hashrate] to go off of and
|
||||||
|
// there's not a good way to access it without doing weird
|
||||||
|
// [Arc<Mutex>] shenanigans, so the raw [hashrate_1h] is
|
||||||
|
// copied here instead.
|
||||||
|
pub hashrate: u64,
|
||||||
// Network API
|
// Network API
|
||||||
|
pub monero_difficulty: HumanNumber, // e.g: [15,000,000]
|
||||||
|
pub monero_hashrate: HumanNumber, // e.g: [1.000 GH/s]
|
||||||
|
pub hash: String,
|
||||||
|
pub height: HumanNumber,
|
||||||
|
pub reward: u64, // Atomic units
|
||||||
// Pool API
|
// Pool API
|
||||||
|
pub p2pool_difficulty: HumanNumber,
|
||||||
|
pub p2pool_hashrate: HumanNumber,
|
||||||
|
pub miners: HumanNumber, // Current amount of miners on P2Pool sidechain
|
||||||
|
// Mean (calcualted in functions, not serialized)
|
||||||
|
pub solo_block_mean: HumanTime, // Time it would take the user to find a solo block
|
||||||
|
pub p2pool_block_mean: HumanTime, // Time it takes the P2Pool sidechain to find a block
|
||||||
|
pub p2pool_share_mean: HumanTime, // Time it would take the user to find a P2Pool share
|
||||||
|
// Percentage of P2Pool hashrate capture of overall Monero hashrate.
|
||||||
|
pub p2pool_percent: HumanNumber,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for PubP2poolApi {
|
impl Default for PubP2poolApi {
|
||||||
|
@ -1284,6 +1304,19 @@ impl PubP2poolApi {
|
||||||
average_effort: HumanNumber::unknown(),
|
average_effort: HumanNumber::unknown(),
|
||||||
current_effort: HumanNumber::unknown(),
|
current_effort: HumanNumber::unknown(),
|
||||||
connections: HumanNumber::unknown(),
|
connections: HumanNumber::unknown(),
|
||||||
|
hashrate: 0,
|
||||||
|
monero_difficulty: HumanNumber::unknown(),
|
||||||
|
monero_hashrate: HumanNumber::unknown(),
|
||||||
|
hash: String::from("???"),
|
||||||
|
height: HumanNumber::unknown(),
|
||||||
|
reward: 0,
|
||||||
|
p2pool_difficulty: HumanNumber::unknown(),
|
||||||
|
p2pool_hashrate: HumanNumber::unknown(),
|
||||||
|
miners: HumanNumber::unknown(),
|
||||||
|
solo_block_mean: HumanTime::new(),
|
||||||
|
p2pool_block_mean: HumanTime::new(),
|
||||||
|
p2pool_share_mean: HumanTime::new(),
|
||||||
|
p2pool_percent: HumanNumber::unknown(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1301,6 +1334,21 @@ impl PubP2poolApi {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Essentially greps the output for [x.xxxxxxxxxxxx XMR] where x = a number.
|
||||||
|
// It sums each match and counts along the way, handling an error by not adding and printing to console.
|
||||||
|
fn calc_payouts_and_xmr(output: &str, regex: &P2poolRegex) -> (u128 /* payout count */, f64 /* total xmr */) {
|
||||||
|
let iter = regex.payout.find_iter(output);
|
||||||
|
let mut sum: f64 = 0.0;
|
||||||
|
let mut count: u128 = 0;
|
||||||
|
for i in iter {
|
||||||
|
match regex.float.find(i.as_str()).unwrap().as_str().parse::<f64>() {
|
||||||
|
Ok(num) => { sum += num; count += 1; },
|
||||||
|
Err(e) => error!("P2Pool | Total XMR sum calculation error: [{}]", e),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
(count, sum)
|
||||||
|
}
|
||||||
|
|
||||||
// Mutate "watchdog"'s [PubP2poolApi] with data the process output.
|
// Mutate "watchdog"'s [PubP2poolApi] with data the process output.
|
||||||
fn update_from_output(public: &Arc<Mutex<Self>>, output_parse: &Arc<Mutex<String>>, output_pub: &Arc<Mutex<String>>, elapsed: std::time::Duration, regex: &P2poolRegex) {
|
fn update_from_output(public: &Arc<Mutex<Self>>, output_parse: &Arc<Mutex<String>>, output_pub: &Arc<Mutex<String>>, elapsed: std::time::Duration, regex: &P2poolRegex) {
|
||||||
// 1. Take the process's current output buffer and combine it with Pub (if not empty)
|
// 1. Take the process's current output buffer and combine it with Pub (if not empty)
|
||||||
|
@ -1359,34 +1407,65 @@ impl PubP2poolApi {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Mutate [PubP2poolApi] with data from a [PrivP2poolLocalApi] and the process output.
|
// Mutate [PubP2poolApi] with data from a [PrivP2poolLocalApi] and the process output.
|
||||||
fn update_from_local(public: &Arc<Mutex<Self>>, private: PrivP2poolLocalApi) {
|
fn update_from_local(public: &Arc<Mutex<Self>>, local: PrivP2poolLocalApi) {
|
||||||
// priv -> pub conversion
|
|
||||||
let mut public = public.lock().unwrap();
|
let mut public = public.lock().unwrap();
|
||||||
*public = Self {
|
*public = Self {
|
||||||
hashrate_15m: HumanNumber::from_u128(private.hashrate_15m),
|
hashrate_15m: HumanNumber::from_u64(local.hashrate_15m),
|
||||||
hashrate_1h: HumanNumber::from_u128(private.hashrate_1h),
|
hashrate_1h: HumanNumber::from_u64(local.hashrate_1h),
|
||||||
hashrate_24h: HumanNumber::from_u128(private.hashrate_24h),
|
hashrate_24h: HumanNumber::from_u64(local.hashrate_24h),
|
||||||
shares_found: HumanNumber::from_u128(private.shares_found),
|
shares_found: HumanNumber::from_u64(local.shares_found),
|
||||||
average_effort: HumanNumber::to_percent(private.average_effort),
|
average_effort: HumanNumber::to_percent(local.average_effort),
|
||||||
current_effort: HumanNumber::to_percent(private.current_effort),
|
current_effort: HumanNumber::to_percent(local.current_effort),
|
||||||
connections: HumanNumber::from_u16(private.connections),
|
connections: HumanNumber::from_u16(local.connections),
|
||||||
|
hashrate: local.hashrate_1h,
|
||||||
..std::mem::take(&mut *public)
|
..std::mem::take(&mut *public)
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
// Essentially greps the output for [x.xxxxxxxxxxxx XMR] where x = a number.
|
// Mutate [PubP2poolApi] with data from a [PrivP2pool(Network|Pool)Api].
|
||||||
// It sums each match and counts along the way, handling an error by not adding and printing to console.
|
fn update_from_network_pool(public: &Arc<Mutex<Self>>, net: PrivP2poolNetworkApi, pool: PrivP2poolPoolApi) {
|
||||||
fn calc_payouts_and_xmr(output: &str, regex: &P2poolRegex) -> (u128 /* payout count */, f64 /* total xmr */) {
|
let hashrate = public.lock().unwrap().hashrate; // The user's total P2Pool hashrate
|
||||||
let iter = regex.payout.find_iter(output);
|
let monero_difficulty = net.difficulty;
|
||||||
let mut sum: f64 = 0.0;
|
let monero_hashrate = monero_difficulty / MONERO_BLOCK_TIME_IN_SECONDS;
|
||||||
let mut count: u128 = 0;
|
let p2pool_hashrate = pool.pool_statistics.hashRate;
|
||||||
for i in iter {
|
let p2pool_difficulty = p2pool_hashrate * P2POOL_BLOCK_TIME_IN_SECONDS;
|
||||||
match regex.float.find(i.as_str()).unwrap().as_str().parse::<f64>() {
|
// These [0] checks prevent dividing by 0 (it [panic!()]s)
|
||||||
Ok(num) => { sum += num; count += 1; },
|
let p2pool_block_mean = if p2pool_hashrate == 0 {
|
||||||
Err(e) => error!("P2Pool | Total XMR sum calculation error: [{}]", e),
|
HumanTime::new()
|
||||||
}
|
} else {
|
||||||
|
HumanTime::into_human(std::time::Duration::from_secs(monero_difficulty / p2pool_hashrate))
|
||||||
|
};
|
||||||
|
let p2pool_percent = if monero_hashrate == 0 {
|
||||||
|
HumanNumber::unknown()
|
||||||
|
} else {
|
||||||
|
let f = (p2pool_hashrate as f32) / (monero_hashrate as f32) * 100.0;
|
||||||
|
HumanNumber::to_percent_3_point(f)
|
||||||
|
};
|
||||||
|
let solo_block_mean;
|
||||||
|
let p2pool_share_mean;
|
||||||
|
if hashrate == 0 {
|
||||||
|
solo_block_mean = HumanTime::new();
|
||||||
|
p2pool_share_mean = HumanTime::new();
|
||||||
|
} else {
|
||||||
|
solo_block_mean = HumanTime::into_human(std::time::Duration::from_secs(monero_difficulty / hashrate));
|
||||||
|
p2pool_share_mean = HumanTime::into_human(std::time::Duration::from_secs(p2pool_difficulty / hashrate));
|
||||||
}
|
}
|
||||||
(count, sum)
|
let mut public = public.lock().unwrap();
|
||||||
|
*public = Self {
|
||||||
|
monero_difficulty: HumanNumber::from_u64(monero_difficulty),
|
||||||
|
monero_hashrate: HumanNumber::from_u64_to_gigahash_3_point(monero_hashrate),
|
||||||
|
hash: net.hash,
|
||||||
|
height: HumanNumber::from_u32(net.height),
|
||||||
|
reward: net.reward,
|
||||||
|
p2pool_difficulty: HumanNumber::from_u64(p2pool_difficulty),
|
||||||
|
p2pool_hashrate: HumanNumber::from_u64_to_megahash_3_point(p2pool_hashrate),
|
||||||
|
miners: HumanNumber::from_u32(pool.pool_statistics.miners),
|
||||||
|
solo_block_mean,
|
||||||
|
p2pool_block_mean,
|
||||||
|
p2pool_share_mean,
|
||||||
|
p2pool_percent,
|
||||||
|
..std::mem::take(&mut *public)
|
||||||
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1395,10 +1474,10 @@ impl PubP2poolApi {
|
||||||
// P2Pool seems to initialize all stats at 0 (or 0.0), so no [Option] wrapper seems needed.
|
// P2Pool seems to initialize all stats at 0 (or 0.0), so no [Option] wrapper seems needed.
|
||||||
#[derive(Debug, Serialize, Deserialize, Clone, Copy)]
|
#[derive(Debug, Serialize, Deserialize, Clone, Copy)]
|
||||||
struct PrivP2poolLocalApi {
|
struct PrivP2poolLocalApi {
|
||||||
hashrate_15m: u128,
|
hashrate_15m: u64,
|
||||||
hashrate_1h: u128,
|
hashrate_1h: u64,
|
||||||
hashrate_24h: u128,
|
hashrate_24h: u64,
|
||||||
shares_found: u128,
|
shares_found: u64,
|
||||||
average_effort: f32,
|
average_effort: f32,
|
||||||
current_effort: f32,
|
current_effort: f32,
|
||||||
connections: u16, // No one will have more than 65535 connections... right?
|
connections: u16, // No one will have more than 65535 connections... right?
|
||||||
|
@ -1432,10 +1511,10 @@ impl PrivP2poolLocalApi {
|
||||||
// This matches P2Pool's [network/stats] JSON API file.
|
// This matches P2Pool's [network/stats] JSON API file.
|
||||||
#[derive(Debug, Serialize, Deserialize, Clone)]
|
#[derive(Debug, Serialize, Deserialize, Clone)]
|
||||||
struct PrivP2poolNetworkApi {
|
struct PrivP2poolNetworkApi {
|
||||||
difficulty: u128,
|
difficulty: u64,
|
||||||
hash: String,
|
hash: String,
|
||||||
height: u32,
|
height: u32,
|
||||||
reward: u128,
|
reward: u64,
|
||||||
timestamp: u32,
|
timestamp: u32,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1487,7 +1566,7 @@ impl PrivP2poolPoolApi {
|
||||||
#[allow(non_snake_case)]
|
#[allow(non_snake_case)]
|
||||||
#[derive(Debug, Serialize, Deserialize, Clone, Copy)]
|
#[derive(Debug, Serialize, Deserialize, Clone, Copy)]
|
||||||
struct PoolStatistics {
|
struct PoolStatistics {
|
||||||
hashRate: u128,
|
hashRate: u64,
|
||||||
miners: u32,
|
miners: u32,
|
||||||
}
|
}
|
||||||
impl Default for PoolStatistics { fn default() -> Self { Self::new() } }
|
impl Default for PoolStatistics { fn default() -> Self { Self::new() } }
|
||||||
|
@ -1766,6 +1845,69 @@ mod test {
|
||||||
assert_eq!(public.xmr_month, 648000.0000001296);
|
assert_eq!(public.xmr_month, 648000.0000001296);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn update_pub_p2pool_from_local_network_pool() {
|
||||||
|
use std::sync::{Arc,Mutex};
|
||||||
|
use crate::helper::PubP2poolApi;
|
||||||
|
use crate::helper::PrivP2poolLocalApi;
|
||||||
|
use crate::helper::PrivP2poolNetworkApi;
|
||||||
|
use crate::helper::PrivP2poolPoolApi;
|
||||||
|
use crate::helper::PoolStatistics;
|
||||||
|
let public = Arc::new(Mutex::new(PubP2poolApi::new()));
|
||||||
|
let local = PrivP2poolLocalApi {
|
||||||
|
hashrate_15m: 10_000,
|
||||||
|
hashrate_1h: 20_000,
|
||||||
|
hashrate_24h: 30_000,
|
||||||
|
shares_found: 1000,
|
||||||
|
average_effort: 100.000,
|
||||||
|
current_effort: 200.000,
|
||||||
|
connections: 1234,
|
||||||
|
};
|
||||||
|
let network = PrivP2poolNetworkApi {
|
||||||
|
difficulty: 300_000_000_000,
|
||||||
|
hash: "asdf".to_string(),
|
||||||
|
height: 1234,
|
||||||
|
reward: 2345,
|
||||||
|
timestamp: 3456,
|
||||||
|
};
|
||||||
|
let pool = PrivP2poolPoolApi {
|
||||||
|
pool_statistics: PoolStatistics {
|
||||||
|
hashRate: 1_000_000, // 1 MH/s
|
||||||
|
miners: 1_000,
|
||||||
|
}
|
||||||
|
};
|
||||||
|
// Update Local
|
||||||
|
PubP2poolApi::update_from_local(&public, local);
|
||||||
|
let p = public.lock().unwrap();
|
||||||
|
println!("AFTER LOCAL: {:#?}", p);
|
||||||
|
assert_eq!(p.hashrate_15m.to_string(), "10,000");
|
||||||
|
assert_eq!(p.hashrate_1h.to_string(), "20,000");
|
||||||
|
assert_eq!(p.hashrate_24h.to_string(), "30,000");
|
||||||
|
assert_eq!(p.shares_found.to_string(), "1,000");
|
||||||
|
assert_eq!(p.average_effort.to_string(), "100.00%");
|
||||||
|
assert_eq!(p.current_effort.to_string(), "200.00%");
|
||||||
|
assert_eq!(p.connections.to_string(), "1,234");
|
||||||
|
assert_eq!(p.hashrate, 20000);
|
||||||
|
drop(p);
|
||||||
|
// Update Network + Pool
|
||||||
|
PubP2poolApi::update_from_network_pool(&public, network, pool);
|
||||||
|
let p = public.lock().unwrap();
|
||||||
|
println!("AFTER NETWORK+POOL: {:#?}", p);
|
||||||
|
assert_eq!(p.monero_difficulty.to_string(), "300,000,000,000");
|
||||||
|
assert_eq!(p.monero_hashrate.to_string(), "2.500 GH/s");
|
||||||
|
assert_eq!(p.hash.to_string(), "asdf");
|
||||||
|
assert_eq!(p.height.to_string(), "1,234");
|
||||||
|
assert_eq!(p.reward, 2345);
|
||||||
|
assert_eq!(p.p2pool_difficulty.to_string(), "10,000,000");
|
||||||
|
assert_eq!(p.p2pool_hashrate.to_string(), "1.000 MH/s");
|
||||||
|
assert_eq!(p.miners.to_string(), "1,000");
|
||||||
|
assert_eq!(p.solo_block_mean.to_string(), "5 months, 21 days, 9 hours, 52 minutes");
|
||||||
|
assert_eq!(p.p2pool_block_mean.to_string(), "3 days, 11 hours, 20 minutes");
|
||||||
|
assert_eq!(p.p2pool_share_mean.to_string(), "8 minutes, 20 seconds");
|
||||||
|
assert_eq!(p.p2pool_percent.to_string(), "0.040%");
|
||||||
|
drop(p);
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn serde_priv_p2pool_local_api() {
|
fn serde_priv_p2pool_local_api() {
|
||||||
let data =
|
let data =
|
||||||
|
|
17
src/human.rs
17
src/human.rs
|
@ -117,6 +117,9 @@ impl HumanNumber {
|
||||||
Self(format!("{:.2}%", f))
|
Self(format!("{:.2}%", f))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
pub fn to_percent_3_point(f: f32) -> Self {
|
||||||
|
Self(format!("{:.3}%", f))
|
||||||
|
}
|
||||||
pub fn from_f32(f: f32) -> Self {
|
pub fn from_f32(f: f32) -> Self {
|
||||||
let mut buf = num_format::Buffer::new();
|
let mut buf = num_format::Buffer::new();
|
||||||
buf.write_formatted(&(f as u64), &LOCALE);
|
buf.write_formatted(&(f as u64), &LOCALE);
|
||||||
|
@ -191,6 +194,18 @@ impl HumanNumber {
|
||||||
}
|
}
|
||||||
Self(string)
|
Self(string)
|
||||||
}
|
}
|
||||||
|
// [1_000_000] -> [1.000 MH/s]
|
||||||
|
pub fn from_u64_to_megahash_3_point(hash: u64) -> Self {
|
||||||
|
let hash = (hash as f64)/1_000_000.0;
|
||||||
|
let hash = format!("{:.3} MH/s", hash);
|
||||||
|
Self(hash)
|
||||||
|
}
|
||||||
|
// [1_000_000_000] -> [1.000 GH/s]
|
||||||
|
pub fn from_u64_to_gigahash_3_point(hash: u64) -> Self {
|
||||||
|
let hash = (hash as f64)/1_000_000_000.0;
|
||||||
|
let hash = format!("{:.3} GH/s", hash);
|
||||||
|
Self(hash)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//---------------------------------------------------------------------------------------------------- TESTS
|
//---------------------------------------------------------------------------------------------------- TESTS
|
||||||
|
@ -201,6 +216,7 @@ mod test {
|
||||||
use crate::human::HumanNumber;
|
use crate::human::HumanNumber;
|
||||||
assert!(HumanNumber::to_percent(0.001).to_string() == "0%");
|
assert!(HumanNumber::to_percent(0.001).to_string() == "0%");
|
||||||
assert!(HumanNumber::to_percent(12.123123123123).to_string() == "12.12%");
|
assert!(HumanNumber::to_percent(12.123123123123).to_string() == "12.12%");
|
||||||
|
assert!(HumanNumber::to_percent_3_point(0.001).to_string() == "0.001%");
|
||||||
assert!(HumanNumber::from_hashrate([Some(123.1), Some(11111.1), None]).to_string() == "[123 H/s, 11,111 H/s, ??? H/s]");
|
assert!(HumanNumber::from_hashrate([Some(123.1), Some(11111.1), None]).to_string() == "[123 H/s, 11,111 H/s, ??? H/s]");
|
||||||
assert!(HumanNumber::from_hashrate([None, Some(1.123), Some(123123.312)]).to_string() == "[??? H/s, 1 H/s, 123,123 H/s]");
|
assert!(HumanNumber::from_hashrate([None, Some(1.123), Some(123123.312)]).to_string() == "[??? H/s, 1 H/s, 123,123 H/s]");
|
||||||
assert!(HumanNumber::from_load([Some(123.1234), Some(321.321), None]).to_string() == "[123.12, 321.32, ???]");
|
assert!(HumanNumber::from_load([Some(123.1234), Some(321.321), None]).to_string() == "[123.12, 321.32, ???]");
|
||||||
|
@ -231,6 +247,7 @@ mod test {
|
||||||
HumanNumber::from_u128(340_282_366_920_938_463_463_374_607_431_768_211_455).to_string(),
|
HumanNumber::from_u128(340_282_366_920_938_463_463_374_607_431_768_211_455).to_string(),
|
||||||
"340,282,366,920,938,463,463,374,607,431,768,211,455",
|
"340,282,366,920,938,463,463,374,607,431,768,211,455",
|
||||||
);
|
);
|
||||||
|
assert!(HumanNumber::from_u64_to_gigahash_3_point(1_000_000_000).to_string() == "1.000 GH/s");
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
|
12
src/main.rs
12
src/main.rs
|
@ -1594,6 +1594,8 @@ impl eframe::App for App {
|
||||||
let distro = true;
|
let distro = true;
|
||||||
#[cfg(not(feature = "distro"))]
|
#[cfg(not(feature = "distro"))]
|
||||||
let distro = false;
|
let distro = false;
|
||||||
|
let p2pool_gui_len = self.p2pool_api.lock().unwrap().output.len();
|
||||||
|
let xmrig_gui_len = self.xmrig_api.lock().unwrap().output.len();
|
||||||
let debug_info = format!(
|
let debug_info = format!(
|
||||||
"Gupax version: {}\n
|
"Gupax version: {}\n
|
||||||
Bundled P2Pool version: {}\n
|
Bundled P2Pool version: {}\n
|
||||||
|
@ -1622,6 +1624,10 @@ XMRig console byte length: {}\n
|
||||||
{:#?}\n
|
{:#?}\n
|
||||||
------------------------------------------ XMRIG IMAGE ------------------------------------------
|
------------------------------------------ XMRIG IMAGE ------------------------------------------
|
||||||
{:#?}\n
|
{:#?}\n
|
||||||
|
------------------------------------------ P2POOL GUI API ------------------------------------------
|
||||||
|
{:#?}\n
|
||||||
|
------------------------------------------ XMRIG GUI API ------------------------------------------
|
||||||
|
{:#?}\n
|
||||||
------------------------------------------ WORKING STATE ------------------------------------------
|
------------------------------------------ WORKING STATE ------------------------------------------
|
||||||
{:#?}\n
|
{:#?}\n
|
||||||
------------------------------------------ ORIGINAL STATE ------------------------------------------
|
------------------------------------------ ORIGINAL STATE ------------------------------------------
|
||||||
|
@ -1649,10 +1655,12 @@ XMRig console byte length: {}\n
|
||||||
self.exe,
|
self.exe,
|
||||||
self.state.gupax.absolute_p2pool_path.display(),
|
self.state.gupax.absolute_p2pool_path.display(),
|
||||||
self.state.gupax.absolute_xmrig_path.display(),
|
self.state.gupax.absolute_xmrig_path.display(),
|
||||||
self.p2pool_api.lock().unwrap().output.len(),
|
p2pool_gui_len,
|
||||||
self.xmrig_api.lock().unwrap().output.len(),
|
xmrig_gui_len,
|
||||||
self.p2pool_img.lock().unwrap(),
|
self.p2pool_img.lock().unwrap(),
|
||||||
self.xmrig_img.lock().unwrap(),
|
self.xmrig_img.lock().unwrap(),
|
||||||
|
self.p2pool_api.lock().unwrap(),
|
||||||
|
self.xmrig_api.lock().unwrap(),
|
||||||
self.state,
|
self.state,
|
||||||
self.og.lock().unwrap(),
|
self.og.lock().unwrap(),
|
||||||
);
|
);
|
||||||
|
|
Loading…
Reference in a new issue