diff --git a/src/lib.rs b/src/lib.rs index 630a113..fe6e28f 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -46,6 +46,12 @@ use tokio::runtime::Runtime; #[macro_use] extern crate napi_derive; +/// Polling interval for event loops and state checks. +const POLL_INTERVAL: Duration = Duration::from_millis(10); + +/// Max time to wait for channels to become usable after sync. +const CHANNEL_USABLE_TIMEOUT: Duration = Duration::from_secs(10); + static GLOBAL_LOGGER: OnceLock> = OnceLock::new(); fn logger_instance() -> &'static Arc { @@ -566,7 +572,7 @@ impl MdkNode { last_event_time = now; } - std::thread::sleep(std::time::Duration::from_millis(10)); + std::thread::sleep(POLL_INTERVAL); } if let Err(err) = self.node.stop() { @@ -753,7 +759,7 @@ impl MdkNode { return Ok(()); } - std::thread::sleep(Duration::from_millis(50)); + std::thread::sleep(POLL_INTERVAL); } } @@ -830,13 +836,8 @@ impl MdkNode { panic!("failed to sync wallets: {err}"); } - let available_balance_msat: u64 = self - .node - .list_channels() - .into_iter() - .filter(|channel| channel.is_channel_ready) - .map(|channel| channel.outbound_capacity_msat) - .sum(); + wait_for_usable_channels(&self.node); + let available_balance_msat = usable_outbound_capacity_msat(&self.node); eprintln!("[lightning-js] pay_lnurl available_balance_msat={available_balance_msat}"); if available_balance_msat == 0 { @@ -927,13 +928,9 @@ impl MdkNode { ) })?; - let available_balance_msat: u64 = self - .node - .list_channels() - .into_iter() - .filter(|channel| channel.is_channel_ready) - .map(|channel| channel.outbound_capacity_msat) - .sum(); + wait_for_usable_channels(&self.node); + let available_balance_msat = usable_outbound_capacity_msat(&self.node); + eprintln!("[lightning-js] pay_bolt11 available_balance_msat={available_balance_msat}"); if available_balance_msat == 0 { if let Err(err) = self.node.stop() { @@ -1063,20 +1060,11 @@ impl MdkNode { } eprintln!("[lightning-js] pay_bolt12_offer wallet sync complete"); - let channels = self.node.list_channels(); - let ready_channels: Vec<_> = channels - .iter() - .filter(|channel| channel.is_channel_ready) - .collect(); - let available_balance_msat: u64 = ready_channels - .iter() - .map(|channel| channel.outbound_capacity_msat) - .sum(); + wait_for_usable_channels(&self.node); + let available_balance_msat = usable_outbound_capacity_msat(&self.node); eprintln!( - "[lightning-js] pay_bolt12_offer channels: total={} ready={} available_balance_msat={}", - channels.len(), - ready_channels.len(), + "[lightning-js] pay_bolt12_offer available_balance_msat={}", available_balance_msat ); @@ -1186,6 +1174,45 @@ impl MdkNode { } } +/// Wait for all channels to become usable after node startup/sync. +fn wait_for_usable_channels(node: &Node) { + let start = Instant::now(); + + loop { + let channels = node.list_channels(); + let total = channels.len(); + let usable = channels.iter().filter(|c| c.is_usable).count(); + + if total > 0 && usable == total { + eprintln!( + "[lightning-js] All channels usable ({usable}/{total}) after {}ms", + start.elapsed().as_millis() + ); + return; + } + + if start.elapsed() >= CHANNEL_USABLE_TIMEOUT { + eprintln!( + "[lightning-js] Timeout: {usable}/{total} channels usable after {}s", + CHANNEL_USABLE_TIMEOUT.as_secs() + ); + return; + } + + std::thread::sleep(POLL_INTERVAL); + } +} + +/// Compute total outbound capacity across all usable channels. +fn usable_outbound_capacity_msat(node: &Node) -> u64 { + node + .list_channels() + .iter() + .filter(|c| c.is_usable) + .map(|c| c.outbound_capacity_msat) + .sum() +} + fn scid_from_human_readable_string(human_readable_scid: &str) -> Result { let mut parts = human_readable_scid.split('x');