commit e8faafc931432f434d85862800286ebfd71330ea
parent a70b7f796ded9a81bfdd6e698582fcfd997f7f21
Author: Joris Hartog <jorishartog@hotmail.com>
Date: Wed, 29 Jul 2026 16:35:42 +0200
Clean up runtime logging
Diffstat:
5 files changed, 98 insertions(+), 37 deletions(-)
diff --git a/rust-toolchain.toml b/rust-toolchain.toml
@@ -0,0 +1,4 @@
+[toolchain]
+channel = "1.86.0"
+components = ["rustfmt", "clippy"]
+profile = "minimal"
diff --git a/src/adapters/p2p.rs b/src/adapters/p2p.rs
@@ -25,7 +25,7 @@ use crate::{
app::{
BlockInventory, GossipEnvelope, MEMPOOL_STATUS_LIMIT, NETWORK_ID, NodeCore,
PROTOCOL_VERSION, PeerDirection, ProtocolHello, SharedNode, SharedPeerBook,
- TransactionRejection, now_ms,
+ TransactionRejection, debug_logging_enabled, now_ms,
},
domain::{Block, ChainSnapshot, Ledger, Transaction, TransactionSubmitOutcome, verify_vdf},
};
@@ -609,7 +609,9 @@ impl GossipNetwork {
async fn forward_outbox(&self) {
let outbox = self.inner.node.lock().await.drain_outbox();
if let Err(error) = self.broadcast(outbox).await {
- eprintln!("p2p rebroadcast failed: {error:#}");
+ if debug_logging_enabled() {
+ eprintln!("p2p rebroadcast failed: {error:#}");
+ }
}
}
}
@@ -642,14 +644,17 @@ async fn accept_loop(network: GossipNetwork, listener: TcpListener) {
&network.inner.metrics.last_session_failure,
format!("{remote_addr}: {error:#}"),
);
- eprintln!(
- "p2p inbound connection from {remote_addr} failed: {error:#}"
- );
+ if debug_logging_enabled() {
+ eprintln!(
+ "p2p inbound connection from {remote_addr} failed: {error:#}"
+ );
+ }
}
}
});
}
- Err(error) => eprintln!("p2p accept failed: {error:#}"),
+ Err(error) if debug_logging_enabled() => eprintln!("p2p accept failed: {error:#}"),
+ Err(_) => {}
}
}
}
@@ -745,7 +750,9 @@ async fn outbound_session(
.lock()
.await
.record_error(&peer, message.clone());
- eprintln!("p2p session with {peer} failed: {message}");
+ if debug_logging_enabled() {
+ eprintln!("p2p session with {peer} failed: {message}");
+ }
}
}
@@ -2142,7 +2149,9 @@ async fn record_inbound_result(
.await
.record_misbehavior(&peer, message.clone());
}
- eprintln!("p2p envelope from {peer} ignored: {message}");
+ if debug_logging_enabled() {
+ eprintln!("p2p envelope from {peer} ignored: {message}");
+ }
}
}
}
diff --git a/src/adapters/stratum.rs b/src/adapters/stratum.rs
@@ -17,7 +17,7 @@ use tokio::{
use crate::{
adapters::p2p::GossipNetwork,
- app::{ExternalMineJob, SharedNode},
+ app::{ExternalMineJob, SharedNode, debug_logging_enabled},
domain::{STRATUM_EXTRANONCE1_HEX, STRATUM_EXTRANONCE2_SIZE, StratumMineShare},
};
@@ -66,13 +66,16 @@ async fn run_listener(server: StratumServer, listener: TcpListener) {
let server = server.clone();
tokio::spawn(async move {
if let Err(error) = handle_connection(server, stream).await {
- eprintln!("stratum session with {remote} failed: {error:#}");
+ if debug_logging_enabled() {
+ eprintln!("stratum session with {remote} failed: {error:#}");
+ }
}
});
}
- Err(error) => {
+ Err(error) if debug_logging_enabled() => {
eprintln!("stratum accept failed: {error:#}");
}
+ Err(_) => {}
}
}
}
diff --git a/src/app.rs b/src/app.rs
@@ -1,6 +1,9 @@
use std::{
collections::{BTreeMap, BTreeSet},
- sync::Arc,
+ sync::{
+ Arc,
+ atomic::{AtomicBool, Ordering},
+ },
time::{SystemTime, UNIX_EPOCH},
};
@@ -31,6 +34,15 @@ pub const PEER_MISBEHAVIOR_BAN_MS: u64 = 10 * 60 * 1_000;
pub const PEER_CLOCK_OFFSET_ACCEPTANCE_MS: i64 = 10 * 60 * 1_000;
const PEER_CLOCK_OFFSET_STALE_MS: u64 = 20 * 60 * 1_000;
const AUTO_POW_NONCE_ATTEMPTS_PER_TICK: u64 = 8;
+static DEBUG_LOGGING: AtomicBool = AtomicBool::new(false);
+
+pub fn set_debug_logging(enabled: bool) {
+ DEBUG_LOGGING.store(enabled, Ordering::Relaxed);
+}
+
+pub fn debug_logging_enabled() -> bool {
+ DEBUG_LOGGING.load(Ordering::Relaxed)
+}
#[derive(Clone, Debug)]
pub struct NodeConfig {
diff --git a/src/main.rs b/src/main.rs
@@ -10,7 +10,10 @@ use std::{
use anyhow::{Context, Result, bail};
use iuna::{
adapters::{chain_store::SqliteChainStore, config_store, http, p2p, stratum, wallet_store},
- app::{NodeCore, PeerBook, SharedNode, SharedPeerBook, StratumStatus, now_ms},
+ app::{
+ NodeCore, PeerBook, SharedNode, SharedPeerBook, StratumStatus, debug_logging_enabled,
+ now_ms, set_debug_logging,
+ },
domain::{
Amount, ChainSnapshot, GenesisBurn, Ledger, MICRO_IUNA, VDF_TARGET_BLOCK_MS, run_vdf,
},
@@ -29,6 +32,8 @@ async fn main() -> Result<()> {
let Some(opts) = CliOptions::parse()? else {
return Ok(());
};
+ set_debug_logging(opts.debug);
+ let debug_logging = opts.debug;
let wallet_path = opts.wallet_path();
let config_path = opts.config_path();
let wallet_file_exists = wallet_path.exists();
@@ -124,13 +129,13 @@ async fn main() -> Result<()> {
let finalizer_node = Arc::clone(&node);
let finalizer_gossip = gossip.clone();
tokio::spawn(async move {
- run_automatic_finalizer(finalizer_node, finalizer_gossip).await;
+ run_automatic_finalizer(finalizer_node, finalizer_gossip, debug_logging).await;
});
let sync_node = Arc::clone(&node);
let sync_gossip = gossip.clone();
tokio::spawn(async move {
- run_peer_sync(sync_node, sync_gossip).await;
+ run_peer_sync(sync_node, sync_gossip, debug_logging).await;
});
if !has_chain {
@@ -249,6 +254,7 @@ struct CliOptions {
join_peers: Vec<String>,
chain_mode: ChainMode,
data_dir: PathBuf,
+ debug: bool,
}
impl CliOptions {
@@ -267,6 +273,7 @@ impl CliOptions {
join_peers: Vec::new(),
chain_mode: ChainMode::Setup,
data_dir: default_data_dir(),
+ debug: false,
};
let raw_args = args.into_iter().collect::<Vec<_>>();
@@ -317,6 +324,7 @@ impl CliOptions {
opts.join_peers.push(peer);
}
"--data-dir" => opts.data_dir = PathBuf::from(next_value(&mut args, "--data-dir")?),
+ "--debug" => opts.debug = true,
"--help" | "-h" => {
print_help();
std::process::exit(0);
@@ -404,7 +412,8 @@ fn help_text() -> &'static str {
--p2p <addr:port> P2P TCP listener address (default 127.0.0.1:9444)\n\
--stratum <addr:port> Stratum V1 listener for SHA-256 ASIC miners\n\
--join <addr:port> Fetch chain snapshot from this peer before finalization\n\
- --data-dir <path> Local wallet directory (default ~/.iuna)\n\n\
+ --data-dir <path> Local wallet directory (default ~/.iuna)\n\
+ --debug Print verbose runtime logs\n\n\
Environment:\n\
IUNA_DEV_SKIP_SEED_VERIFY=1 Show a setup button to skip seed verification\n"
}
@@ -522,7 +531,7 @@ async fn join_chain_ledger(join_peers: &[String], advertised_addr: SocketAddr) -
)
}
-async fn run_automatic_finalizer(node: SharedNode, gossip: p2p::GossipNetwork) {
+async fn run_automatic_finalizer(node: SharedNode, gossip: p2p::GossipNetwork, debug: bool) {
let mut last_logged_skip: Option<(u64, String)> = None;
loop {
if !node.lock().await.has_real_chain() {
@@ -538,21 +547,25 @@ async fn run_automatic_finalizer(node: SharedNode, gossip: p2p::GossipNetwork) {
};
if let Err(error) = gossip.broadcast(outbox).await {
- eprintln!("p2p broadcast failed after automatic burn: {error:#}");
+ if debug {
+ eprintln!("p2p broadcast failed after automatic burn: {error:#}");
+ }
}
- if let Some(tx) = &plan.pow_mined {
- println!(
- "auto-pow queued mine action for height {} ({})",
- height,
- tx.signature()
- );
+ if debug {
+ if let Some(tx) = &plan.pow_mined {
+ println!(
+ "auto-pow queued mine action for height {} ({})",
+ height,
+ tx.signature()
+ );
+ }
}
let Some(work) = plan.work else {
if let Some(reason) = &plan.skipped_reason {
let skip = (height, reason.clone());
- if last_logged_skip.as_ref() != Some(&skip) {
+ if debug && last_logged_skip.as_ref() != Some(&skip) {
println!("auto-finalization skipped at height {height}: {reason}");
last_logged_skip = Some(skip);
}
@@ -562,18 +575,22 @@ async fn run_automatic_finalizer(node: SharedNode, gossip: p2p::GossipNetwork) {
};
last_logged_skip = None;
- println!(
- "leader selected locally for candidate block {}; running VDF for {} rounds",
- work.height(),
- work.vdf_rounds()
- );
+ if debug {
+ println!(
+ "leader selected locally for candidate block {}; running VDF for {} rounds",
+ work.height(),
+ work.vdf_rounds()
+ );
+ }
let seed = work.vdf_seed().to_string();
let rounds = work.vdf_rounds();
let vdf_output = match tokio::task::spawn_blocking(move || run_vdf(&seed, rounds)).await {
Ok(output) => output,
Err(error) => {
- eprintln!("VDF worker failed: {error:#}");
+ if debug {
+ eprintln!("VDF worker failed: {error:#}");
+ }
continue;
}
};
@@ -586,21 +603,25 @@ async fn run_automatic_finalizer(node: SharedNode, gossip: p2p::GossipNetwork) {
};
match finalized {
- Ok(block) => {
+ Ok(block) if debug => {
println!("auto-finalized block {} ({})", block.height, block.hash);
}
- Err(error) => println!("auto-finalization skipped after VDF: {error:#}"),
+ Ok(_) => {}
+ Err(error) if debug => println!("auto-finalization skipped after VDF: {error:#}"),
+ Err(_) => {}
}
if let Err(error) = gossip.broadcast(outbox).await {
- eprintln!("p2p broadcast failed after automatic block: {error:#}");
+ if debug {
+ eprintln!("p2p broadcast failed after automatic block: {error:#}");
+ }
}
tokio::task::yield_now().await;
}
}
-async fn run_peer_sync(node: SharedNode, gossip: p2p::GossipNetwork) {
+async fn run_peer_sync(node: SharedNode, gossip: p2p::GossipNetwork, debug: bool) {
loop {
tokio::time::sleep(std::time::Duration::from_secs(5)).await;
let envelopes = {
@@ -613,7 +634,9 @@ async fn run_peer_sync(node: SharedNode, gossip: p2p::GossipNetwork) {
let mut envelopes = envelopes;
envelopes.push(gossip.peer_exchange().await);
if let Err(error) = gossip.broadcast(envelopes).await {
- eprintln!("p2p sync gossip failed: {error:#}");
+ if debug {
+ eprintln!("p2p sync gossip failed: {error:#}");
+ }
}
}
}
@@ -646,7 +669,10 @@ async fn run_chain_persistence_with_interval(
match persist_chain_snapshot(&store, snapshot).await {
Ok(()) => last_saved_tip = Some(tip_hash),
- Err(error) => eprintln!("chain persistence failed: {error:#}"),
+ Err(error) if debug_logging_enabled() => {
+ eprintln!("chain persistence failed: {error:#}")
+ }
+ Err(_) => {}
}
}
}
@@ -688,6 +714,7 @@ mod tests {
assert!(help_text().contains("IUNA_DEV_SKIP_SEED_VERIFY=1"));
assert!(help_text().contains("skip seed verification"));
assert!(help_text().contains("--stratum <addr:port>"));
+ assert!(help_text().contains("--debug"));
}
fn ledger_with_one_spendable_iuna(wallet: &Wallet) -> Ledger {
@@ -736,6 +763,12 @@ mod tests {
}
#[test]
+ fn debug_logging_can_be_enabled() {
+ assert!(!parse(&[]).unwrap().unwrap().debug);
+ assert!(parse(&["--debug"]).unwrap().unwrap().debug);
+ }
+
+ #[test]
fn removed_wallet_seed_is_rejected() {
let error = parse(&["--wallet-seed", "alice", "--genesis"]).unwrap_err();
assert!(error.to_string().contains("--wallet-seed was removed"));