diff --git a/README.md b/README.md index d9e2135..c202117 100644 --- a/README.md +++ b/README.md @@ -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. -There are `34` unit tests throughout the codebase files, you should probably run: +There are `37` unit tests throughout the codebase files, you should probably run: ``` cargo test ``` diff --git a/src/constants.rs b/src/constants.rs index 36f850d..4a5dcb7 100644 --- a/src/constants.rs +++ b/src/constants.rs @@ -15,10 +15,10 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . -pub const GUPAX_VERSION: &str = concat!("v", env!("CARGO_PKG_VERSION")); // e.g: Gupax v1.0.0 +pub const GUPAX_VERSION: &str = concat!("v", env!("CARGO_PKG_VERSION")); // e.g: v1.0.0 pub const P2POOL_VERSION: &str = "v2.6"; -pub const XMRIG_VERSION: &str = "v6.18.1"; -pub const COMMIT: &str = include_str!("../.git/refs/heads/main"); +pub const XMRIG_VERSION: &str = "v6.18.1"; +pub const COMMIT: &str = include_str!("../.git/refs/heads/main"); // e.g: Gupax_v1_0_0 // Would have been [Gupax_v1.0.0] but P2Pool truncates everything after [.] pub const GUPAX_VERSION_UNDERSCORE: &str = concat!( @@ -31,12 +31,12 @@ pub const GUPAX_VERSION_UNDERSCORE: &str = concat!( ); // App frame resolution, [4:3] aspect ratio, [1.33:1] -pub const APP_MIN_WIDTH: f32 = 640.0; +pub const APP_MIN_WIDTH: f32 = 640.0; pub const APP_MIN_HEIGHT: f32 = 480.0; -pub const APP_MAX_WIDTH: f32 = 3840.0; +pub const APP_MAX_WIDTH: f32 = 3840.0; pub const APP_MAX_HEIGHT: f32 = 2160.0; // Default, 1280x960 -pub const APP_DEFAULT_WIDTH: f32 = 1280.0; +pub const APP_DEFAULT_WIDTH: f32 = 1280.0; pub const APP_DEFAULT_HEIGHT: f32 = 960.0; // Constants specific for Linux distro packaging of Gupax @@ -46,12 +46,11 @@ r#"This [Gupax] was compiled for use as a Linux distro package. Built-in updates // Use macOS shaped icon for macOS #[cfg(target_os = "macos")] -pub const BYTES_ICON: &[u8] = include_bytes!("../images/icons/icon@2x.png"); +pub const BYTES_ICON: &[u8] = include_bytes!("../images/icons/icon@2x.png"); #[cfg(not(target_os = "macos"))] -pub const BYTES_ICON: &[u8] = include_bytes!("../images/icons/icon.png"); +pub const BYTES_ICON: &[u8] = include_bytes!("../images/icons/icon.png"); pub const BYTES_BANNER: &[u8] = include_bytes!("../images/banner.png"); -pub const HORIZONTAL: &str = "--------------------------------------------"; -// The text to separate my "process stopped, here's stats" text from the process output in the console. +pub const HORIZONTAL: &str = "--------------------------------------------"; pub const HORI_CONSOLE: &str = "---------------------------------------------------------------------------------------------------------------------------"; // Keyboard shortcuts @@ -72,18 +71,18 @@ r#"*---------------------------------------* *---------------------------------------*"#; // P2Pool & XMRig default API stuff #[cfg(target_os = "windows")] -pub const P2POOL_API_PATH_LOCAL: &str = r"local\stats"; +pub const P2POOL_API_PATH_LOCAL: &str = r"local\stats"; #[cfg(target_os = "windows")] pub const P2POOL_API_PATH_NETWORK: &str = r"network\stats"; #[cfg(target_os = "windows")] -pub const P2POOL_API_PATH_POOL: &str = r"pool\stats"; +pub const P2POOL_API_PATH_POOL: &str = r"pool\stats"; #[cfg(target_family = "unix")] -pub const P2POOL_API_PATH_LOCAL: &str = "local/stats"; +pub const P2POOL_API_PATH_LOCAL: &str = "local/stats"; #[cfg(target_family = "unix")] pub const P2POOL_API_PATH_NETWORK: &str = "network/stats"; #[cfg(target_family = "unix")] -pub const P2POOL_API_PATH_POOL: &str = "pool/stats"; -pub const XMRIG_API_URI: &str = "1/summary"; // The default relative URI of XMRig's API +pub const P2POOL_API_PATH_POOL: &str = "pool/stats"; +pub const XMRIG_API_URI: &str = "1/summary"; // The default relative URI of XMRig's API // Process state tooltips (online, offline, etc) pub const P2POOL_ALIVE: &str = "P2Pool is online"; @@ -103,31 +102,28 @@ pub const XMRIG_MIDDLE: &str = "XMRig is in the middle of (re)starting/stopping" pub const SPACE: f32 = 10.0; // Some colors -pub const RED: egui::Color32 = egui::Color32::from_rgb(230, 50, 50); -pub const GREEN: egui::Color32 = egui::Color32::from_rgb(100, 230, 100); -pub const YELLOW: egui::Color32 = egui::Color32::from_rgb(230, 230, 100); +pub const RED: egui::Color32 = egui::Color32::from_rgb(230, 50, 50); +pub const GREEN: egui::Color32 = egui::Color32::from_rgb(100, 230, 100); +pub const YELLOW: egui::Color32 = egui::Color32::from_rgb(230, 230, 100); pub const BRIGHT_YELLOW: egui::Color32 = egui::Color32::from_rgb(250, 250, 100); -pub const BONE: egui::Color32 = egui::Color32::from_rgb(190, 190, 190); // In between LIGHT_GRAY <-> GRAY -pub const WHITE: egui::Color32 = egui::Color32::WHITE; -pub const GRAY: egui::Color32 = egui::Color32::GRAY; -pub const LIGHT_GRAY: egui::Color32 = egui::Color32::LIGHT_GRAY; -pub const BLACK: egui::Color32 = egui::Color32::BLACK; -pub const DARK_GRAY: egui::Color32 = egui::Color32::from_rgb(18, 18, 18); +pub const BONE: egui::Color32 = egui::Color32::from_rgb(190, 190, 190); // In between LIGHT_GRAY <-> GRAY +pub const WHITE: egui::Color32 = egui::Color32::WHITE; +pub const GRAY: egui::Color32 = egui::Color32::GRAY; +pub const LIGHT_GRAY: egui::Color32 = egui::Color32::LIGHT_GRAY; +pub const BLACK: egui::Color32 = egui::Color32::BLACK; +pub const DARK_GRAY: egui::Color32 = egui::Color32::from_rgb(18, 18, 18); // [Duration] constants pub const SECOND: std::time::Duration = std::time::Duration::from_secs(1); -pub const ZERO_SECONDS: std::time::Duration = std::time::Duration::from_secs(0); -pub const MILLI_900: std::time::Duration = std::time::Duration::from_millis(900); -pub const TOKIO_SECOND: tokio::time::Duration = std::time::Duration::from_secs(1); // The explaination given to the user on why XMRig needs sudo. pub const XMRIG_ADMIN_REASON: &str = r#"The large hashrate difference between XMRig and other miners like Monero and P2Pool's built-in miners is mostly due to XMRig configuring CPU MSRs and setting up hugepages. Other miners like Monero or P2Pool's built-in miner do not do this. It can be done manually but it isn't recommended since XMRig does this for you automatically, but only if it has the proper admin privileges."#; // Password buttons -pub const PASSWORD_TEXT: &str = "Enter sudo/admin password..."; +pub const PASSWORD_TEXT: &str = "Enter sudo/admin password..."; pub const PASSWORD_LEAVE: &str = "Return to the previous screen"; pub const PASSWORD_ENTER: &str = "Attempt with the current password"; -pub const PASSWORD_HIDE: &str = "Toggle hiding/showing the password"; +pub const PASSWORD_HIDE: &str = "Toggle hiding/showing the password"; // OS specific @@ -150,62 +146,62 @@ pub const OS_NAME: &str = "Linux"; // Tooltips // Status -pub const STATUS_GUPAX_UPTIME: &str = "How long Gupax has been online"; -pub const STATUS_GUPAX_CPU_USAGE: &str = "How much CPU Gupax is currently using. This accounts for all your threads (it is out of 100%)"; -pub const STATUS_GUPAX_MEMORY_USAGE: &str = "How much memory Gupax is currently using in Megabytes"; +pub const STATUS_GUPAX_UPTIME: &str = "How long Gupax has been online"; +pub const STATUS_GUPAX_CPU_USAGE: &str = "How much CPU Gupax is currently using. This accounts for all your threads (it is out of 100%)"; +pub const STATUS_GUPAX_MEMORY_USAGE: &str = "How much memory Gupax is currently using in Megabytes"; pub const STATUS_GUPAX_SYSTEM_CPU_USAGE: &str = "How much CPU your entire system is currently using. This accounts for all your threads (it is out of 100%)"; -pub const STATUS_GUPAX_SYSTEM_MEMORY: &str = "How much memory your entire system has (including swap) and is currently using in Gigabytes"; +pub const STATUS_GUPAX_SYSTEM_MEMORY: &str = "How much memory your entire system has (including swap) and is currently using in Gigabytes"; pub const STATUS_GUPAX_SYSTEM_CPU_MODEL: &str = "The detected model of your system's CPU and its current frequency"; //-- -pub const STATUS_P2POOL_UPTIME: &str = "How long P2Pool has been online"; -pub const STATUS_P2POOL_PAYOUTS: &str = "The total amount of payouts received in this instance of P2Pool and an extrapolated estimate of how many you will receive. Warning: these stats will be quite inaccurate if your P2Pool hasn't been running for a long time!"; -pub const STATUS_P2POOL_XMR: &str = "The total amount of XMR mined in this instance of P2Pool and an extrapolated estimate of how many you will mine in the future. Warning: these stats will be quite inaccurate if your P2Pool hasn't been running for a long time!"; -pub const STATUS_P2POOL_HASHRATE: &str = "The total amount of hashrate your P2Pool has pointed at it in 15 minute, 1 hour, and 24 hour averages"; -pub const STATUS_P2POOL_SHARES: &str = "The total amount of shares found on P2Pool"; -pub const STATUS_P2POOL_EFFORT: &str = "The average amount of effort needed to find a share, and the current effort"; +pub const STATUS_P2POOL_UPTIME: &str = "How long P2Pool has been online"; +pub const STATUS_P2POOL_PAYOUTS: &str = "The total amount of payouts received in this instance of P2Pool and an extrapolated estimate of how many you will receive. Warning: these stats will be quite inaccurate if your P2Pool hasn't been running for a long time!"; +pub const STATUS_P2POOL_XMR: &str = "The total amount of XMR mined in this instance of P2Pool and an extrapolated estimate of how many you will mine in the future. Warning: these stats will be quite inaccurate if your P2Pool hasn't been running for a long time!"; +pub const STATUS_P2POOL_HASHRATE: &str = "The total amount of hashrate your P2Pool has pointed at it in 15 minute, 1 hour, and 24 hour averages"; +pub const STATUS_P2POOL_SHARES: &str = "The total amount of shares found on P2Pool"; +pub const STATUS_P2POOL_EFFORT: &str = "The average amount of effort needed to find a share, and the current effort"; pub const STATUS_P2POOL_CONNECTIONS: &str = "The total amount of miner connections on this P2Pool"; pub const STATUS_P2POOL_MONERO_NODE: &str = "The Monero node being used by P2Pool"; -pub const STATUS_P2POOL_POOL: &str = "The P2Pool sidechain you're currently connected to"; -pub const STATUS_P2POOL_ADDRESS: &str = "The Monero address P2Pool will send payouts to"; +pub const STATUS_P2POOL_POOL: &str = "The P2Pool sidechain you're currently connected to"; +pub const STATUS_P2POOL_ADDRESS: &str = "The Monero address P2Pool will send payouts to"; //-- -pub const STATUS_XMRIG_UPTIME: &str = "How long XMRig has been online"; -pub const STATUS_XMRIG_CPU: &str = "The average CPU load of XMRig. [1.0] represents 1 thread is maxed out, e.g: If you have 8 threads, [4.0] means half your threads are maxed out."; -pub const STATUS_XMRIG_HASHRATE: &str = "The average hashrate of XMRig"; -pub const STATUS_XMRIG_DIFFICULTY: &str = "The current difficulty of the job XMRig is working on"; -pub const STATUS_XMRIG_SHARES: &str = "The amount of accepted and rejected shares"; -pub const STATUS_XMRIG_POOL: &str = "The pool XMRig is currently mining to"; -pub const STATUS_XMRIG_THREADS: &str = "The amount of threads XMRig is currently using"; +pub const STATUS_XMRIG_UPTIME: &str = "How long XMRig has been online"; +pub const STATUS_XMRIG_CPU: &str = "The average CPU load of XMRig. [1.0] represents 1 thread is maxed out, e.g: If you have 8 threads, [4.0] means half your threads are maxed out."; +pub const STATUS_XMRIG_HASHRATE: &str = "The average hashrate of XMRig"; +pub const STATUS_XMRIG_DIFFICULTY: &str = "The current difficulty of the job XMRig is working on"; +pub const STATUS_XMRIG_SHARES: &str = "The amount of accepted and rejected shares"; +pub const STATUS_XMRIG_POOL: &str = "The pool XMRig is currently mining to"; +pub const STATUS_XMRIG_THREADS: &str = "The amount of threads XMRig is currently using"; // Status Submenus pub const STATUS_SUBMENU_PROCESSES: &str = "View the status of process related data for [Gupax|P2Pool|XMRig]"; -pub const STATUS_SUBMENU_P2POOL: &str = "View P2Pool specific data"; -pub const STATUS_SUBMENU_MONERO: &str = "View general Monero blockchain data"; +pub const STATUS_SUBMENU_P2POOL: &str = "View P2Pool specific data"; +pub const STATUS_SUBMENU_MONERO: &str = "View general Monero blockchain data"; // Gupax -pub const GUPAX_UPDATE: &str = "Check for updates on Gupax, P2Pool, and XMRig via GitHub's API and upgrade automatically"; -pub const GUPAX_AUTO_UPDATE: &str = "Automatically check for updates at startup"; -pub const GUPAX_SHOULD_RESTART: &str = "Gupax was updated. A restart is recommended but not required"; -pub const GUPAX_UP_TO_DATE: &str = "Gupax is up-to-date"; +pub const GUPAX_UPDATE: &str = "Check for updates on Gupax, P2Pool, and XMRig via GitHub's API and upgrade automatically"; +pub const GUPAX_AUTO_UPDATE: &str = "Automatically check for updates at startup"; +pub const GUPAX_SHOULD_RESTART: &str = "Gupax was updated. A restart is recommended but not required"; +pub const GUPAX_UP_TO_DATE: &str = "Gupax is up-to-date"; #[cfg(not(target_os = "macos"))] -pub const GUPAX_UPDATE_VIA_TOR: &str = "Update through the Tor network. Tor is embedded within Gupax; a Tor system proxy is not required"; +pub const GUPAX_UPDATE_VIA_TOR: &str = "Update through the Tor network. Tor is embedded within Gupax; a Tor system proxy is not required"; #[cfg(target_os = "macos")] // Arti library has issues on macOS -pub const GUPAX_UPDATE_VIA_TOR: &'static str = "WARNING: This option is unstable on macOS. Update through the Tor network. Tor is embedded within Gupax; a Tor system proxy is not required"; -pub const GUPAX_ASK_BEFORE_QUIT: &str = "Ask before quitting Gupax"; +pub const GUPAX_UPDATE_VIA_TOR: &str = "WARNING: This option is unstable on macOS. Update through the Tor network. Tor is embedded within Gupax; a Tor system proxy is not required"; +pub const GUPAX_ASK_BEFORE_QUIT: &str = "Ask before quitting Gupax"; pub const GUPAX_SAVE_BEFORE_QUIT: &str = "Automatically save any changed settings before quitting"; -pub const GUPAX_AUTO_P2POOL: &str = "Automatically start P2Pool on Gupax startup. If you are using [P2Pool Simple], this will NOT wait for your [Auto-Ping] to finish, it will start P2Pool on the pool you already have selected. This option will fail if your P2Pool settings aren't valid!"; -pub const GUPAX_AUTO_XMRIG: &str = "Automatically start XMRig on Gupax startup. This option will fail if your XMRig settings aren't valid!"; -pub const GUPAX_ADJUST: &str = "Adjust and set the width/height of the Gupax window"; -pub const GUPAX_WIDTH: &str = "Set the width of the Gupax window"; -pub const GUPAX_HEIGHT: &str = "Set the height of the Gupax window"; -pub const GUPAX_LOCK_WIDTH: &str = "Automatically match the HEIGHT against the WIDTH in a 4:3 ratio"; -pub const GUPAX_LOCK_HEIGHT: &str = "Automatically match the WIDTH against the HEIGHT in a 4:3 ratio"; -pub const GUPAX_NO_LOCK: &str = "Allow individual selection of width and height"; -pub const GUPAX_SET: &str = "Set the width/height of the Gupax window to the current values"; -pub const GUPAX_TAB: &str = "Set the default tab Gupax starts on"; -pub const GUPAX_TAB_ABOUT: &str = "Set the tab Gupax starts on to: About"; -pub const GUPAX_TAB_STATUS: &str = "Set the tab Gupax starts on to: Status"; -pub const GUPAX_TAB_GUPAX: &str = "Set the tab Gupax starts on to: Gupax"; -pub const GUPAX_TAB_P2POOL: &str = "Set the tab Gupax starts on to: P2Pool"; -pub const GUPAX_TAB_XMRIG: &str = "Set the tab Gupax starts on to: XMRig"; +pub const GUPAX_AUTO_P2POOL: &str = "Automatically start P2Pool on Gupax startup. If you are using [P2Pool Simple], this will NOT wait for your [Auto-Ping] to finish, it will start P2Pool on the pool you already have selected. This option will fail if your P2Pool settings aren't valid!"; +pub const GUPAX_AUTO_XMRIG: &str = "Automatically start XMRig on Gupax startup. This option will fail if your XMRig settings aren't valid!"; +pub const GUPAX_ADJUST: &str = "Adjust and set the width/height of the Gupax window"; +pub const GUPAX_WIDTH: &str = "Set the width of the Gupax window"; +pub const GUPAX_HEIGHT: &str = "Set the height of the Gupax window"; +pub const GUPAX_LOCK_WIDTH: &str = "Automatically match the HEIGHT against the WIDTH in a 4:3 ratio"; +pub const GUPAX_LOCK_HEIGHT: &str = "Automatically match the WIDTH against the HEIGHT in a 4:3 ratio"; +pub const GUPAX_NO_LOCK: &str = "Allow individual selection of width and height"; +pub const GUPAX_SET: &str = "Set the width/height of the Gupax window to the current values"; +pub const GUPAX_TAB: &str = "Set the default tab Gupax starts on"; +pub const GUPAX_TAB_ABOUT: &str = "Set the tab Gupax starts on to: About"; +pub const GUPAX_TAB_STATUS: &str = "Set the tab Gupax starts on to: Status"; +pub const GUPAX_TAB_GUPAX: &str = "Set the tab Gupax starts on to: Gupax"; +pub const GUPAX_TAB_P2POOL: &str = "Set the tab Gupax starts on to: P2Pool"; +pub const GUPAX_TAB_XMRIG: &str = "Set the tab Gupax starts on to: XMRig"; pub const GUPAX_SIMPLE: &str = r#"Use simple Gupax settings: @@ -223,19 +219,19 @@ pub const GUPAX_PATH_P2POOL: &str = "The location of the P2Pool binary: Both abs pub const GUPAX_PATH_XMRIG: &str = "The location of the XMRig binary: Both absolute and relative paths are accepted; A red [X] will appear if there is no file found at the given path"; // P2Pool -pub const P2POOL_MAIN: &str = "Use the P2Pool main-chain. This P2Pool finds blocks faster, but has a higher difficulty. Suitable for miners with more than 50kH/s"; -pub const P2POOL_MINI: &str = "Use the P2Pool mini-chain. This P2Pool finds blocks slower, but has a lower difficulty. Suitable for miners with less than 50kH/s"; -pub const P2POOL_OUT: &str = "How many out-bound peers to connect to? (you connecting to others)"; -pub const P2POOL_IN: &str = "How many in-bound peers to allow? (others connecting to you)"; -pub const P2POOL_LOG: &str = "Verbosity of the console log"; -pub const P2POOL_AUTO_NODE: &str = "Automatically ping the community Monero nodes at Gupax startup"; -pub const P2POOL_AUTO_SELECT: &str = "Automatically select the fastest community Monero node after pinging"; +pub const P2POOL_MAIN: &str = "Use the P2Pool main-chain. This P2Pool finds blocks faster, but has a higher difficulty. Suitable for miners with more than 50kH/s"; +pub const P2POOL_MINI: &str = "Use the P2Pool mini-chain. This P2Pool finds blocks slower, but has a lower difficulty. Suitable for miners with less than 50kH/s"; +pub const P2POOL_OUT: &str = "How many out-bound peers to connect to? (you connecting to others)"; +pub const P2POOL_IN: &str = "How many in-bound peers to allow? (others connecting to you)"; +pub const P2POOL_LOG: &str = "Verbosity of the console log"; +pub const P2POOL_AUTO_NODE: &str = "Automatically ping the community Monero nodes at Gupax startup"; +pub const P2POOL_AUTO_SELECT: &str = "Automatically select the fastest community Monero node after pinging"; pub const P2POOL_SELECT_FASTEST: &str = "Select the fastest community Monero node"; -pub const P2POOL_SELECT_RANDOM: &str = "Select a random community Monero node"; -pub const P2POOL_SELECT_LAST: &str = "Select the previous community Monero node"; -pub const P2POOL_SELECT_NEXT: &str = "Select the next community Monero node"; -pub const P2POOL_PING: &str = "Ping the built-in community Monero nodes"; -pub const P2POOL_ADDRESS: &str = "You must use a primary Monero address to mine on P2Pool (starts with a 4). It is highly recommended to create a new wallet since addresses are public on P2Pool!"; +pub const P2POOL_SELECT_RANDOM: &str = "Select a random community Monero node"; +pub const P2POOL_SELECT_LAST: &str = "Select the previous community Monero node"; +pub const P2POOL_SELECT_NEXT: &str = "Select the next community Monero node"; +pub const P2POOL_PING: &str = "Ping the built-in community Monero nodes"; +pub const P2POOL_ADDRESS: &str = "You must use a primary Monero address to mine on P2Pool (starts with a 4). It is highly recommended to create a new wallet since addresses are public on P2Pool!"; pub const P2POOL_INPUT: &str = "Send a command to P2Pool"; pub const P2POOL_ARGUMENTS: &str = r#"WARNING: Use [--no-color] and make sure to set [--data-api ] & [--local-api] so that the [Status] tab can work! @@ -263,10 +259,10 @@ pub const P2POOL_PATH_OK: &str = "P2Pool was found at the given PATH"; pub const P2POOL_PATH_EMPTY: &str = "P2Pool PATH is empty! To fix: goto the [Gupax Advanced] tab, select [Open] and specify where P2Pool is located."; // Node/Pool list -pub const LIST_ADD: &str = "Add the current values to the list"; -pub const LIST_SAVE: &str = "Save the current values to the already existing entry"; +pub const LIST_ADD: &str = "Add the current values to the list"; +pub const LIST_SAVE: &str = "Save the current values to the already existing entry"; pub const LIST_DELETE: &str = "Delete the currently selected entry"; -pub const LIST_CLEAR: &str = "Clear all current values"; +pub const LIST_CLEAR: &str = "Clear all current values"; // XMRig pub const XMRIG_SIMPLE: &str = @@ -289,21 +285,21 @@ pub const XMRIG_ARGUMENTS: &str = r#"WARNING: Use [--no-color] and make sure to set [--http-host ] & [--http-port ] so that the [Status] tab can work! Start XMRig with these arguments and override all below settings"#; -pub const XMRIG_ADDRESS: &str = "Specify which Monero address to payout to. This does nothing if mining to P2Pool since the address being payed out to will be the one P2Pool started with. This doubles as a rig identifier for P2Pool and some pools."; -pub const XMRIG_NAME: &str = "Add a unique name to identify this pool; Only [A-Za-z0-9-_.] and spaces allowed; Max length = 30 characters"; -pub const XMRIG_IP: &str = "Specify the pool IP to connect to with XMRig; It must be a valid IPv4 address or a valid domain name; Max length = 255 characters"; -pub const XMRIG_PORT: &str = "Specify the port of the pool; [1-65535]"; -pub const XMRIG_RIG: &str = "Add an optional rig ID. This will be the name shown on the pool; Only [A-Za-z0-9-_] and spaces allowed; Max length = 30 characters"; -pub const XMRIG_PAUSE: &str = "THIS SETTING IS DISABLED IF SET TO [0]. Pause mining if user is active, resume after"; -pub const XMRIG_API_IP: &str = "Specify which IP to bind to for XMRig's HTTP API; If empty: [localhost/127.0.0.1]"; -pub const XMRIG_API_PORT: &str = "Specify which port to bind to for XMRig's HTTP API; If empty: [18088]"; -pub const XMRIG_TLS: &str = "Enable SSL/TLS connections (needs pool support)"; -pub const XMRIG_KEEPALIVE: &str = "Send keepalive packets to prevent timeout (needs pool support)"; -pub const XMRIG_THREADS: &str = "Number of CPU threads to use for mining"; -pub const XMRIG_PATH_NOT_FILE: &str = "XMRig binary not found at the given PATH in the Gupax tab! To fix: goto the [Gupax Advanced] tab, select [Open] and specify where XMRig is located."; +pub const XMRIG_ADDRESS: &str = "Specify which Monero address to payout to. This does nothing if mining to P2Pool since the address being payed out to will be the one P2Pool started with. This doubles as a rig identifier for P2Pool and some pools."; +pub const XMRIG_NAME: &str = "Add a unique name to identify this pool; Only [A-Za-z0-9-_.] and spaces allowed; Max length = 30 characters"; +pub const XMRIG_IP: &str = "Specify the pool IP to connect to with XMRig; It must be a valid IPv4 address or a valid domain name; Max length = 255 characters"; +pub const XMRIG_PORT: &str = "Specify the port of the pool; [1-65535]"; +pub const XMRIG_RIG: &str = "Add an optional rig ID. This will be the name shown on the pool; Only [A-Za-z0-9-_] and spaces allowed; Max length = 30 characters"; +pub const XMRIG_PAUSE: &str = "THIS SETTING IS DISABLED IF SET TO [0]. Pause mining if user is active, resume after"; +pub const XMRIG_API_IP: &str = "Specify which IP to bind to for XMRig's HTTP API; If empty: [localhost/127.0.0.1]"; +pub const XMRIG_API_PORT: &str = "Specify which port to bind to for XMRig's HTTP API; If empty: [18088]"; +pub const XMRIG_TLS: &str = "Enable SSL/TLS connections (needs pool support)"; +pub const XMRIG_KEEPALIVE: &str = "Send keepalive packets to prevent timeout (needs pool support)"; +pub const XMRIG_THREADS: &str = "Number of CPU threads to use for mining"; +pub const XMRIG_PATH_NOT_FILE: &str = "XMRig binary not found at the given PATH in the Gupax tab! To fix: goto the [Gupax Advanced] tab, select [Open] and specify where XMRig is located."; pub const XMRIG_PATH_NOT_VALID: &str = "XMRig binary at the given PATH in the Gupax tab doesn't look like XMRig! To fix: goto the [Gupax Advanced] tab, select [Open] and specify where XMRig is located."; -pub const XMRIG_PATH_OK: &str = "XMRig was found at the given PATH"; -pub const XMRIG_PATH_EMPTY: &str = "XMRig PATH is empty! To fix: goto the [Gupax Advanced] tab, select [Open] and specify where XMRig is located."; +pub const XMRIG_PATH_OK: &str = "XMRig was found at the given PATH"; +pub const XMRIG_PATH_EMPTY: &str = "XMRig PATH is empty! To fix: goto the [Gupax Advanced] tab, select [Open] and specify where XMRig is located."; // CLI argument messages pub const ARG_HELP: &str = diff --git a/src/disk.rs b/src/disk.rs index 3adcfc9..09f8d8c 100644 --- a/src/disk.rs +++ b/src/disk.rs @@ -48,6 +48,7 @@ use crate::{ Tab, xmr::*, macros::*, + P2poolRegex, }; use log::*; @@ -70,23 +71,20 @@ pub const POOL_TOML: &str = "pool.toml"; // P2Pool API // Lives within the Gupax OS data directory. // ~/.local/share/gupax/p2pool/ -// ├─ payout // Raw log lines of payouts received -// ├─ xmr // Raw log lines of XMR mined -// ├─ block // Raw log lines of actual blocks found -// ├─ total_payout // Single [u128] representing total payouts -// ├─ total_xmr // Single [u128] representing total XMR mined in atomic units -// ├─ total_block // Single [u128] representing total blocks foundpub const GUPAX_P2POOL_API_: &str = "state.toml"; +// ├─ payout_log // Raw log lines of payouts received +// ├─ payout // Single [u64] representing total payouts +// ├─ xmr // Single [u64] representing total XMR mined in atomic units #[cfg(target_os = "windows")] pub const GUPAX_P2POOL_API_DIRECTORY: &str = r"p2pool\"; #[cfg(target_family = "unix")] pub const GUPAX_P2POOL_API_DIRECTORY: &str = "p2pool/"; -pub const GUPAX_P2POOL_API_PAYOUT: &str = "payout_log"; -pub const GUPAX_P2POOL_API_TOTAL_PAYOUT: &str = "payout"; -pub const GUPAX_P2POOL_API_TOTAL_XMR: &str = "xmr"; +pub const GUPAX_P2POOL_API_LOG: &str = "log"; +pub const GUPAX_P2POOL_API_PAYOUT: &str = "payout"; +pub const GUPAX_P2POOL_API_XMR: &str = "xmr"; pub const GUPAX_P2POOL_API_FILE_ARRAY: [&str; 3] = [ + GUPAX_P2POOL_API_LOG, GUPAX_P2POOL_API_PAYOUT, - GUPAX_P2POOL_API_TOTAL_PAYOUT, - GUPAX_P2POOL_API_TOTAL_XMR, + GUPAX_P2POOL_API_XMR, ]; #[cfg(target_os = "windows")] @@ -562,14 +560,14 @@ impl Pool { //---------------------------------------------------------------------------------------------------- Gupax-P2Pool API #[derive(Clone,Debug)] pub struct GupaxP2poolApi { - pub payout: HumanNumber, - pub xmr: AtomicUnit, - pub int_payout: u64, - pub payout_ord: PayoutOrd, // Ordered Vec of payouts - pub log_payout: String, - pub path_xmr: PathBuf, - pub path_int_payout: PathBuf, - pub path_log_payout: PathBuf, + pub log: String, // Log file only containing full payout lines + pub payout: HumanNumber, // Human-friendly display of payout count + pub payout_u64: u64, // [u64] version of above + pub payout_ord: PayoutOrd, // Ordered Vec of payouts, see [PayoutOrd] + pub xmr: AtomicUnit, // XMR stored as atomic units + pub path_log: PathBuf, // Path to [log] + pub path_payout: PathBuf, // Path to [payout] + pub path_xmr: PathBuf, // Path to [xmr] } impl Default for GupaxP2poolApi { fn default() -> Self { Self::new() } } @@ -577,28 +575,28 @@ impl Default for GupaxP2poolApi { fn default() -> Self { Self::new() } } impl GupaxP2poolApi { pub fn new() -> Self { Self { + log: String::new(), payout: HumanNumber::unknown(), - xmr: AtomicUnit::new(), - int_payout: 0, - log_payout: String::new(), + payout_u64: 0, payout_ord: PayoutOrd::new(), + xmr: AtomicUnit::new(), path_xmr: PathBuf::new(), - path_int_payout: PathBuf::new(), - path_log_payout: PathBuf::new(), + path_payout: PathBuf::new(), + path_log: PathBuf::new(), } } pub fn fill_paths(&mut self, gupax_p2pool_dir: &PathBuf) { - let mut path_xmr = gupax_p2pool_dir.clone(); - let mut path_int_payout = gupax_p2pool_dir.clone(); - let mut path_log_payout = gupax_p2pool_dir.clone(); - path_int_payout.push(GUPAX_P2POOL_API_TOTAL_PAYOUT); - path_xmr.push(GUPAX_P2POOL_API_TOTAL_XMR); - path_log_payout.push(GUPAX_P2POOL_API_PAYOUT); + let mut path_log = gupax_p2pool_dir.clone(); + let mut path_payout = gupax_p2pool_dir.clone(); + let mut path_xmr = gupax_p2pool_dir.clone(); + path_log.push(GUPAX_P2POOL_API_LOG); + path_payout.push(GUPAX_P2POOL_API_PAYOUT); + path_xmr.push(GUPAX_P2POOL_API_XMR); *self = Self { - path_int_payout, + path_log, + path_payout, path_xmr, - path_log_payout, ..std::mem::take(self) }; } @@ -615,7 +613,7 @@ impl GupaxP2poolApi { match std::fs::File::create(&path) { Ok(mut f) => { match file { - GUPAX_P2POOL_API_TOTAL_PAYOUT|GUPAX_P2POOL_API_TOTAL_XMR => writeln!(f, "0")?, + GUPAX_P2POOL_API_PAYOUT|GUPAX_P2POOL_API_XMR => writeln!(f, "0")?, _ => (), } info!("GupaxP2poolApi | [{}] create ... OK", path.display()); @@ -627,45 +625,46 @@ impl GupaxP2poolApi { } pub fn read_all_files_and_update(&mut self) -> Result<(), TomlError> { - let int_payout = match read_to_string(File::IntPayout, &self.path_int_payout)?.trim().parse::() { + let payout_u64 = match read_to_string(File::Payout, &self.path_payout)?.trim().parse::() { Ok(o) => o, - Err(e) => { warn!("GupaxP2poolApi | [int_payout] parse error: {}", e); return Err(TomlError::Parse("int_payout")) } + Err(e) => { warn!("GupaxP2poolApi | [payout] parse error: {}", e); return Err(TomlError::Parse("payout")) } }; - let xmr = match read_to_string(File::IntXmr, &self.path_xmr)?.trim().parse::() { - Ok(o) => AtomicUnit::from_u128(o), + let xmr = match read_to_string(File::Xmr, &self.path_xmr)?.trim().parse::() { + Ok(o) => AtomicUnit::from_u64(o), Err(e) => { warn!("GupaxP2poolApi | [xmr] parse error: {}", e); return Err(TomlError::Parse("xmr")) } }; - let payout = HumanNumber::from_u64(int_payout); - let log_payout = read_to_string(File::LogPayout, &self.path_log_payout)?; - self.payout_ord.update_from_payout_log(&log_payout); + let payout = HumanNumber::from_u64(payout_u64); + let log = read_to_string(File::Log, &self.path_log)?; + self.payout_ord.update_from_payout_log(&log); *self = Self { + log, payout, + payout_u64, xmr, - int_payout, - log_payout, ..std::mem::take(self) }; Ok(()) } - // Takes raw int and raw log line and appends it. - pub fn add_payout(&mut self, xmr: u128, log_payout_line: &str) { - self.log_payout.push_str(log_payout_line); - self.int_payout += 1; - self.payout = HumanNumber::from_u64(self.int_payout); - self.xmr = self.xmr.add_u128(xmr); + // Takes the log line and (date, atomic_unit, block) and updates [self] and the [PayoutOrd] + pub fn add_payout(&mut self, log_payout_line: &str, date: String, atomic_unit: AtomicUnit, block: HumanNumber) { + self.log.push_str(log_payout_line); + self.payout_u64 += 1; + self.payout = HumanNumber::from_u64(self.payout_u64); + self.xmr = self.xmr.add_self(atomic_unit); + self.payout_ord.push(date, atomic_unit, block); } pub fn write_to_all_files(&self) -> Result<(), TomlError> { - Self::disk_overwrite(&self.int_payout.to_string(), &self.path_int_payout)?; - Self::disk_overwrite(&self.xmr.to_u128().to_string(), &self.path_xmr)?; - Self::disk_append(&self.log_payout, &self.path_log_payout)?; + Self::disk_overwrite(&self.payout_u64.to_string(), &self.path_payout)?; + Self::disk_overwrite(&self.xmr.to_string(), &self.path_xmr)?; + Self::disk_append(&self.log, &self.path_log)?; Ok(()) } pub fn disk_append(string: &str, path: &PathBuf) -> Result<(), TomlError> { use std::io::Write; - let mut file = match fs::OpenOptions::new().append(true).open(path) { + let mut file = match fs::OpenOptions::new().append(true).create(true).open(path) { Ok(f) => f, Err(e) => { error!("GupaxP2poolApi | Append [{}] ... FAIL: {}", path.display(), e); return Err(TomlError::Io(e)) }, }; @@ -677,7 +676,7 @@ impl GupaxP2poolApi { pub fn disk_overwrite(string: &str, path: &PathBuf) -> Result<(), TomlError> { use std::io::Write; - let mut file = match fs::OpenOptions::new().write(true).open(path) { + let mut file = match fs::OpenOptions::new().write(true).truncate(true).create(true).open(path) { Ok(f) => f, Err(e) => { error!("GupaxP2poolApi | Overwrite [{}] ... FAIL: {}", path.display(), e); return Err(TomlError::Io(e)) }, }; @@ -736,9 +735,9 @@ pub enum File { Pool, // pool.toml | XMRig manual pool selector // Gupax-P2Pool API - LogPayout, // payout | Raw log lines of P2Pool payouts received - IntPayout, // total_payout | Single [u128] representing total payouts - IntXmr, // total_xmr | Single [u128] representing total XMR mined in atomic units + Log, // log | Raw log lines of P2Pool payouts received + Payout, // payout | Single [u64] representing total payouts + Xmr, // xmr | Single [u64] representing total XMR mined in atomic units } //---------------------------------------------------------------------------------------------------- [Submenu] enum for [Status] tab @@ -1288,9 +1287,9 @@ mod test { // Create, write some fake data. GupaxP2poolApi::create_all_files(&path).unwrap(); - api.log_payout = "NOTICE 2022-01-27 01:30:23.1377 P2Pool You received a payout of 0.000000000001 XMR in block 2642816".to_string(); - api.int_payout = 1; - api.xmr = AtomicUnit::from_u128(2); + api.log = "NOTICE 2022-01-27 01:30:23.1377 P2Pool You received a payout of 0.000000000001 XMR in block 2642816".to_string(); + api.payout_u64 = 1; + api.xmr = AtomicUnit::from_u64(2); GupaxP2poolApi::write_to_all_files(&api).unwrap(); println!("AFTER WRITE: {:#?}", api); @@ -1299,10 +1298,10 @@ mod test { println!("AFTER READ: {:#?}", api); // Assert that the file read mutated the internal struct correctly. - assert_eq!(api.int_payout, 1); - assert_eq!(api.xmr.to_u128(), 2); + assert_eq!(api.payout_u64, 1); + assert_eq!(api.xmr.to_u64(), 2); assert!(!api.payout_ord.is_empty()); - assert!(api.log_payout.contains("2022-01-27 01:30:23.1377 P2Pool You received a payout of 0.000000000001 XMR in block 2642816\n")); + assert!(api.log.contains("2022-01-27 01:30:23.1377 P2Pool You received a payout of 0.000000000001 XMR in block 2642816\n")); } #[test] diff --git a/src/helper.rs b/src/helper.rs index 5d1507f..6d3249b 100644 --- a/src/helper.rs +++ b/src/helper.rs @@ -268,7 +268,7 @@ impl Helper { if regex.payout.is_match(&line) { debug!("P2Pool PTY | Found payout, attempting write: {}", line); let (date, atomic_unit, block) = PayoutOrd::parse_line(&line, ®ex); - GupaxP2poolApi::add_payout(&mut lock!(gupax_p2pool_api), atomic_unit.to_u128(), &line); + GupaxP2poolApi::add_payout(&mut lock!(gupax_p2pool_api), &line, date, atomic_unit, block); if let Err(e) = GupaxP2poolApi::write_to_all_files(&lock!(gupax_p2pool_api)) { error!("P2Pool PTY GupaxP2poolApi | Write error: {}", e); } } if let Err(e) = writeln!(lock!(output_parse), "{}", line) { error!("P2Pool PTY Parse | Output error: {}", e); } diff --git a/src/human.rs b/src/human.rs index fbc2897..e5034ce 100644 --- a/src/human.rs +++ b/src/human.rs @@ -15,11 +15,10 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . -use crate::constants::*; - //---------------------------------------------------------------------------------------------------- Constants // The locale numbers are formatting in is English, which looks like: [1,000] pub const LOCALE: num_format::Locale = num_format::Locale::en; +pub const ZERO_SECONDS: std::time::Duration = std::time::Duration::from_secs(0); //---------------------------------------------------------------------------------------------------- [HumanTime] // This converts a [std::time::Duration] into something more readable. @@ -37,11 +36,11 @@ impl Default for HumanTime { } impl HumanTime { - pub fn new() -> HumanTime { + pub const fn new() -> HumanTime { HumanTime(ZERO_SECONDS) } - pub fn into_human(d: Duration) -> HumanTime { + pub const fn into_human(d: Duration) -> HumanTime { HumanTime(d) } diff --git a/src/xmr.rs b/src/xmr.rs index 18b1711..6163748 100644 --- a/src/xmr.rs +++ b/src/xmr.rs @@ -16,7 +16,7 @@ // along with this program. If not, see . // This file is for handling actual XMR integers/floats using [AtomicUnit] & [PayoutOrd] -// AtomicUnit is just a wrapper around a [u128] implementing common XMR Atomic Unit functions. +// AtomicUnit is just a wrapper around a [u64] implementing common XMR Atomic Unit functions. // PayoutOrd is a wrapper around a [Vec] for sorting P2Pool payouts with this type signature: // "Vec<(String, AtomicUnit, HumanNumber)>" // These represent: @@ -35,30 +35,38 @@ use log::*; // too bad if I wrote it to disk as a float, but then I realized [.cmp()] doesn't // work on [f64] and also that Rust makes sorting floats a pain so instead of deleting // this code and making some float sorter, I might as well use it. -#[derive(Debug, Clone)] -pub struct AtomicUnit(u128); + +// [u64] can hold max: 18_446_744_073_709_551_615 which equals to 18,446,744,073 XMR (18 billion). +// Given the constant XMR tail emission of (0.3 per minute|18 per hour|432 per day|157,680 per year) +// this would take: 116,976~ years to overflow. +#[derive(Debug,Clone,Copy,PartialEq,Eq)] +pub struct AtomicUnit(u64); impl AtomicUnit { - pub fn new() -> Self { + pub const fn new() -> Self { Self(0) } - pub fn from_u128(u: u128) -> Self { + pub const fn from_u64(u: u64) -> Self { Self(u) } - pub fn add_u128(&mut self, u: u128) -> Self { + pub const fn add_u64(self, u: u64) -> Self { Self(self.0 + u) } - pub fn add_self(&mut self, atomic_unit: &Self) -> Self { + pub const fn add_self(self, atomic_unit: Self) -> Self { Self(self.0 + atomic_unit.0) } - pub fn to_u128(&self) -> u128 { + pub const fn to_u64(self) -> u64 { self.0 } + pub fn to_string(self) -> String { + self.0.to_string() + } + pub fn sum_vec(vec: &Vec) -> Self { let mut sum = 0; for int in vec { @@ -68,7 +76,7 @@ impl AtomicUnit { } pub fn from_f64(f: f64) -> Self { - Self((f * 1_000_000_000_000.0) as u128) + Self((f * 1_000_000_000_000.0) as u64) } pub fn to_f64(&self) -> f64 { @@ -111,10 +119,23 @@ impl PayoutOrd { Self(vec![(String::from("????-??-?? ??:??:??.????"), AtomicUnit::new(), HumanNumber::unknown())]) } - pub fn from_vec(vec: Vec<(String, AtomicUnit, HumanNumber)>) -> Self { + pub const fn from_vec(vec: Vec<(String, AtomicUnit, HumanNumber)>) -> Self { Self(vec) } + pub fn is_same(a: &Self, b: &Self) -> bool { + if a.0.is_empty() && b.0.is_empty() { return true } + if a.0.len() != b.0.len() { return false } + let mut n = 0; + for (date, atomic_unit, block) in &a.0 { + if *date != b.0[n].0 { return false } + if *atomic_unit != b.0[n].1 { return false } + if *block != b.0[n].2 { return false } + n += 1; + } + true + } + pub fn is_empty(&self) -> bool { self.0.is_empty() } @@ -175,26 +196,31 @@ impl PayoutOrd { *self = Self(vec); } + // Takes the wrapper types, and pushes to existing [Self] + pub fn push(&mut self, date: String, atomic_unit: AtomicUnit, block: HumanNumber) { + self.0.push((date, atomic_unit, block)); + } + // Takes the raw components (no wrapper types), convert them and pushes to existing [Self] - pub fn push(&mut self, date: &str, atomic_unit: u128, block: u64) { + pub fn push_raw(&mut self, date: &str, atomic_unit: u64, block: u64) { let atomic_unit = AtomicUnit(atomic_unit); let block = HumanNumber::from_u64(block); self.0.push((date.to_string(), atomic_unit, block)); } pub fn atomic_unit_sum(&self) -> AtomicUnit { - let mut sum: u128 = 0; + let mut sum: u64 = 0; for (_, atomic_unit, _) in &self.0 { - sum += atomic_unit.to_u128(); + sum += atomic_unit.to_u64(); } - AtomicUnit::from_u128(sum) + AtomicUnit::from_u64(sum) } // Sort [Self] from highest payout to lowest pub fn sort_payout_high_to_low(&mut self) { // This is a little confusing because wrapper types are basically 1 element tuples so: // self.0 = The [Vec] within [PayoutOrd] - // b.1.0 = [b] is [(String, AtomicUnit, HumanNumber)], [.1] is the [AtomicUnit] inside it, [.0] is the [u128] inside that + // b.1.0 = [b] is [(String, AtomicUnit, HumanNumber)], [.1] is the [AtomicUnit] inside it, [.0] is the [u64] inside that // a.1.0 = Same deal, but we compare it with the previous value (b) self.0.sort_by(|a, b| b.1.0.cmp(&a.1.0)); } @@ -249,7 +275,7 @@ r#"2021-12-21 01:01:01.1111 | 0.001000000000 XMR | Block 1,234,567 let mut payout_ord = PayoutOrd::from_vec(vec![]); let should_be = "2022-09-08 18:42:55.4636 | 0.000000000001 XMR | Block 2,654,321\n"; println!("BEFORE: {:#?}", payout_ord); - payout_ord.push("2022-09-08 18:42:55.4636", 1, 2654321); + payout_ord.push_raw("2022-09-08 18:42:55.4636", 1, 2654321); println!("AFTER: {}", payout_ord); println!("SHOULD_BE: {}", should_be); assert_eq!(payout_ord.to_string(), should_be); @@ -261,14 +287,14 @@ r#"2021-12-21 01:01:01.1111 | 0.001000000000 XMR | Block 1,234,567 use crate::xmr::AtomicUnit; use crate::human::HumanNumber; let mut payout_ord = PayoutOrd::from_vec(vec![ - ("2022-09-08 18:42:55.4636".to_string(), AtomicUnit::from_u128(1), HumanNumber::from_u64(2654321)), - ("2022-09-09 16:18:26.7582".to_string(), AtomicUnit::from_u128(1), HumanNumber::from_u64(2654322)), - ("2022-09-10 11:15:21.1272".to_string(), AtomicUnit::from_u128(1), HumanNumber::from_u64(2654323)), + ("2022-09-08 18:42:55.4636".to_string(), AtomicUnit::from_u64(1), HumanNumber::from_u64(2654321)), + ("2022-09-09 16:18:26.7582".to_string(), AtomicUnit::from_u64(1), HumanNumber::from_u64(2654322)), + ("2022-09-10 11:15:21.1272".to_string(), AtomicUnit::from_u64(1), HumanNumber::from_u64(2654323)), ]); println!("OG: {:#?}", payout_ord); let sum = PayoutOrd::atomic_unit_sum(&payout_ord); - println!("SUM: {}", sum.to_u128()); - assert_eq!(sum.to_u128(), 3); + println!("SUM: {}", sum.to_u64()); + assert_eq!(sum.to_u64(), 3); } #[test] @@ -277,9 +303,9 @@ r#"2021-12-21 01:01:01.1111 | 0.001000000000 XMR | Block 1,234,567 use crate::xmr::AtomicUnit; use crate::human::HumanNumber; let mut payout_ord = PayoutOrd::from_vec(vec![ - ("2022-09-08 18:42:55.4636".to_string(), AtomicUnit::from_u128(1000000000), HumanNumber::from_u64(2654321)), - ("2022-09-09 16:18:26.7582".to_string(), AtomicUnit::from_u128(2000000000), HumanNumber::from_u64(2654322)), - ("2022-09-10 11:15:21.1272".to_string(), AtomicUnit::from_u128(3000000000), HumanNumber::from_u64(2654323)), + ("2022-09-08 18:42:55.4636".to_string(), AtomicUnit::from_u64(1000000000), HumanNumber::from_u64(2654321)), + ("2022-09-09 16:18:26.7582".to_string(), AtomicUnit::from_u64(2000000000), HumanNumber::from_u64(2654322)), + ("2022-09-10 11:15:21.1272".to_string(), AtomicUnit::from_u64(3000000000), HumanNumber::from_u64(2654323)), ]); println!("OG: {:#?}", payout_ord); @@ -307,4 +333,25 @@ r#"2022-09-08 18:42:55.4636 | 0.001000000000 XMR | Block 2,654,321 println!("IS:\n{}", payout_ord); assert_eq!(payout_ord.to_string(), should_be); } + + #[test] + fn payout_ord_is_same() { + use crate::xmr::PayoutOrd; + use crate::xmr::AtomicUnit; + use crate::human::HumanNumber; + let mut payout_ord = PayoutOrd::from_vec(vec![ + ("2022-09-08 18:42:55.4636".to_string(), AtomicUnit::from_u64(1000000000), HumanNumber::from_u64(2654321)), + ("2022-09-09 16:18:26.7582".to_string(), AtomicUnit::from_u64(2000000000), HumanNumber::from_u64(2654322)), + ("2022-09-10 11:15:21.1272".to_string(), AtomicUnit::from_u64(3000000000), HumanNumber::from_u64(2654323)), + ]); + let payout_ord_2 = payout_ord.clone(); + println!("1: {:#?}", payout_ord); + println!("2: {:#?}", payout_ord); + + assert!(PayoutOrd::is_same(&payout_ord, &payout_ord_2) == true); + payout_ord.push_raw("2022-09-08 18:42:55.4636", 1000000000, 2654321); + println!("1: {:#?}", payout_ord); + println!("2: {:#?}", payout_ord); + assert!(PayoutOrd::is_same(&payout_ord, &payout_ord_2) == false); + } }