Skip to content

Add balance and is_live fields to ChannelDetails #340

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions fuzz/fuzz_targets/router_target.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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[..])
Expand Down
10 changes: 10 additions & 0 deletions src/ln/channel.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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"));
Expand Down
25 changes: 25 additions & 0 deletions src/ln/channelmanager.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What's about channel_update with disable flags set ? Or if we detect channel transaction but closing hasn't get enough confs (and so channel isn't prune yet from channel graph) ?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As for (a), we handle that in Router, and I'm still pretty confused as to how a peer can send that to you and have you do anything, do we implement it yet anyway?, as for (b) I think we prune it immediately, no?

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Okay, so "liveness" is just a ChannelManager view-based and doesn't rely on what the Router may receive (like a channel_update from peer disabling this channel, which is not implemented yet because #207 is still on stand-by)

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think #207 should result in the Channel knowing if the counterparty sent us a channel_update disabling our own channel, then we could view it, but, yes.

/// the peer is connected, and (c) no monitor update failure is pending resolution.
pub is_live: bool,
}

macro_rules! handle_error {
Expand Down Expand Up @@ -613,19 +627,26 @@ 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
}

/// 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());
Expand All @@ -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,
});
}
}
Expand Down
6 changes: 6 additions & 0 deletions src/ln/router.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -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);
Expand Down