From: Matt Corallo Date: Sat, 1 Jun 2019 16:11:27 +0000 (-0400) Subject: Add balance and is_live fields to ChannelDetails X-Git-Tag: v0.0.12~207^2 X-Git-Url: http://git.bitcoin.ninja/index.cgi?a=commitdiff_plain;h=3d55d71fda509935dc830f49f523a516bb048a88;hp=-c;p=rust-lightning Add balance and is_live fields to ChannelDetails --- 3d55d71fda509935dc830f49f523a516bb048a88 diff --git a/fuzz/fuzz_targets/router_target.rs b/fuzz/fuzz_targets/router_target.rs index 70164985..2dcad55a 100644 --- a/fuzz/fuzz_targets/router_target.rs +++ b/fuzz/fuzz_targets/router_target.rs @@ -205,6 +205,9 @@ pub fn do_test(data: &[u8]) { remote_network_id: get_pubkey!(), channel_value_satoshis: slice_to_be64(get_slice!(8)), user_id: 0, + inbound_capacity_msat: 0, + is_live: true, + outbound_capacity_msat: 0, }); } Some(&first_hops_vec[..]) diff --git a/src/ln/channel.rs b/src/ln/channel.rs index 698cb419..14ef0c51 100644 --- a/src/ln/channel.rs +++ b/src/ln/channel.rs @@ -1583,6 +1583,16 @@ impl Channel { (htlc_outbound_count as u32, htlc_outbound_value_msat) } + /// Get the available (ie not including pending HTLCs) inbound and outbound balance in msat. + /// Doesn't bother handling the + /// if-we-removed-it-already-but-haven't-fully-resolved-they-can-still-send-an-inbound-HTLC + /// corner case properly. + pub fn get_inbound_outbound_available_balance_msat(&self) -> (u64, u64) { + // Note that we have to handle overflow due to the above case. + (cmp::min(self.channel_value_satoshis as i64 * 1000 - self.value_to_self_msat as i64 - self.get_inbound_pending_htlc_stats().1 as i64, 0) as u64, + cmp::min(self.value_to_self_msat as i64 - self.get_outbound_pending_htlc_stats().1 as i64, 0) as u64) + } + pub fn update_add_htlc(&mut self, msg: &msgs::UpdateAddHTLC, pending_forward_state: PendingHTLCStatus) -> Result<(), ChannelError> { if (self.channel_state & (ChannelState::ChannelFunded as u32 | ChannelState::RemoteShutdownSent as u32)) != (ChannelState::ChannelFunded as u32) { return Err(ChannelError::Close("Got add HTLC message when channel was not in an operational state")); diff --git a/src/ln/channelmanager.rs b/src/ln/channelmanager.rs index 3ffd080e..24947cbe 100644 --- a/src/ln/channelmanager.rs +++ b/src/ln/channelmanager.rs @@ -391,6 +391,20 @@ pub struct ChannelDetails { pub channel_value_satoshis: u64, /// The user_id passed in to create_channel, or 0 if the channel was inbound. pub user_id: u64, + /// The available outbound capacity for sending HTLCs to the remote peer. This does not include + /// any pending HTLCs which are not yet fully resolved (and, thus, who's balance is not + /// available for inclusion in new outbound HTLCs). This further does not include any pending + /// outgoing HTLCs which are awaiting some other resolution to be sent. + pub outbound_capacity_msat: u64, + /// The available inbound capacity for the remote peer to send HTLCs to us. This does not + /// include any pending HTLCs which are not yet fully resolved (and, thus, who's balance is not + /// available for inclusion in new inbound HTLCs). + /// Note that there are some corner cases not fully handled here, so the actual available + /// inbound capacity may be slightly higher than this. + pub inbound_capacity_msat: u64, + /// True if the channel is (a) confirmed and funding_locked messages have been exchanged, (b) + /// the peer is connected, and (c) no monitor update failure is pending resolution. + pub is_live: bool, } macro_rules! handle_error { @@ -613,12 +627,16 @@ impl ChannelManager { let channel_state = self.channel_state.lock().unwrap(); let mut res = Vec::with_capacity(channel_state.by_id.len()); for (channel_id, channel) in channel_state.by_id.iter() { + let (inbound_capacity_msat, outbound_capacity_msat) = channel.get_inbound_outbound_available_balance_msat(); res.push(ChannelDetails { channel_id: (*channel_id).clone(), short_channel_id: channel.get_short_channel_id(), remote_network_id: channel.get_their_node_id(), channel_value_satoshis: channel.get_value_satoshis(), + inbound_capacity_msat, + outbound_capacity_msat, user_id: channel.get_user_id(), + is_live: channel.is_live(), }); } res @@ -626,6 +644,9 @@ impl ChannelManager { /// Gets the list of usable channels, in random order. Useful as an argument to /// Router::get_route to ensure non-announced channels are used. + /// + /// These are guaranteed to have their is_live value set to true, see the documentation for + /// ChannelDetails::is_live for more info on exactly what the criteria are. pub fn list_usable_channels(&self) -> Vec { let channel_state = self.channel_state.lock().unwrap(); let mut res = Vec::with_capacity(channel_state.by_id.len()); @@ -634,12 +655,16 @@ impl ChannelManager { // internal/external nomenclature, but that's ok cause that's probably what the user // really wanted anyway. if channel.is_live() { + let (inbound_capacity_msat, outbound_capacity_msat) = channel.get_inbound_outbound_available_balance_msat(); res.push(ChannelDetails { channel_id: (*channel_id).clone(), short_channel_id: channel.get_short_channel_id(), remote_network_id: channel.get_their_node_id(), channel_value_satoshis: channel.get_value_satoshis(), + inbound_capacity_msat, + outbound_capacity_msat, user_id: channel.get_user_id(), + is_live: true, }); } } diff --git a/src/ln/router.rs b/src/ln/router.rs index dc58f6d2..bb20c31c 100644 --- a/src/ln/router.rs +++ b/src/ln/router.rs @@ -1468,6 +1468,9 @@ mod tests { remote_network_id: node8.clone(), channel_value_satoshis: 0, user_id: 0, + outbound_capacity_msat: 0, + inbound_capacity_msat: 0, + is_live: true, }]; let route = router.get_route(&node3, Some(&our_chans), &Vec::new(), 100, 42).unwrap(); assert_eq!(route.hops.len(), 2); @@ -1543,6 +1546,9 @@ mod tests { remote_network_id: node4.clone(), channel_value_satoshis: 0, user_id: 0, + outbound_capacity_msat: 0, + inbound_capacity_msat: 0, + is_live: true, }]; let route = router.get_route(&node7, Some(&our_chans), &last_hops, 100, 42).unwrap(); assert_eq!(route.hops.len(), 2);