Add balance and is_live fields to ChannelDetails 2019-06-channeldetails-fields
authorMatt Corallo <git@bluematt.me>
Sat, 1 Jun 2019 16:11:27 +0000 (12:11 -0400)
committerMatt Corallo <git@bluematt.me>
Thu, 18 Jul 2019 22:02:31 +0000 (18:02 -0400)
fuzz/fuzz_targets/router_target.rs
src/ln/channel.rs
src/ln/channelmanager.rs
src/ln/router.rs

index 70164985bdbe71d71479aa1d255065cb26344c21..2dcad55a1aaf84bec173a24956de94d34110f3f8 100644 (file)
@@ -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[..])
index 698cb419daf62d4647466ef0f54f632a405ec2b3..14ef0c5152f38132e4f8d4bc0f78ab16b9d77a7f 100644 (file)
@@ -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"));
index 3ffd080e9158f63625af30a1dcad3dda363154f7..24947cbe5568a0d550734dcd26708b2d8d385c18 100644 (file)
@@ -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<ChannelDetails> {
                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,
                                });
                        }
                }
index dc58f6d20ec374f3476ffa2ab404e1b339225a65..bb20c31c35af9f868ee76c91933558b173130dc4 100644 (file)
@@ -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);