From d1c0d1ca0439ce6c81d321202f81b1ad60ced639 Mon Sep 17 00:00:00 2001 From: Joerg Date: Thu, 28 May 2026 20:40:36 +0200 Subject: [PATCH 1/5] debug, panic windows --- src/bin/grin.rs | 4 +-- src/bin/grin.yml | 4 +++ src/bin/tools/seedcheck.rs | 62 +++++++++++++++++++++++++++++++------- 3 files changed, 57 insertions(+), 13 deletions(-) diff --git a/src/bin/grin.rs b/src/bin/grin.rs index 168e5e6e33..65d81cc161 100644 --- a/src/bin/grin.rs +++ b/src/bin/grin.rs @@ -226,8 +226,8 @@ fn real_main() -> i32 { // seedcheck command ("seedcheck", Some(seedcheck_args)) => { - let is_testnet = seedcheck_args.is_present("testnet"); - let results = check_seeds(is_testnet); + let is_testnet = args.is_present("testnet") || seedcheck_args.is_present("testnet"); + let results = check_seeds(is_testnet, seedcheck_args.value_of("seed")); let output = serde_json::to_string_pretty(&results).expect("Unable to serialize results"); diff --git a/src/bin/grin.yml b/src/bin/grin.yml index 1390e1c6ec..018983f210 100644 --- a/src/bin/grin.yml +++ b/src/bin/grin.yml @@ -107,3 +107,7 @@ subcommands: help: Output file to write the results to long: output takes_value: true + - seed: + help: DNS seed hostname to check instead of the default seed list + long: seed + takes_value: true diff --git a/src/bin/tools/seedcheck.rs b/src/bin/tools/seedcheck.rs index 2ffff88b52..1e5d3a8174 100644 --- a/src/bin/tools/seedcheck.rs +++ b/src/bin/tools/seedcheck.rs @@ -21,7 +21,8 @@ use grin_core::{genesis, global}; use grin_p2p as p2p; use grin_servers::{resolve_dns_to_addrs, MAINNET_DNS_SEEDS, TESTNET_DNS_SEEDS}; use std::fs; -use std::net::{SocketAddr, TcpStream}; +use std::net::TcpStream; +use std::path::PathBuf; use std::time::Duration; use thiserror::Error; @@ -88,46 +89,71 @@ pub struct SeedCheckConnectAttempt { pub handshake_success: bool, pub user_agent: Option, pub capabilities: Option, + pub error: Option, } -pub fn check_seeds(is_testnet: bool) -> Vec { +pub fn check_seeds(is_testnet: bool, seed: Option<&str>) -> Vec { let mut result = vec![]; let (default_seeds, port) = match is_testnet { true => (TESTNET_DNS_SEEDS, "13414"), false => (MAINNET_DNS_SEEDS, "3414"), }; + let seeds = match seed { + Some(seed) => vec![seed], + None => default_seeds.to_vec(), + }; if is_testnet { global::set_local_chain_type(global::ChainTypes::Testnet); } + eprintln!( + "Running seedcheck for {} on port {}", + if is_testnet { "testnet" } else { "mainnet" }, + port + ); + let config = p2p::types::P2PConfig::default(); let adapter = Arc::new(p2p::DummyAdapter {}); + let tmp_root = PathBuf::from(format!(".__grintmp__/seedcheck-{}", std::process::id())); + let peer_store_root = tmp_root.join("peer_store_root"); let peers = Arc::new(p2p::Peers::new( - p2p::store::PeerStore::new(".__grintmp__/peer_store_root").unwrap(), + p2p::store::PeerStore::new(peer_store_root.to_str().unwrap()).unwrap(), adapter, config.clone(), )); - for s in default_seeds.iter() { + for s in seeds.iter() { info!("Checking seed health for {}", s); + eprintln!("Checking seed {}", s); let mut seed_result = SeedCheckResult::default(); seed_result.url = s.to_string(); let resolved_dns_entries = resolve_dns_to_addrs(&vec![format!("{}:{}", s, port)]); if resolved_dns_entries.is_empty() { info!("FAIL - No dns entries found for {}", s); + eprintln!(" FAIL dns: no records found"); result.push(seed_result); continue; } seed_result.dns_resolutions_found = true; + eprintln!(" DNS records: {}", resolved_dns_entries.len()); // Check backwards, last contains the latest (at least on my machine!) for r in resolved_dns_entries.iter().rev() { + eprintln!(" Trying {}", r); let res = check_seed_health(*r, is_testnet, &peers); if let Ok(p) = res { + let user_agent = p.info.user_agent.clone(); + let capabilities = format!("{:?}", p.info.capabilities); info!( "SUCCESS - Performed Handshake with seed for {} at {}. {} - {:?}", - s, r, p.info.user_agent, p.info.capabilities + s, r, user_agent, p.info.capabilities + ); + eprintln!( + " OK handshake: {} - {:?}", + user_agent, p.info.capabilities ); + p.stop(); + p.wait(); //info!("{:?}", p); seed_result.success = true; seed_result @@ -135,10 +161,12 @@ pub fn check_seeds(is_testnet: bool) -> Vec { .push(SeedCheckConnectAttempt { ip_addr: r.to_string(), handshake_success: true, - user_agent: Some(p.info.user_agent), - capabilities: Some(format!("{:?}", p.info.capabilities)), + user_agent: Some(user_agent), + capabilities: Some(capabilities), + error: None, }); - } else { + } else if let Err(e) = res { + eprintln!(" FAIL handshake: {}", e); seed_result .unsuccessful_attempts .push(SeedCheckConnectAttempt { @@ -146,6 +174,7 @@ pub fn check_seeds(is_testnet: bool) -> Vec { handshake_success: false, user_agent: None, capabilities: None, + error: Some(e.to_string()), }); } } @@ -155,13 +184,22 @@ pub fn check_seeds(is_testnet: bool) -> Vec { "FAIL - Unable to handshake at any known DNS resolutions for {}", s ); + eprintln!(" FAIL seed: no successful handshakes"); } result.push(seed_result); } + drop(peers); + // Clean up temporary files - fs::remove_dir_all(".__grintmp__").expect("Unable to delete temporary files"); + if let Err(e) = fs::remove_dir_all(tmp_root) { + debug!("Unable to delete temporary seedcheck files: {:?}", e); + eprintln!( + "WARN cleanup: unable to delete temporary seedcheck files: {:?}", + e + ); + } result } @@ -177,19 +215,21 @@ fn check_seed_health( true => genesis::genesis_test().hash(), false => genesis::genesis_main().hash(), }; + eprintln!(" Using genesis hash {}", genesis_hash); let handshake = p2p::handshake::Handshake::new(genesis_hash, config.clone()); match TcpStream::connect_timeout(&addr.0, Duration::from_secs(5)) { Ok(stream) => { - let addr = SocketAddr::new(config.host, config.port); + let self_addr = p2p::PeerAddr::from_ip(config.host); + eprintln!(" Advertising self addr {}", self_addr); let total_diff = Difficulty::from_num(1); let peer = p2p::Peer::connect( stream, capabilities, total_diff, - p2p::PeerAddr(addr), + self_addr, &handshake, peers.clone(), )?; From d202f8e21c0592500b11c2fdaf4e52e34f6695a4 Mon Sep 17 00:00:00 2001 From: Joerg Date: Mon, 15 Jun 2026 09:07:18 +0200 Subject: [PATCH 2/5] rm dbg --- src/bin/tools/seedcheck.rs | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/src/bin/tools/seedcheck.rs b/src/bin/tools/seedcheck.rs index 1e5d3a8174..2f1c650519 100644 --- a/src/bin/tools/seedcheck.rs +++ b/src/bin/tools/seedcheck.rs @@ -131,15 +131,12 @@ pub fn check_seeds(is_testnet: bool, seed: Option<&str>) -> Vec let resolved_dns_entries = resolve_dns_to_addrs(&vec![format!("{}:{}", s, port)]); if resolved_dns_entries.is_empty() { info!("FAIL - No dns entries found for {}", s); - eprintln!(" FAIL dns: no records found"); result.push(seed_result); continue; } seed_result.dns_resolutions_found = true; - eprintln!(" DNS records: {}", resolved_dns_entries.len()); // Check backwards, last contains the latest (at least on my machine!) for r in resolved_dns_entries.iter().rev() { - eprintln!(" Trying {}", r); let res = check_seed_health(*r, is_testnet, &peers); if let Ok(p) = res { let user_agent = p.info.user_agent.clone(); @@ -148,10 +145,6 @@ pub fn check_seeds(is_testnet: bool, seed: Option<&str>) -> Vec "SUCCESS - Performed Handshake with seed for {} at {}. {} - {:?}", s, r, user_agent, p.info.capabilities ); - eprintln!( - " OK handshake: {} - {:?}", - user_agent, p.info.capabilities - ); p.stop(); p.wait(); //info!("{:?}", p); @@ -166,7 +159,6 @@ pub fn check_seeds(is_testnet: bool, seed: Option<&str>) -> Vec error: None, }); } else if let Err(e) = res { - eprintln!(" FAIL handshake: {}", e); seed_result .unsuccessful_attempts .push(SeedCheckConnectAttempt { @@ -184,7 +176,6 @@ pub fn check_seeds(is_testnet: bool, seed: Option<&str>) -> Vec "FAIL - Unable to handshake at any known DNS resolutions for {}", s ); - eprintln!(" FAIL seed: no successful handshakes"); } result.push(seed_result); @@ -215,14 +206,12 @@ fn check_seed_health( true => genesis::genesis_test().hash(), false => genesis::genesis_main().hash(), }; - eprintln!(" Using genesis hash {}", genesis_hash); let handshake = p2p::handshake::Handshake::new(genesis_hash, config.clone()); match TcpStream::connect_timeout(&addr.0, Duration::from_secs(5)) { Ok(stream) => { let self_addr = p2p::PeerAddr::from_ip(config.host); - eprintln!(" Advertising self addr {}", self_addr); let total_diff = Difficulty::from_num(1); let peer = p2p::Peer::connect( From 07b383eb1abf76fb901568d9097e6451fd96bf02 Mon Sep 17 00:00:00 2001 From: Joerg Date: Mon, 15 Jun 2026 10:38:36 +0200 Subject: [PATCH 3/5] cleanup seedcheck output and temp path handling --- src/bin/tools/seedcheck.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/bin/tools/seedcheck.rs b/src/bin/tools/seedcheck.rs index 2f1c650519..a85ef621f2 100644 --- a/src/bin/tools/seedcheck.rs +++ b/src/bin/tools/seedcheck.rs @@ -115,10 +115,11 @@ pub fn check_seeds(is_testnet: bool, seed: Option<&str>) -> Vec let config = p2p::types::P2PConfig::default(); let adapter = Arc::new(p2p::DummyAdapter {}); - let tmp_root = PathBuf::from(format!(".__grintmp__/seedcheck-{}", std::process::id())); + let tmp_root = format!(".__grintmp__/seedcheck-{}", std::process::id()); + let tmp_root = PathBuf::from(tmp_root); let peer_store_root = tmp_root.join("peer_store_root"); let peers = Arc::new(p2p::Peers::new( - p2p::store::PeerStore::new(peer_store_root.to_str().unwrap()).unwrap(), + p2p::store::PeerStore::new(&peer_store_root.to_string_lossy()).unwrap(), adapter, config.clone(), )); From 0290eacaa98f432417bc9034df6a7cdd0a5e4ab5 Mon Sep 17 00:00:00 2001 From: ardocrat Date: Wed, 17 Jun 2026 19:08:52 +0300 Subject: [PATCH 4/5] fix: remove temporary directory after execution --- src/bin/tools/seedcheck.rs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/bin/tools/seedcheck.rs b/src/bin/tools/seedcheck.rs index a85ef621f2..3b0da1d748 100644 --- a/src/bin/tools/seedcheck.rs +++ b/src/bin/tools/seedcheck.rs @@ -115,9 +115,10 @@ pub fn check_seeds(is_testnet: bool, seed: Option<&str>) -> Vec let config = p2p::types::P2PConfig::default(); let adapter = Arc::new(p2p::DummyAdapter {}); - let tmp_root = format!(".__grintmp__/seedcheck-{}", std::process::id()); - let tmp_root = PathBuf::from(tmp_root); - let peer_store_root = tmp_root.join("peer_store_root"); + let tmp_root = ".__grintmp__"; + let mut data_root = PathBuf::from(tmp_root); + data_root.push(format!("seedcheck-{}", std::process::id())); + let peer_store_root = data_root.join("peer_store_root"); let peers = Arc::new(p2p::Peers::new( p2p::store::PeerStore::new(&peer_store_root.to_string_lossy()).unwrap(), adapter, From 594f1ed7fa04f0acb046ce4171db037b769f351b Mon Sep 17 00:00:00 2001 From: wiesche Date: Mon, 22 Jun 2026 08:43:20 +0200 Subject: [PATCH 5/5] fix: cleanup seedcheck temp root safely --- src/bin/tools/seedcheck.rs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/bin/tools/seedcheck.rs b/src/bin/tools/seedcheck.rs index 3b0da1d748..ac7d3ed619 100644 --- a/src/bin/tools/seedcheck.rs +++ b/src/bin/tools/seedcheck.rs @@ -185,14 +185,16 @@ pub fn check_seeds(is_testnet: bool, seed: Option<&str>) -> Vec drop(peers); - // Clean up temporary files - if let Err(e) = fs::remove_dir_all(tmp_root) { + // Clean up temporary files for this process, then remove the common root + // only if no other seedcheck process is using it. + if let Err(e) = fs::remove_dir_all(&data_root) { debug!("Unable to delete temporary seedcheck files: {:?}", e); eprintln!( "WARN cleanup: unable to delete temporary seedcheck files: {:?}", e ); } + let _ = fs::remove_dir(tmp_root); result }