Skip to content

Commit 8419d13

Browse files
committed
Add list_channels_by_counterparty method
While we already provide a `list_channels` method, it could result in quite a large `Vec<ChannelDetails>`. Here, we provide the means to query our channels by `counterparty_node_id` and DRY up the code.
1 parent d355ce1 commit 8419d13

File tree

1 file changed

+76
-48
lines changed

1 file changed

+76
-48
lines changed

lightning/src/ln/channelmanager.rs

+76-48
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ use crate::ln::msgs::{ChannelMessageHandler, DecodeError, LightningError, MAX_VA
5353
use crate::ln::outbound_payment;
5454
use crate::ln::outbound_payment::{OutboundPayments, PaymentAttempts, PendingOutboundPayment};
5555
use crate::ln::wire::Encode;
56-
use crate::chain::keysinterface::{EntropySource, KeysManager, NodeSigner, Recipient, SignerProvider, ChannelSigner};
56+
use crate::chain::keysinterface::{EntropySource, KeysManager, NodeSigner, Recipient, SignerProvider, ChannelSigner, WriteableEcdsaChannelSigner};
5757
use crate::util::config::{UserConfig, ChannelConfig};
5858
use crate::util::events::{Event, EventHandler, EventsProvider, MessageSendEvent, MessageSendEventsProvider, ClosureReason, HTLCDestination};
5959
use crate::util::events;
@@ -1229,6 +1229,55 @@ impl ChannelDetails {
12291229
pub fn get_outbound_payment_scid(&self) -> Option<u64> {
12301230
self.short_channel_id.or(self.outbound_scid_alias)
12311231
}
1232+
1233+
fn from_channel<Signer: WriteableEcdsaChannelSigner>(channel: &Channel<Signer>,
1234+
best_block_height: u32, latest_features: InitFeatures) -> Self {
1235+
1236+
let balance = channel.get_available_balances();
1237+
let (to_remote_reserve_satoshis, to_self_reserve_satoshis) =
1238+
channel.get_holder_counterparty_selected_channel_reserve_satoshis();
1239+
ChannelDetails {
1240+
channel_id: channel.channel_id(),
1241+
counterparty: ChannelCounterparty {
1242+
node_id: channel.get_counterparty_node_id(),
1243+
features: latest_features,
1244+
unspendable_punishment_reserve: to_remote_reserve_satoshis,
1245+
forwarding_info: channel.counterparty_forwarding_info(),
1246+
// Ensures that we have actually received the `htlc_minimum_msat` value
1247+
// from the counterparty through the `OpenChannel` or `AcceptChannel`
1248+
// message (as they are always the first message from the counterparty).
1249+
// Else `Channel::get_counterparty_htlc_minimum_msat` could return the
1250+
// default `0` value set by `Channel::new_outbound`.
1251+
outbound_htlc_minimum_msat: if channel.have_received_message() {
1252+
Some(channel.get_counterparty_htlc_minimum_msat()) } else { None },
1253+
outbound_htlc_maximum_msat: channel.get_counterparty_htlc_maximum_msat(),
1254+
},
1255+
funding_txo: channel.get_funding_txo(),
1256+
// Note that accept_channel (or open_channel) is always the first message, so
1257+
// `have_received_message` indicates that type negotiation has completed.
1258+
channel_type: if channel.have_received_message() { Some(channel.get_channel_type().clone()) } else { None },
1259+
short_channel_id: channel.get_short_channel_id(),
1260+
outbound_scid_alias: if channel.is_usable() { Some(channel.outbound_scid_alias()) } else { None },
1261+
inbound_scid_alias: channel.latest_inbound_scid_alias(),
1262+
channel_value_satoshis: channel.get_value_satoshis(),
1263+
unspendable_punishment_reserve: to_self_reserve_satoshis,
1264+
balance_msat: balance.balance_msat,
1265+
inbound_capacity_msat: balance.inbound_capacity_msat,
1266+
outbound_capacity_msat: balance.outbound_capacity_msat,
1267+
next_outbound_htlc_limit_msat: balance.next_outbound_htlc_limit_msat,
1268+
user_channel_id: channel.get_user_id(),
1269+
confirmations_required: channel.minimum_depth(),
1270+
confirmations: Some(channel.get_funding_tx_confirmations(best_block_height)),
1271+
force_close_spend_delay: channel.get_counterparty_selected_contest_delay(),
1272+
is_outbound: channel.is_outbound(),
1273+
is_channel_ready: channel.is_usable(),
1274+
is_usable: channel.is_live(),
1275+
is_public: channel.should_announce(),
1276+
inbound_htlc_minimum_msat: Some(channel.get_holder_htlc_minimum_msat()),
1277+
inbound_htlc_maximum_msat: channel.get_holder_htlc_maximum_msat(),
1278+
config: Some(channel.config()),
1279+
}
1280+
}
12321281
}
12331282

12341283
/// Used by [`ChannelManager::list_recent_payments`] to express the status of recent payments.
@@ -1716,51 +1765,10 @@ where
17161765
for (_cp_id, peer_state_mutex) in per_peer_state.iter() {
17171766
let mut peer_state_lock = peer_state_mutex.lock().unwrap();
17181767
let peer_state = &mut *peer_state_lock;
1719-
for (channel_id, channel) in peer_state.channel_by_id.iter().filter(f) {
1720-
let balance = channel.get_available_balances();
1721-
let (to_remote_reserve_satoshis, to_self_reserve_satoshis) =
1722-
channel.get_holder_counterparty_selected_channel_reserve_satoshis();
1723-
res.push(ChannelDetails {
1724-
channel_id: (*channel_id).clone(),
1725-
counterparty: ChannelCounterparty {
1726-
node_id: channel.get_counterparty_node_id(),
1727-
features: peer_state.latest_features.clone(),
1728-
unspendable_punishment_reserve: to_remote_reserve_satoshis,
1729-
forwarding_info: channel.counterparty_forwarding_info(),
1730-
// Ensures that we have actually received the `htlc_minimum_msat` value
1731-
// from the counterparty through the `OpenChannel` or `AcceptChannel`
1732-
// message (as they are always the first message from the counterparty).
1733-
// Else `Channel::get_counterparty_htlc_minimum_msat` could return the
1734-
// default `0` value set by `Channel::new_outbound`.
1735-
outbound_htlc_minimum_msat: if channel.have_received_message() {
1736-
Some(channel.get_counterparty_htlc_minimum_msat()) } else { None },
1737-
outbound_htlc_maximum_msat: channel.get_counterparty_htlc_maximum_msat(),
1738-
},
1739-
funding_txo: channel.get_funding_txo(),
1740-
// Note that accept_channel (or open_channel) is always the first message, so
1741-
// `have_received_message` indicates that type negotiation has completed.
1742-
channel_type: if channel.have_received_message() { Some(channel.get_channel_type().clone()) } else { None },
1743-
short_channel_id: channel.get_short_channel_id(),
1744-
outbound_scid_alias: if channel.is_usable() { Some(channel.outbound_scid_alias()) } else { None },
1745-
inbound_scid_alias: channel.latest_inbound_scid_alias(),
1746-
channel_value_satoshis: channel.get_value_satoshis(),
1747-
unspendable_punishment_reserve: to_self_reserve_satoshis,
1748-
balance_msat: balance.balance_msat,
1749-
inbound_capacity_msat: balance.inbound_capacity_msat,
1750-
outbound_capacity_msat: balance.outbound_capacity_msat,
1751-
next_outbound_htlc_limit_msat: balance.next_outbound_htlc_limit_msat,
1752-
user_channel_id: channel.get_user_id(),
1753-
confirmations_required: channel.minimum_depth(),
1754-
confirmations: Some(channel.get_funding_tx_confirmations(best_block_height)),
1755-
force_close_spend_delay: channel.get_counterparty_selected_contest_delay(),
1756-
is_outbound: channel.is_outbound(),
1757-
is_channel_ready: channel.is_usable(),
1758-
is_usable: channel.is_live(),
1759-
is_public: channel.should_announce(),
1760-
inbound_htlc_minimum_msat: Some(channel.get_holder_htlc_minimum_msat()),
1761-
inbound_htlc_maximum_msat: channel.get_holder_htlc_maximum_msat(),
1762-
config: Some(channel.config()),
1763-
});
1768+
for (_channel_id, channel) in peer_state.channel_by_id.iter().filter(f) {
1769+
let details = ChannelDetails::from_channel(channel, best_block_height,
1770+
peer_state.latest_features.clone());
1771+
res.push(details);
17641772
}
17651773
}
17661774
}
@@ -1786,6 +1794,24 @@ where
17861794
self.list_channels_with_filter(|&(_, ref channel)| channel.is_live())
17871795
}
17881796

1797+
/// Gets the list of channels we have with a given counterparty, in random order.
1798+
pub fn list_channels_with_counterparty(&self, counterparty_node_id: &PublicKey) -> Vec<ChannelDetails> {
1799+
let best_block_height = self.best_block.read().unwrap().height();
1800+
let per_peer_state = self.per_peer_state.read().unwrap();
1801+
1802+
if let Some(peer_state_mutex) = per_peer_state.get(counterparty_node_id) {
1803+
let mut peer_state_lock = peer_state_mutex.lock().unwrap();
1804+
let peer_state = &mut *peer_state_lock;
1805+
let features = &peer_state.latest_features;
1806+
return peer_state.channel_by_id
1807+
.iter()
1808+
.map(|(_, channel)|
1809+
ChannelDetails::from_channel(channel, best_block_height, features.clone()))
1810+
.collect();
1811+
}
1812+
vec![]
1813+
}
1814+
17891815
/// Returns in an undefined order recent payments that -- if not fulfilled -- have yet to find a
17901816
/// successful path, or have unresolved HTLCs.
17911817
///
@@ -7854,8 +7880,10 @@ mod tests {
78547880
// to connect messages with new values
78557881
chan.0.contents.fee_base_msat *= 2;
78567882
chan.1.contents.fee_base_msat *= 2;
7857-
let node_a_chan_info = nodes[0].node.list_channels()[0].clone();
7858-
let node_b_chan_info = nodes[1].node.list_channels()[0].clone();
7883+
let node_a_chan_info = nodes[0].node.list_channels_with_counterparty(
7884+
&nodes[1].node.get_our_node_id()).pop().unwrap();
7885+
let node_b_chan_info = nodes[1].node.list_channels_with_counterparty(
7886+
&nodes[0].node.get_our_node_id()).pop().unwrap();
78597887

78607888
// The first two nodes (which opened a channel) should now require fresh persistence
78617889
assert!(nodes[0].node.await_persistable_update_timeout(Duration::from_millis(1)));

0 commit comments

Comments
 (0)