From 42e67d940ecb92adfb8134d7703951b423186052 Mon Sep 17 00:00:00 2001 From: "hinto.janai" Date: Sun, 26 Nov 2023 16:19:52 -0500 Subject: [PATCH] node: only add simple nodes to backup lists if green/yellow This avoids adding potential dead nodes to the list and causing P2Pool to abort. If no ping data is available, no backup nodes are added. --- src/constants.rs | 32 +++++++++++++++------------ src/main.rs | 57 ++++++++++++++++++++++++++++++++++++------------ src/node.rs | 21 ++++++++++-------- src/p2pool.rs | 4 ++-- src/xmrig.rs | 2 +- 5 files changed, 76 insertions(+), 40 deletions(-) diff --git a/src/constants.rs b/src/constants.rs index 8854282..d0b301e 100644 --- a/src/constants.rs +++ b/src/constants.rs @@ -270,20 +270,24 @@ 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 remote Monero nodes at Gupax startup"; -pub const P2POOL_AUTO_SELECT: &str = "Automatically select the fastest remote Monero node after pinging"; -pub const P2POOL_BACKUP_HOST: &str = "Automatically switch to the other nodes listed if the current one is down"; -pub const P2POOL_SELECT_FASTEST: &str = "Select the fastest remote Monero node"; -pub const P2POOL_SELECT_RANDOM: &str = "Select a random remote Monero node"; -pub const P2POOL_SELECT_LAST: &str = "Select the previous remote Monero node"; -pub const P2POOL_SELECT_NEXT: &str = "Select the next remote Monero node"; -pub const P2POOL_PING: &str = "Ping the built-in remote 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_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 remote Monero nodes at Gupax startup"; +pub const P2POOL_AUTO_SELECT: &str = "Automatically select the fastest remote Monero node after pinging"; +pub const P2POOL_BACKUP_HOST_SIMPLE: &str = +r#"Automatically switch to the other nodes listed if the current one is down. + +Note: you must ping the remote nodes or this feature will default to only using the currently selected node."#; +pub const P2POOL_BACKUP_HOST_ADVANCED: &str = "Automatically switch to the other nodes in your list if the current one is down."; +pub const P2POOL_SELECT_FASTEST: &str = "Select the fastest remote Monero node"; +pub const P2POOL_SELECT_RANDOM: &str = "Select a random remote Monero node"; +pub const P2POOL_SELECT_LAST: &str = "Select the previous remote Monero node"; +pub const P2POOL_SELECT_NEXT: &str = "Select the next remote Monero node"; +pub const P2POOL_PING: &str = "Ping the built-in remote 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_COMMUNITY_NODE_WARNING: &str = r#"TL;DR: Run & use your own Monero Node. diff --git a/src/main.rs b/src/main.rs index 60abe11..2a7a1da 100644 --- a/src/main.rs +++ b/src/main.rs @@ -538,36 +538,65 @@ impl App { return None; } - if self.state.p2pool.simple { - let mut ip = lock!(self.ping).fastest.to_string(); + // INVARIANT: + // We must ensure all nodes are capable of + // sending/receiving valid JSON-RPC requests. + // + // This is done during the `Ping` phase, meaning + // all the nodes listed in our `self.ping` should + // have ping data. We can use this data to filter + // out "dead" nodes. + // + // The user must have at least pinged once so that + // we actually have this data to work off of, else, + // this "backup host" feature will return here + // with 0 extra nodes as we can't be sure that any + // of them are actually online. + // + // Realistically, most of them are, but we can't be sure, + // and checking here without explicitly asking the user + // to connect to nodes is a no-go (also, non-async environment). + if !lock!(self.ping).pinged { + warn!("Backup hosts ... simple node backup: no ping data available, returning None"); + return None; + } + if self.state.p2pool.simple { let mut vec = Vec::with_capacity(REMOTE_NODES.len()); - for _ in 0..REMOTE_NODES.len() { - let (ip_new, rpc, zmq) = RemoteNode::get_ip_rpc_zmq(&ip); + // Locking during this entire loop should be fine, + // only a few nodes to iter through. + for pinged_node in lock!(self.ping).nodes.iter() { + // Continue if this node is not green/yellow. + if pinged_node.ms > crate::node::RED_NODE_PING { + continue; + } + + let (ip, rpc, zmq) = RemoteNode::get_ip_rpc_zmq(&pinged_node.ip); let node = Node { - ip: ip_new.into(), + ip: ip.into(), rpc: rpc.into(), zmq: zmq.into(), }; vec.push(node); - ip = RemoteNode::get_next_from_ping(ip_new, &lock!(self.ping).nodes); } - return Some(vec); - } - - if !self.state.p2pool.simple { - return Some(self.node_vec + if vec.is_empty() { + warn!("Backup hosts ... simple node backup: no viable nodes found"); + None + } else { + info!("Backup hosts ... simple node backup list: {vec:#?}"); + Some(vec) + } + } else { + Some(self.node_vec .iter() .map(|(_, node)| node.clone()) .collect() - ); + ) } - - None } } diff --git a/src/node.rs b/src/node.rs index 21a6382..bd95bb8 100644 --- a/src/node.rs +++ b/src/node.rs @@ -214,6 +214,11 @@ pub fn format_ip(ip: &str) -> String { } //---------------------------------------------------------------------------------------------------- Node data +pub const GREEN_NODE_PING: u128 = 300; +// yellow is anything in-between green/red +pub const RED_NODE_PING: u128 = 500; +pub const TIMEOUT_NODE_PING: u128 = 5000; + #[derive(Debug, Clone)] pub struct NodeData { pub ip: &'static str, @@ -387,8 +392,6 @@ impl Ping { percent: f32, node_vec: Arc>> ) { - const DEAD_NODE_PING: u128 = 5000; - let ms; let now = Instant::now(); @@ -402,30 +405,30 @@ impl Ping { if rpc.result.mainnet && rpc.result.synchronized { ms = now.elapsed().as_millis(); } else { - ms = DEAD_NODE_PING; + ms = TIMEOUT_NODE_PING; warn!("Ping | {ip} responded with valid get_info but is not in sync, remove this node!"); } } _ => { - ms = DEAD_NODE_PING; + ms = TIMEOUT_NODE_PING; warn!("Ping | {ip} responded but with invalid get_info, remove this node!"); } } }, - _ => ms = DEAD_NODE_PING, + _ => ms = TIMEOUT_NODE_PING, }; }, - _ => ms = DEAD_NODE_PING, + _ => ms = TIMEOUT_NODE_PING, }; let info = format!("{ms}ms ... {ip}"); info!("Ping | {ms}ms ... {ip}"); - let color = if ms < 300 { + let color = if ms < GREEN_NODE_PING { GREEN - } else if ms < 500 { + } else if ms < RED_NODE_PING { YELLOW - } else if ms < DEAD_NODE_PING { + } else if ms < TIMEOUT_NODE_PING { RED } else { BLACK diff --git a/src/p2pool.rs b/src/p2pool.rs index 45c6e39..49c08df 100644 --- a/src/p2pool.rs +++ b/src/p2pool.rs @@ -231,7 +231,7 @@ impl crate::disk::P2pool { ui.add_sized([width, height], Checkbox::new(&mut self.auto_ping, "Auto-ping")).on_hover_text(P2POOL_AUTO_NODE); ui.separator(); // [Backup host] - ui.add_sized([width, height], Checkbox::new(&mut self.backup_host, "Backup host")).on_hover_text(P2POOL_BACKUP_HOST); + ui.add_sized([width, height], Checkbox::new(&mut self.backup_host, "Backup host")).on_hover_text(P2POOL_BACKUP_HOST_SIMPLE); })}); debug!("P2Pool Tab | Rendering warning text"); @@ -494,7 +494,7 @@ impl crate::disk::P2pool { let width = width - SPACE; let height = ui.available_height() / 3.0; // [Backup host] - ui.add_sized([width, height], Checkbox::new(&mut self.backup_host, "Backup host")).on_hover_text(P2POOL_BACKUP_HOST); + ui.add_sized([width, height], Checkbox::new(&mut self.backup_host, "Backup host")).on_hover_text(P2POOL_BACKUP_HOST_ADVANCED); }); } } diff --git a/src/xmrig.rs b/src/xmrig.rs index e1813cf..74e5103 100644 --- a/src/xmrig.rs +++ b/src/xmrig.rs @@ -114,7 +114,7 @@ impl crate::disk::Xmrig { ui.vertical(|ui| { let width = width / 10.0; let text_width = width * 2.4; - ui.spacing_mut().slider_width = width * 7.1; + ui.spacing_mut().slider_width = width * 6.5; ui.spacing_mut().icon_width = width / 25.0; ui.horizontal(|ui| { ui.add_sized([text_width, text_edit], Label::new(format!("Threads [1-{}]:", self.max_threads)));