From 991f202fce548afc6ce2e0d5b6285229a118d043 Mon Sep 17 00:00:00 2001
From: hinto-janaiyo <hinto.janaiyo@protonmail.com>
Date: Sat, 31 Dec 2022 13:47:41 -0500
Subject: [PATCH] Status Submenu: (de)serialize logs in our own format

Instead of saving P2Pool payout logs as they are, they are now
(de)serialized in the same [Display] format, e.g:

<DATE> <TIME>            | <12_DOT_FLOAT> XMR | Block <BLOCK>
2022-09-31 12:53:52.8683 | 0.166122683521 XMR | Block 2,713,512

The parsing functions were updated to be able to read both raw
log lines and the new above format.
---
 Cargo.lock    | 24 +++++++-------
 src/disk.rs   | 91 ++++++++++++++++++++++++++++++---------------------
 src/helper.rs |  7 ++--
 src/human.rs  |  3 ++
 src/regex.rs  |  4 +++
 src/status.rs | 17 +++++-----
 src/xmr.rs    | 60 +++++++++++++++++++++++----------
 7 files changed, 127 insertions(+), 79 deletions(-)

diff --git a/Cargo.lock b/Cargo.lock
index a9bb987..fa42541 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -449,9 +449,9 @@ dependencies = [
 
 [[package]]
 name = "calloop"
-version = "0.10.4"
+version = "0.10.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "19457a0da465234abd76134a5c2a910c14bd3c5558463e4396ab9a37a328e465"
+checksum = "1a59225be45a478d772ce015d9743e49e92798ece9e34eda9a6aa2a6a7f40192"
 dependencies = [
  "log",
  "nix 0.25.1",
@@ -1841,9 +1841,9 @@ dependencies = [
 
 [[package]]
 name = "half"
-version = "2.1.0"
+version = "2.2.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ad6a9459c9c30b177b925162351f97e7d967c7ea8bab3b8352805327daf45554"
+checksum = "6c467d36af040b7b2681f5fddd27427f6da8d3d072f575a265e181d2f8e8d157"
 dependencies = [
  "crunchy",
 ]
@@ -2665,9 +2665,9 @@ dependencies = [
 
 [[package]]
 name = "once_cell"
-version = "1.16.0"
+version = "1.17.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "86f0b0d4bf799edbc74508c1e8bf170ff5f41238e5f8225603ca7caaae2b7860"
+checksum = "6f61fba1741ea2b3d6a1e3178721804bb716a68a6aeba1149b5d52e3d464ea66"
 
 [[package]]
 name = "opaque-debug"
@@ -3420,18 +3420,18 @@ checksum = "58bc9567378fc7690d6b2addae4e60ac2eeea07becb2c64b9f218b53865cba2a"
 
 [[package]]
 name = "serde"
-version = "1.0.151"
+version = "1.0.152"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "97fed41fc1a24994d044e6db6935e69511a1153b52c15eb42493b26fa87feba0"
+checksum = "bb7d1f0d3021d347a83e556fc4683dea2ea09d87bccdf88ff5c12545d89d5efb"
 dependencies = [
  "serde_derive",
 ]
 
 [[package]]
 name = "serde_derive"
-version = "1.0.151"
+version = "1.0.152"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "255abe9a125a985c05190d687b320c12f9b1f0b99445e608c21ba0782c719ad8"
+checksum = "af487d118eecd09402d70a5d72551860e788df87b464af30e5ea6a38c75c541e"
 dependencies = [
  "proc-macro2",
  "quote",
@@ -3832,9 +3832,9 @@ dependencies = [
 
 [[package]]
 name = "sysinfo"
-version = "0.27.1"
+version = "0.27.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ccb297c0afb439440834b4bcf02c5c9da8ec2e808e70f36b0d8e815ff403bd24"
+checksum = "17351d0e9eb8841897b14e9669378f3c69fb57779cc04f8ca9a9d512edfb2563"
 dependencies = [
  "cfg-if",
  "core-foundation-sys",
diff --git a/src/disk.rs b/src/disk.rs
index 4613b1f..bd245ac 100644
--- a/src/disk.rs
+++ b/src/disk.rs
@@ -605,6 +605,7 @@ pub struct GupaxP2poolApi {
 impl Default for GupaxP2poolApi { fn default() -> Self { Self::new() } }
 
 impl GupaxP2poolApi {
+	//---------------------------------------------------------------------------------------------------- Init, these pretty much only get called once
 	pub fn new() -> Self {
 		Self {
 			log: String::new(),
@@ -659,34 +660,6 @@ impl GupaxP2poolApi {
 		Ok(())
 	}
 
-	pub fn update_log_rev(&mut self) {
-		let mut log_rev = String::with_capacity(self.log.len());
-		for line in self.log.lines().rev() {
-			log_rev.push_str(line);
-			log_rev.push_str("\n");
-		}
-		self.log_rev = log_rev;
-	}
-
-	pub fn append_head_log_rev(&mut self, line: &str) {
-		self.log_rev = format!("{}\n{}", line, self.log_rev);
-	}
-
-	pub fn update_payout_low(&mut self) {
-		self.payout_ord.sort_payout_low_to_high();
-		self.payout_low = self.payout_ord.to_string();
-	}
-
-	pub fn update_payout_high(&mut self) {
-		self.payout_ord.sort_payout_high_to_low();
-		self.payout_high = self.payout_ord.to_string();
-	}
-
-	pub fn update_payout_strings(&mut self) {
-		self.update_payout_low();
-		self.update_payout_high();
-	}
-
 	pub fn read_all_files_and_update(&mut self) -> Result<(), TomlError> {
 		let payout_u64 = match read_to_string(File::Payout, &self.path_payout)?.trim().parse::<u64>() {
 			Ok(o)  => o,
@@ -711,10 +684,48 @@ impl GupaxP2poolApi {
 		Ok(())
 	}
 
-	// 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.append_head_log_rev(log_payout_line);
+	//---------------------------------------------------------------------------------------------------- Live, functions that actually update/write live stats
+	pub fn update_log_rev(&mut self) {
+		let mut log_rev = String::with_capacity(self.log.len());
+		for line in self.log.lines().rev() {
+			log_rev.push_str(line);
+			log_rev.push_str("\n");
+		}
+		self.log_rev = log_rev;
+	}
+
+	pub fn format_payout(date: &str, atomic_unit: &AtomicUnit, block: &HumanNumber) -> String {
+		format!("{} | {} XMR | Block {}", date, atomic_unit, block)
+	}
+
+	pub fn append_log(&mut self, formatted_log_line: &str) {
+		self.log.push_str(formatted_log_line);
+		self.log.push_str("\n");
+	}
+
+	pub fn append_head_log_rev(&mut self, formatted_log_line: &str) {
+		self.log_rev = format!("{}\n{}", formatted_log_line, self.log_rev);
+	}
+
+	pub fn update_payout_low(&mut self) {
+		self.payout_ord.sort_payout_low_to_high();
+		self.payout_low = self.payout_ord.to_string();
+	}
+
+	pub fn update_payout_high(&mut self) {
+		self.payout_ord.sort_payout_high_to_low();
+		self.payout_high = self.payout_ord.to_string();
+	}
+
+	pub fn update_payout_strings(&mut self) {
+		self.update_payout_low();
+		self.update_payout_high();
+	}
+
+	// Takes the (date, atomic_unit, block) and updates [self] and the [PayoutOrd]
+	pub fn add_payout(&mut self, formatted_log_line: &str, date: String, atomic_unit: AtomicUnit, block: HumanNumber) {
+		self.append_log(formatted_log_line);
+		self.append_head_log_rev(formatted_log_line);
 		self.payout_u64 += 1;
 		self.payout = HumanNumber::from_u64(self.payout_u64);
 		self.xmr = self.xmr.add_self(atomic_unit);
@@ -722,20 +733,20 @@ impl GupaxP2poolApi {
 		self.update_payout_strings();
 	}
 
-	pub fn write_to_all_files(&self) -> Result<(), TomlError> {
+	pub fn write_to_all_files(&self, formatted_log_line: &str) -> Result<(), TomlError> {
 		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)?;
+		Self::disk_append(formatted_log_line, &self.path_log)?;
 		Ok(())
 	}
 
-	pub fn disk_append(string: &str, path: &PathBuf) -> Result<(), TomlError> {
+	pub fn disk_append(formatted_log_line: &str, path: &PathBuf) -> Result<(), TomlError> {
 		use std::io::Write;
 		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)) },
 		};
-		match writeln!(file, "{}", string) {
+		match writeln!(file, "{}", formatted_log_line) {
 			Ok(_) => { debug!("GupaxP2poolApi | Append [{}] ... OK", path.display()); Ok(()) },
 			Err(e) => { error!("GupaxP2poolApi | Append [{}] ... FAIL: {}", path.display(), e); Err(TomlError::Io(e)) },
 		}
@@ -1384,6 +1395,8 @@ mod test {
 	#[test]
 	fn create_and_serde_gupax_p2pool_api() {
 		use crate::disk::GupaxP2poolApi;
+		use crate::regex::P2poolRegex;
+		use crate::xmr::PayoutOrd;
 		use crate::xmr::AtomicUnit;
 
 		// Get API dir, fill paths.
@@ -1398,7 +1411,9 @@ mod test {
 		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();
+		let (date, atomic_unit, block) = PayoutOrd::parse_raw_payout_line(&api.log, &P2poolRegex::new());
+		let formatted_log_line = GupaxP2poolApi::format_payout(&date, &atomic_unit, &block);
+		GupaxP2poolApi::write_to_all_files(&api, &formatted_log_line).unwrap();
 		println!("AFTER WRITE: {:#?}", api);
 
 		// Read
@@ -1409,7 +1424,7 @@ mod test {
 		assert_eq!(api.payout_u64, 1);
 		assert_eq!(api.xmr.to_u64(), 2);
 		assert!(!api.payout_ord.is_empty());
-		assert!(api.log.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 | 0.000000000001 XMR | Block 2,642,816"));
 	}
 
 	#[test]
diff --git a/src/helper.rs b/src/helper.rs
index c5c79d6..ec2dd2f 100644
--- a/src/helper.rs
+++ b/src/helper.rs
@@ -267,9 +267,10 @@ impl Helper {
 //			println!("{}", line); // For debugging.
 			if regex.payout.is_match(&line) {
 				debug!("P2Pool PTY | Found payout, attempting write: {}", line);
-				let (date, atomic_unit, block) = PayoutOrd::parse_line(&line, &regex);
-				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); }
+				let (date, atomic_unit, block) = PayoutOrd::parse_raw_payout_line(&line, &regex);
+				let formatted_log_line = GupaxP2poolApi::format_payout(&date, &atomic_unit, &block);
+				GupaxP2poolApi::add_payout(&mut lock!(gupax_p2pool_api), &formatted_log_line, date, atomic_unit, block);
+				if let Err(e) = GupaxP2poolApi::write_to_all_files(&lock!(gupax_p2pool_api), &formatted_log_line) { error!("P2Pool PTY GupaxP2poolApi | Write error: {}", e); }
 			}
 			if let Err(e) = writeln!(lock!(output_parse), "{}", line) { error!("P2Pool PTY Parse | Output error: {}", e); }
 			if let Err(e) = writeln!(lock!(output_pub), "{}", line) { error!("P2Pool PTY Pub | Output error: {}", e); }
diff --git a/src/human.rs b/src/human.rs
index e62356d..4bf267a 100644
--- a/src/human.rs
+++ b/src/human.rs
@@ -113,6 +113,9 @@ impl HumanNumber {
 	pub fn unknown() -> Self {
 		Self("???".to_string())
 	}
+	pub fn from_str(s: &str) -> Self {
+		Self(s.to_string())
+	}
 	pub fn to_percent(f: f32) -> Self {
 		if f < 0.01 {
 			Self("0%".to_string())
diff --git a/src/regex.rs b/src/regex.rs
index 8bb802c..ca2e60f 100644
--- a/src/regex.rs
+++ b/src/regex.rs
@@ -74,6 +74,7 @@ pub struct P2poolRegex {
 	pub payout_float: regex::Regex,
 	pub block: regex::Regex,
 	pub block_int: regex::Regex,
+	pub block_comma: regex::Regex,
 }
 
 impl P2poolRegex {
@@ -84,6 +85,7 @@ impl P2poolRegex {
 			payout_float: regex::Regex::new("[0-9].[0-9]{12}").unwrap(), // Assumes 12 digits after the dot.
 			block: regex::Regex::new("block [0-9]{7}").unwrap(), // Monero blocks will be 7 digits for... the next 10,379 years
 			block_int: regex::Regex::new("[0-9]{7}").unwrap(),
+			block_comma: regex::Regex::new("[0-9],[0-9]{3},[0-9]{3}").unwrap(),
 		}
 	}
 }
@@ -115,10 +117,12 @@ mod test {
 		use regex::Regex;
 		let r = crate::P2poolRegex::new();
 		let text = "NOTICE  2022-11-11 11:11:11.1111 P2Pool You received a payout of 0.111111111111 XMR in block 1111111";
+		let text2 = "2022-11-11 11:11:11.1111 | 0.111111111111 XMR | Block 1,111,111";
 		assert_eq!(r.payout.find(text).unwrap().as_str(),       "payout of 0.111111111111 XMR");
 		assert_eq!(r.payout_float.find(text).unwrap().as_str(), "0.111111111111");
 		assert_eq!(r.date.find(text).unwrap().as_str(),         "2022-11-11 11:11:11.1111");
 		assert_eq!(r.block.find(text).unwrap().as_str(),        "block 1111111");
 		assert_eq!(r.block_int.find(text).unwrap().as_str(),    "1111111");
+		assert_eq!(r.block_comma.find(text2).unwrap().as_str(),  "1,111,111");
 	}
 }
diff --git a/src/status.rs b/src/status.rs
index 150792c..6a59de8 100644
--- a/src/status.rs
+++ b/src/status.rs
@@ -165,8 +165,8 @@ pub fn show(&mut self, sys: &Arc<Mutex<Sys>>, p2pool_api: &Arc<Mutex<PubP2poolAp
 		egui::Frame::none().fill(DARK_GRAY).show(ui, |ui| {
 			egui::ScrollArea::vertical().stick_to_bottom(self.payout_view == PayoutView::Oldest).max_width(width).max_height(log).auto_shrink([false; 2]).show_viewport(ui, |ui, _| {
 				match self.payout_view {
-					PayoutView::Latest   => ui.add_sized([width, log], TextEdit::multiline(&mut api.log.as_str())),
-					PayoutView::Oldest   => ui.add_sized([width, log], TextEdit::multiline(&mut api.log_rev.as_str())),
+					PayoutView::Latest   => ui.add_sized([width, log], TextEdit::multiline(&mut api.log_rev.as_str())),
+					PayoutView::Oldest   => ui.add_sized([width, log], TextEdit::multiline(&mut api.log.as_str())),
 					PayoutView::Biggest  => ui.add_sized([width, log], TextEdit::multiline(&mut api.payout_high.as_str())),
 					PayoutView::Smallest => ui.add_sized([width, log], TextEdit::multiline(&mut api.payout_low.as_str())),
 				};
@@ -191,14 +191,15 @@ pub fn show(&mut self, sys: &Arc<Mutex<Sys>>, p2pool_api: &Arc<Mutex<PubP2poolAp
 		ui.separator();
 		if ui.add_sized([button, text], SelectableLabel::new(self.hash_metric == Hash::Giga, "Giga")).on_hover_text(STATUS_SUBMENU_GIGA).clicked() { self.hash_metric = Hash::Giga; }
 		ui.separator();
-		ui.spacing_mut().slider_width = button*12.5;
+		ui.spacing_mut().slider_width = button*11.5;
 		ui.add_sized([button*14.0, text], Slider::new(&mut self.hashrate, 1.0..=1_000.0));
 	})});
-	let api = lock!(p2pool_api);
+	// Actual stats
 	ui.set_enabled(p2pool_alive);
 	let text = height / 25.0;
 	let width = (width/3.0)-(SPACE*1.666);
 	let min_height = ui.available_height()/1.25;
+	let api = lock!(p2pool_api);
 	ui.horizontal(|ui| {
 	ui.group(|ui| { ui.vertical(|ui| {
 		ui.set_min_height(min_height);
@@ -206,19 +207,19 @@ pub fn show(&mut self, sys: &Arc<Mutex<Sys>>, p2pool_api: &Arc<Mutex<PubP2poolAp
 			let hashrate          = Hash::convert_to_hash(self.hashrate, self.hash_metric) as u64;
 			let p2pool_share_mean = PubP2poolApi::calculate_share_or_block_time(hashrate, api.p2pool_difficulty_u64);
 			let solo_block_mean   = PubP2poolApi::calculate_share_or_block_time(hashrate, api.monero_difficulty_u64);
-			ui.add_sized([width, text], Label::new(RichText::new("P2Pool Block Mean").underline().color(BONE))).on_hover_text(STATUS_SUBMENU_P2POOL_BLOCK_MEAN);
-			ui.add_sized([width, text], Label::new(api.p2pool_block_mean.to_string()));
 			ui.add_sized([width, text], Label::new(RichText::new("Your P2Pool Hashrate").underline().color(BONE))).on_hover_text(STATUS_SUBMENU_YOUR_P2POOL_HASHRATE);
 			ui.add_sized([width, text], Label::new(format!("{} H/s", HumanNumber::from_u64(hashrate))));
+			ui.add_sized([width, text], Label::new(RichText::new("P2Pool Block Mean").underline().color(BONE))).on_hover_text(STATUS_SUBMENU_P2POOL_BLOCK_MEAN);
+			ui.add_sized([width, text], Label::new(api.p2pool_block_mean.to_string()));
 			ui.add_sized([width, text], Label::new(RichText::new("Your P2Pool Share Mean").underline().color(BONE))).on_hover_text(STATUS_SUBMENU_P2POOL_SHARE_MEAN);
 			ui.add_sized([width, text], Label::new(p2pool_share_mean.to_string()));
 			ui.add_sized([width, text], Label::new(RichText::new("Your Solo Block Mean").underline().color(BONE))).on_hover_text(STATUS_SUBMENU_SOLO_BLOCK_MEAN);
 			ui.add_sized([width, text], Label::new(solo_block_mean.to_string()));
 		} else {
-			ui.add_sized([width, text], Label::new(RichText::new("P2Pool Block Mean").underline().color(BONE))).on_hover_text(STATUS_SUBMENU_P2POOL_BLOCK_MEAN);
-			ui.add_sized([width, text], Label::new(api.p2pool_block_mean.to_string()));
 			ui.add_sized([width, text], Label::new(RichText::new("Your P2Pool Hashrate").underline().color(BONE))).on_hover_text(STATUS_SUBMENU_YOUR_P2POOL_HASHRATE);
 			ui.add_sized([width, text], Label::new(format!("{} H/s", api.hashrate_1h)));
+			ui.add_sized([width, text], Label::new(RichText::new("P2Pool Block Mean").underline().color(BONE))).on_hover_text(STATUS_SUBMENU_P2POOL_BLOCK_MEAN);
+			ui.add_sized([width, text], Label::new(api.p2pool_block_mean.to_string()));
 			ui.add_sized([width, text], Label::new(RichText::new("Your P2Pool Share Mean").underline().color(BONE))).on_hover_text(STATUS_SUBMENU_P2POOL_SHARE_MEAN);
 			ui.add_sized([width, text], Label::new(api.p2pool_share_mean.to_string()));
 			ui.add_sized([width, text], Label::new(RichText::new("Your Solo Block Mean").underline().color(BONE))).on_hover_text(STATUS_SUBMENU_SOLO_BLOCK_MEAN);
diff --git a/src/xmr.rs b/src/xmr.rs
index 3082fd7..938cb34 100644
--- a/src/xmr.rs
+++ b/src/xmr.rs
@@ -140,7 +140,8 @@ impl PayoutOrd {
 		self.0.is_empty()
 	}
 
-	pub fn parse_line(line: &str, regex: &P2poolRegex) -> (String, AtomicUnit, HumanNumber) {
+	// Expected input: "NOTICE  2022-01-27 01:30:23.1377 P2Pool You received a payout of 0.000000000001 XMR in block 2642816"
+	pub fn parse_raw_payout_line(line: &str, regex: &P2poolRegex) -> (String, AtomicUnit, HumanNumber) {
 		// Date
 		let date = match regex.date.find(line) {
 			Some(date) => date.as_str().to_string(),
@@ -154,9 +155,11 @@ impl PayoutOrd {
 					Err(e) => { error!("P2Pool | AtomicUnit parse error: [{}] on [{}]", e, line); AtomicUnit::new() },
 				}
 			} else {
+				error!("P2Pool | AtomicUnit parse error: [{}]", line);
 				AtomicUnit::new()
 			}
 		} else {
+			error!("P2Pool | AtomicUnit parse error: [{}]", line);
 			AtomicUnit::new()
 		};
 		// Block
@@ -167,31 +170,57 @@ impl PayoutOrd {
 					Err(e) => { error!("P2Pool | Block parse error: [{}] on [{}]", e, line); HumanNumber::unknown() },
 				}
 			} else {
+				error!("P2Pool | Block parse error: [{}]", line);
 				HumanNumber::unknown()
 			}
 		} else {
+			error!("P2Pool | Block parse error: [{}]", line);
 			HumanNumber::unknown()
 		};
 		(date, atomic_unit, block)
 	}
 
-	// Takes in input of ONLY P2Pool payout logs and
-	// converts it into a usable [PayoutOrd]
-	// It expects log lines like this:
-	// "NOTICE  2022-04-11 00:20:17.2571 P2Pool You received a payout of 0.001371623621 XMR in block 2562511"
+	// Expected input: "2022-01-27 01:30:23.1377 | 0.000000000001 XMR | Block 2,642,816"
+	pub fn parse_formatted_payout_line(line: &str, regex: &P2poolRegex) -> (String, AtomicUnit, HumanNumber) {
+		// Date
+		let date = match regex.date.find(line) {
+			Some(date) => date.as_str().to_string(),
+			None => { error!("P2Pool | Date parse error: [{}]", line); "????-??-?? ??:??:??.????".to_string() },
+		};
+		// AtomicUnit
+		let atomic_unit = if let Some(word) = regex.payout_float.find(line) {
+			match word.as_str().parse::<f64>() {
+				Ok(au) => AtomicUnit::from_f64(au),
+				Err(e) => { error!("P2Pool | AtomicUnit parse error: [{}] on [{}]", e, line); AtomicUnit::new() },
+			}
+		} else {
+			error!("P2Pool | AtomicUnit parse error: [{}]", line);
+			AtomicUnit::new()
+		};
+		// Block
+		let block = match regex.block_comma.find(line) {
+			Some(b) => HumanNumber::from_str(b.as_str()),
+			None    => { error!("P2Pool | Block parse error: [{}]", line); HumanNumber::unknown() },
+		};
+		(date, atomic_unit, block)
+	}
+
+	// Takes in input of ONLY P2Pool payout logs and converts it into a usable [PayoutOrd]
+	// It expects formatted log lines like this: "2022-04-11 00:20:17.2571 | 0.001371623621 XMR | Block 2,562,511"
 	// For efficiency reasons, I'd like to know the byte size
 	// we should allocate for the vector so we aren't adding every loop.
 	// Given a log [str], the equation for how many bytes the final vec will be is:
-	// (BYTES_OF_DATE + BYTES OF XMR + BYTES OF BLOCK) * amount_of_lines
+	// (BYTES_OF_DATE + BYTES OF XMR + BYTES OF BLOCK) + (SPACES, PIPES, MISC WORDS) * amount_of_lines
 	// The first three are more or less constants (monero block 10m is in 10,379 years...): [23, 14, 7] (sum: 44)
-	// Add 16 more bytes for wrapper type overhead and it's an even [60] bytes per line.
+	// Spaces, pipes, commas and words (XMR, Block): [19]
+	// Add 7 more bytes for wrapper type overhead and it's an even [70] bytes per line.
 	pub fn update_from_payout_log(&mut self, log: &str) {
 		let regex = P2poolRegex::new();
 		let amount_of_lines = log.lines().count();
-		let mut vec: Vec<(String, AtomicUnit, HumanNumber)> = Vec::with_capacity(60 * amount_of_lines);
+		let mut vec: Vec<(String, AtomicUnit, HumanNumber)> = Vec::with_capacity(70 * amount_of_lines);
 		for line in log.lines() {
 			debug!("PayoutOrg | Parsing line: [{}]", line);
-			vec.push(Self::parse_line(line, &regex));
+			vec.push(Self::parse_formatted_payout_line(line, &regex));
 		}
 		*self = Self(vec);
 	}
@@ -259,20 +288,15 @@ mod test {
 	fn update_p2pool_payout_log() {
 		use crate::xmr::PayoutOrd;
 		let log =
-r#"NOTICE  2021-12-21 01:01:01.1111 P2Pool You received a payout of 0.001000000000 XMR in block 1234567
-NOTICE  2021-12-21 02:01:01.1111 P2Pool You received a payout of 0.002000000000 XMR in block 2345678
-NOTICE  2021-12-21 03:01:01.1111 P2Pool You received a payout of 0.003000000000 XMR in block 3456789
+r#"2021-12-21 01:01:01.1111 | 0.001000000000 XMR | Block 1,234,567
+2021-12-21 02:01:01.1111 | 0.002000000000 XMR | Block 2,345,678
+2021-12-21 03:01:01.1111 | 0.003000000000 XMR | Block 3,456,789
 "#;
 		let mut payout_ord = PayoutOrd::new();
 		println!("BEFORE: {}", payout_ord);
 		PayoutOrd::update_from_payout_log(&mut payout_ord, log);
 		println!("AFTER: {}", payout_ord);
-		let should_be =
-r#"2021-12-21 01:01:01.1111 | 0.001000000000 XMR | Block 1,234,567
-2021-12-21 02:01:01.1111 | 0.002000000000 XMR | Block 2,345,678
-2021-12-21 03:01:01.1111 | 0.003000000000 XMR | Block 3,456,789
-"#;
-		assert_eq!(payout_ord.to_string(), should_be)
+		assert_eq!(payout_ord.to_string(), log);
 	}
 
 	#[test]