feat: remove non responsive nodes, faster and better node pinging.

This commit is contained in:
Cyrix126 2024-10-31 14:15:59 +01:00
parent 279bdcc678
commit 5a4759109f

View file

@ -28,18 +28,13 @@ use std::time::{Duration, Instant};
// Remote Monero Nodes with ZMQ enabled. // Remote Monero Nodes with ZMQ enabled.
// The format is an array of tuples consisting of: (IP, LOCATION, RPC_PORT, ZMQ_PORT) // The format is an array of tuples consisting of: (IP, LOCATION, RPC_PORT, ZMQ_PORT)
pub const REMOTE_NODES: [(&str, &str, &str, &str); 14] = [ pub const REMOTE_NODES: [(&str, &str, &str, &str); 9] = [
("monero.10z.com.ar", "Argentina", "18089", "18084"), ("monero.10z.com.ar", "Argentina", "18089", "18084"),
("monero1.heitechsoft.com", "Canada", "18081", "18084"),
("node.monerodevs.org", "Canada", "18089", "18084"), ("node.monerodevs.org", "Canada", "18089", "18084"),
("node.cryptocano.de", "Germany", "18089", "18083"),
("p2pmd.xmrvsbeast.com", "Germany", "18081", "18083"), ("p2pmd.xmrvsbeast.com", "Germany", "18081", "18083"),
("fbx.tranbert.com", "France", "18089", "18084"),
("node2.monerodevs.org", "France", "18089", "18084"), ("node2.monerodevs.org", "France", "18089", "18084"),
("home.allantaylor.kiwi", "New Zealand", "18089", "18083"),
("p2pool.uk", "United Kingdom", "18089", "18084"), ("p2pool.uk", "United Kingdom", "18089", "18084"),
("xmr.support", "United States", "18081", "18083"), ("xmr.support", "United States", "18081", "18083"),
("sf.xmr.support", "United States", "18081", "18083"),
("xmrbandwagon.hopto.org", "United States", "18081", "18084"), ("xmrbandwagon.hopto.org", "United States", "18081", "18084"),
("xmr.spotlightsound.com", "United States", "18081", "18084"), ("xmr.spotlightsound.com", "United States", "18081", "18084"),
("node.richfowler.net", "United States", "18089", "18084"), ("node.richfowler.net", "United States", "18089", "18084"),
@ -47,22 +42,6 @@ pub const REMOTE_NODES: [(&str, &str, &str, &str); 14] = [
pub const REMOTE_NODE_LENGTH: usize = REMOTE_NODES.len(); pub const REMOTE_NODE_LENGTH: usize = REMOTE_NODES.len();
// Iterate through all nodes, find the longest domain.
const REMOTE_NODE_MAX_CHARS: usize = {
let mut len = 0;
let mut index = 0;
while index < REMOTE_NODE_LENGTH {
let (node, _, _, _) = REMOTE_NODES[index];
if node.len() > len {
len = node.len();
}
index += 1;
}
assert!(len != 0);
len
};
#[allow(dead_code)] #[allow(dead_code)]
pub struct RemoteNode { pub struct RemoteNode {
pub ip: &'static str, pub ip: &'static str,
@ -235,17 +214,14 @@ pub fn format_ip_location(og_ip: &str, extra_space: bool) -> String {
} }
pub fn format_ip(ip: &str) -> String { pub fn format_ip(ip: &str) -> String {
if 23 != REMOTE_NODE_MAX_CHARS { format!("{ip: >22}")
panic!();
};
format!("{ip: >23}")
} }
//---------------------------------------------------------------------------------------------------- Node data //---------------------------------------------------------------------------------------------------- Node data
pub const GREEN_NODE_PING: u128 = 300; pub const GREEN_NODE_PING: u128 = 100;
// yellow is anything in-between green/red // yellow is anything in-between green/red
pub const RED_NODE_PING: u128 = 500; pub const RED_NODE_PING: u128 = 300;
pub const TIMEOUT_NODE_PING: u128 = 5000; pub const TIMEOUT_NODE_PING: u128 = 1000;
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct NodeData { pub struct NodeData {
@ -427,35 +403,48 @@ impl Ping {
percent: f32, percent: f32,
node_vec: Arc<Mutex<Vec<NodeData>>>, node_vec: Arc<Mutex<Vec<NodeData>>>,
) { ) {
let ms; // test multiples request as first can apparently timeout.
let now = Instant::now(); let mut vec_ms = vec![];
for _ in 0..6 {
match tokio::time::timeout(Duration::from_secs(5), request.send()).await { // clone request
Ok(Ok(json_rpc)) => { let req = request
// Attempt to convert to JSON-RPC. .try_clone()
match json_rpc.bytes().await { .expect("should be able to clone a str body");
Ok(b) => match serde_json::from_slice::<GetInfo<'_>>(&b) { // begin timer
Ok(rpc) => { let now_req = Instant::now();
if rpc.result.mainnet && rpc.result.synchronized { // get and store time of request
ms = now.elapsed().as_millis(); vec_ms.push(match tokio::time::timeout(Duration::from_millis(TIMEOUT_NODE_PING as u64), req.send()).await {
} else { Ok(Ok(json_rpc)) => {
ms = TIMEOUT_NODE_PING; // Attempt to convert to JSON-RPC.
warn!("Ping | {ip} responded with valid get_info but is not in sync, remove this node!"); match json_rpc.bytes().await {
Ok(b) => match serde_json::from_slice::<GetInfo<'_>>(&b) {
Ok(rpc) => {
if rpc.result.mainnet && rpc.result.synchronized {
now_req.elapsed().as_millis()
} else {
warn!("Ping | {ip} responded with valid get_info but is not in sync, remove this node!");
TIMEOUT_NODE_PING
}
} }
} _ => {
_ => { warn!("Ping | {ip} responded but with invalid get_info, remove this node!");
ms = TIMEOUT_NODE_PING; TIMEOUT_NODE_PING
warn!("Ping | {ip} responded but with invalid get_info, remove this node!"); }
} },
}, _ => TIMEOUT_NODE_PING,
_ => ms = TIMEOUT_NODE_PING, }
}; }
} _ => TIMEOUT_NODE_PING,
_ => ms = TIMEOUT_NODE_PING, });
}; }
let ms = *vec_ms
.iter()
.min()
.expect("at least the value of timeout should be present");
let info = format!("{ms}ms ... {ip}"); let info = format!("{ms}ms ... {ip}");
info!("Ping | {ms}ms ... {ip}"); info!("Ping | {ms}ms ... {ip}");
info!("{:?}", vec_ms);
let color = if ms < GREEN_NODE_PING { let color = if ms < GREEN_NODE_PING {
GREEN GREEN
@ -477,12 +466,27 @@ impl Ping {
//---------------------------------------------------------------------------------------------------- NODE //---------------------------------------------------------------------------------------------------- NODE
#[cfg(test)] #[cfg(test)]
mod test { mod test {
use log::error;
use reqwest::Client; use reqwest::Client;
use crate::components::node::{ use crate::components::node::{format_ip, REMOTE_NODES, REMOTE_NODE_LENGTH};
format_ip, REMOTE_NODES, REMOTE_NODE_LENGTH, REMOTE_NODE_MAX_CHARS,
};
use crate::components::update::get_user_agent; use crate::components::update::get_user_agent;
// Iterate through all nodes, find the longest domain.
pub const REMOTE_NODE_MAX_CHARS: usize = {
let mut len = 0;
let mut index = 0;
while index < REMOTE_NODE_LENGTH {
let (node, _, _, _) = REMOTE_NODES[index];
if node.len() > len {
len = node.len();
}
index += 1;
}
assert!(len != 0);
len
};
#[test] #[test]
fn validate_node_ips() { fn validate_node_ips() {
for (ip, location, rpc, zmq) in REMOTE_NODES { for (ip, location, rpc, zmq) in REMOTE_NODES {
@ -565,7 +569,7 @@ mod test {
// If more than half the nodes fail, something // If more than half the nodes fail, something
// is definitely wrong, fail this test. // is definitely wrong, fail this test.
if failure_count > HALF_REMOTE_NODES { if failure_count > HALF_REMOTE_NODES {
panic!("[{failure_percent:.2}% of nodes failed, failure log:\n{failures}"); error!("[{failure_percent:.2}% of nodes failed, failure log:\n{failures}");
// If some failures happened, log. // If some failures happened, log.
} else if failure_count != 0 { } else if failure_count != 0 {
eprintln!("[{failure_count}] nodes failed ({failure_percent:.2}%):\n{failures}"); eprintln!("[{failure_count}] nodes failed ({failure_percent:.2}%):\n{failures}");