Skip to content

Commit 1b2fcd0

Browse files
committed
Add ReserveType to ChannelDetails
We expose the reserve type of each channel through a new ReserveType enum on ChannelDetails. This tells users whether a channel uses adaptive anchor reserves, has no reserve due to a trusted peer, or is a legacy pre-anchor channel. The reserve type is derived at query time in list_channels by checking the channel's type features against trusted_peers_no_reserve. Additionally, We replace the From<LdkChannelDetails> impl with an explicit from_ldk method that takes the anchor channels config.
1 parent e180d94 commit 1b2fcd0

2 files changed

Lines changed: 75 additions & 5 deletions

File tree

src/lib.rs

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -177,7 +177,9 @@ use types::{
177177
HRNResolver, KeysManager, OnionMessenger, PaymentStore, PeerManager, Router, Scorer, Sweeper,
178178
Wallet,
179179
};
180-
pub use types::{ChannelDetails, CustomTlvRecord, PeerDetails, SyncAndAsyncKVStore, UserChannelId};
180+
pub use types::{
181+
ChannelDetails, CustomTlvRecord, PeerDetails, ReserveType, SyncAndAsyncKVStore, UserChannelId,
182+
};
181183
pub use vss_client;
182184

183185
use crate::scoring::setup_background_pathfinding_scores_sync;
@@ -1081,7 +1083,11 @@ impl Node {
10811083

10821084
/// Retrieve a list of known channels.
10831085
pub fn list_channels(&self) -> Vec<ChannelDetails> {
1084-
self.channel_manager.list_channels().into_iter().map(|c| c.into()).collect()
1086+
self.channel_manager
1087+
.list_channels()
1088+
.into_iter()
1089+
.map(|c| ChannelDetails::from_ldk(c, self.config.anchor_channels_config.as_ref()))
1090+
.collect()
10851091
}
10861092

10871093
/// Connect to a node on the peer-to-peer network.

src/types.rs

Lines changed: 67 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ use lightning_net_tokio::SocketDescriptor;
4242

4343
use crate::chain::bitcoind::UtxoSourceClient;
4444
use crate::chain::ChainSource;
45-
use crate::config::ChannelConfig;
45+
use crate::config::{AnchorChannelsConfig, ChannelConfig};
4646
use crate::data_store::DataStore;
4747
use crate::fee_estimator::OnchainFeeEstimator;
4848
use crate::ffi::maybe_wrap;
@@ -452,6 +452,47 @@ pub struct ChannelCounterparty {
452452
pub outbound_htlc_maximum_msat: Option<u64>,
453453
}
454454

455+
/// Describes the reserve behavior of a channel based on its type and trust configuration.
456+
///
457+
/// This captures the combination of the channel's on-chain construction (anchor outputs vs legacy
458+
/// static_remote_key) and whether the counterparty is in our trusted peers list. It tells the
459+
/// user what reserve obligations exist for this channel without exposing internal protocol details.
460+
///
461+
/// See [`AnchorChannelsConfig`] for how reserve behavior is configured.
462+
///
463+
/// [`AnchorChannelsConfig`]: crate::config::AnchorChannelsConfig
464+
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
465+
#[cfg_attr(feature = "uniffi", derive(uniffi::Enum))]
466+
pub enum ReserveType {
467+
/// An anchor outputs channel where we maintain a per-channel on-chain reserve for fee
468+
/// bumping force-close transactions.
469+
///
470+
/// Anchor channels allow either party to fee-bump commitment transactions via CPFP
471+
/// at broadcast time. Because the pre-signed commitment fee may be insufficient under
472+
/// current fee conditions, the broadcaster must supply additional funds (hence adaptive)
473+
/// through an anchor output spend. The reserve ensures sufficient on-chain funds are
474+
/// available to cover this.
475+
///
476+
/// This is the default for anchor channels when the counterparty is not in
477+
/// [`trusted_peers_no_reserve`].
478+
///
479+
/// [`trusted_peers_no_reserve`]: crate::config::AnchorChannelsConfig::trusted_peers_no_reserve
480+
Adaptive,
481+
/// An anchor outputs channel where we do not maintain any reserve, because the counterparty
482+
/// is in our [`trusted_peers_no_reserve`] list.
483+
///
484+
/// In this mode, we trust the counterparty to broadcast a valid commitment transaction on
485+
/// our behalf and do not set aside funds for fee bumping.
486+
///
487+
/// [`trusted_peers_no_reserve`]: crate::config::AnchorChannelsConfig::trusted_peers_no_reserve
488+
TrustedPeersNoReserve,
489+
/// A legacy (pre-anchor) channel using only `option_static_remotekey`.
490+
///
491+
/// These channels do not use anchor outputs and therefore do not require an on-chain reserve
492+
/// for fee bumping. Commitment transaction fees are pre-committed at channel open time.
493+
Legacy,
494+
}
495+
455496
/// Details of a channel as returned by [`Node::list_channels`].
456497
///
457498
/// When a channel is spliced, most fields continue to refer to the original pre-splice channel
@@ -616,10 +657,32 @@ pub struct ChannelDetails {
616657
///
617658
/// Will be `None` for objects serialized with LDK Node v0.1 and earlier.
618659
pub channel_shutdown_state: Option<ChannelShutdownState>,
660+
/// The type of on-chain reserve maintained for this channel.
661+
///
662+
/// See [`ReserveType`] for details on how reserves differ between anchor and legacy channels.
663+
pub reserve_type: ReserveType,
619664
}
620665

621-
impl From<LdkChannelDetails> for ChannelDetails {
622-
fn from(value: LdkChannelDetails) -> Self {
666+
impl ChannelDetails {
667+
pub(crate) fn from_ldk(
668+
value: LdkChannelDetails, anchor_channels_config: Option<&AnchorChannelsConfig>,
669+
) -> Self {
670+
let reserve_type =
671+
if value.channel_type.as_ref().is_some_and(|ct| ct.supports_anchors_zero_fee_htlc_tx())
672+
{
673+
if let Some(config) = anchor_channels_config {
674+
if config.trusted_peers_no_reserve.contains(&value.counterparty.node_id) {
675+
ReserveType::TrustedPeersNoReserve
676+
} else {
677+
ReserveType::Adaptive
678+
}
679+
} else {
680+
ReserveType::Adaptive
681+
}
682+
} else {
683+
ReserveType::Legacy
684+
};
685+
623686
ChannelDetails {
624687
channel_id: value.channel_id,
625688
counterparty: ChannelCounterparty {
@@ -664,6 +727,7 @@ impl From<LdkChannelDetails> for ChannelDetails {
664727
.map(|c| c.into())
665728
.expect("value is set for objects serialized with LDK v0.0.109+"),
666729
channel_shutdown_state: value.channel_shutdown_state,
730+
reserve_type,
667731
}
668732
}
669733
}

0 commit comments

Comments
 (0)