Skip to content

Commit 00826a1

Browse files
committed
Expose ChannelTypeFeatures in ChannelDetails
Add a UniFFI wrapper so bindings can inspect channel type flags. Update anchor accounting tests to use channel type features instead of inferring zero-fee commitments from the commitment feerate. Co-Authored-By: HAL 9000
1 parent 6fc65fa commit 00826a1

5 files changed

Lines changed: 103 additions & 7 deletions

File tree

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@
1818
- `EsploraSyncConfig` and `ElectrumSyncConfig` now support `force_wallet_full_scan`. When set,
1919
the on-chain wallet keeps using BDK `full_scan` instead of incremental sync until a full scan
2020
succeeds, allowing restored wallets to rediscover funds sent to previously-unknown addresses.
21+
- The `ChannelDetails` returned by `Node::list_channels` now exposes the negotiated
22+
`ChannelTypeFeatures`.
2123
- `Config::anchor_channels_config` is no longer optional, hence anchor channels can no longer be
2224
disabled. We still negotiate legacy channels if the peer does not support anchor channels.
2325

src/ffi/types.rs

Lines changed: 80 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,10 @@ pub use lightning_liquidity::lsps0::ser::LSPSDateTime;
4444
pub use lightning_liquidity::lsps1::msgs::{
4545
LSPS1ChannelInfo, LSPS1OrderId, LSPS1OrderParams, LSPS1PaymentState,
4646
};
47-
use lightning_types::features::{InitFeatures as LdkInitFeatures, NodeFeatures as LdkNodeFeatures};
47+
use lightning_types::features::{
48+
ChannelTypeFeatures as LdkChannelTypeFeatures, InitFeatures as LdkInitFeatures,
49+
NodeFeatures as LdkNodeFeatures,
50+
};
4851
pub use lightning_types::payment::{PaymentHash, PaymentPreimage, PaymentSecret};
4952
pub use lightning_types::string::UntrustedString;
5053
use vss_client::headers::{
@@ -1817,6 +1820,82 @@ impl From<LdkNodeFeatures> for NodeFeatures {
18171820
}
18181821
}
18191822

1823+
#[derive(Debug, Clone, PartialEq, Eq, uniffi::Object)]
1824+
#[uniffi::export(Debug, Eq)]
1825+
pub struct ChannelTypeFeatures {
1826+
pub(crate) inner: LdkChannelTypeFeatures,
1827+
}
1828+
1829+
#[uniffi::export]
1830+
impl ChannelTypeFeatures {
1831+
/// Constructs channel type features from big-endian BOLT 9 encoded bytes.
1832+
#[uniffi::constructor]
1833+
pub fn from_bytes(bytes: &[u8]) -> Self {
1834+
Self { inner: LdkChannelTypeFeatures::from_be_bytes(bytes.to_vec()) }
1835+
}
1836+
1837+
/// Returns the BOLT 9 big-endian encoded representation of these features.
1838+
pub fn to_bytes(&self) -> Vec<u8> {
1839+
self.inner.encode()
1840+
}
1841+
1842+
/// Whether this channel type advertises support for `option_static_remotekey`.
1843+
pub fn supports_static_remote_key(&self) -> bool {
1844+
self.inner.supports_static_remote_key()
1845+
}
1846+
1847+
/// Whether this channel type requires `option_static_remotekey`.
1848+
pub fn requires_static_remote_key(&self) -> bool {
1849+
self.inner.requires_static_remote_key()
1850+
}
1851+
1852+
/// Whether this channel type advertises support for `option_anchors_zero_fee_htlc_tx`.
1853+
pub fn supports_anchors_zero_fee_htlc_tx(&self) -> bool {
1854+
self.inner.supports_anchors_zero_fee_htlc_tx()
1855+
}
1856+
1857+
/// Whether this channel type requires `option_anchors_zero_fee_htlc_tx`.
1858+
pub fn requires_anchors_zero_fee_htlc_tx(&self) -> bool {
1859+
self.inner.requires_anchors_zero_fee_htlc_tx()
1860+
}
1861+
1862+
/// Whether this channel type advertises support for `option_anchors_nonzero_fee_htlc_tx`.
1863+
pub fn supports_anchors_nonzero_fee_htlc_tx(&self) -> bool {
1864+
self.inner.supports_anchors_nonzero_fee_htlc_tx()
1865+
}
1866+
1867+
/// Whether this channel type requires `option_anchors_nonzero_fee_htlc_tx`.
1868+
pub fn requires_anchors_nonzero_fee_htlc_tx(&self) -> bool {
1869+
self.inner.requires_anchors_nonzero_fee_htlc_tx()
1870+
}
1871+
1872+
/// Whether this channel type advertises support for `option_taproot`.
1873+
pub fn supports_taproot(&self) -> bool {
1874+
self.inner.supports_taproot()
1875+
}
1876+
1877+
/// Whether this channel type requires `option_taproot`.
1878+
pub fn requires_taproot(&self) -> bool {
1879+
self.inner.requires_taproot()
1880+
}
1881+
1882+
/// Whether this channel type advertises support for `option_zero_fee_commitments`.
1883+
pub fn supports_anchor_zero_fee_commitments(&self) -> bool {
1884+
self.inner.supports_anchor_zero_fee_commitments()
1885+
}
1886+
1887+
/// Whether this channel type requires `option_zero_fee_commitments`.
1888+
pub fn requires_anchor_zero_fee_commitments(&self) -> bool {
1889+
self.inner.requires_anchor_zero_fee_commitments()
1890+
}
1891+
}
1892+
1893+
impl From<LdkChannelTypeFeatures> for ChannelTypeFeatures {
1894+
fn from(features: LdkChannelTypeFeatures) -> Self {
1895+
Self { inner: features }
1896+
}
1897+
}
1898+
18201899
#[derive(Debug, Clone, PartialEq, Eq, uniffi::Object)]
18211900
#[uniffi::export(Debug, Eq)]
18221901
pub struct InitFeatures {

src/types.rs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,8 @@ use lightning::util::sweep::OutputSweeper;
3939
use lightning_block_sync::gossip::GossipVerifier;
4040
use lightning_liquidity::utils::time::DefaultTimeProvider;
4141
use lightning_net_tokio::SocketDescriptor;
42+
#[cfg(not(feature = "uniffi"))]
43+
use lightning_types::features::ChannelTypeFeatures;
4244

4345
use crate::chain::bitcoind::UtxoSourceClient;
4446
use crate::chain::ChainSource;
@@ -51,6 +53,8 @@ use crate::message_handler::NodeCustomMessageHandler;
5153
use crate::payment::{PaymentDetails, PendingPaymentDetails};
5254
use crate::runtime::RuntimeSpawner;
5355

56+
#[cfg(feature = "uniffi")]
57+
type ChannelTypeFeatures = Arc<crate::ffi::ChannelTypeFeatures>;
5458
#[cfg(not(feature = "uniffi"))]
5559
type InitFeatures = lightning::types::features::InitFeatures;
5660
#[cfg(feature = "uniffi")]
@@ -642,6 +646,11 @@ pub struct ChannelDetails {
642646
///
643647
/// See [`ReserveType`] for details on how reserves differ between anchor and legacy channels.
644648
pub reserve_type: Option<ReserveType>,
649+
/// The negotiated channel type features.
650+
///
651+
/// Will be `None` until channel negotiation has completed and the channel type has been
652+
/// determined.
653+
pub channel_type: Option<ChannelTypeFeatures>,
645654
}
646655

647656
impl ChannelDetails {
@@ -706,6 +715,7 @@ impl ChannelDetails {
706715
.expect("value is set for objects serialized with LDK v0.0.109+"),
707716
channel_shutdown_state: value.channel_shutdown_state,
708717
reserve_type,
718+
channel_type: value.channel_type.map(maybe_wrap),
709719
}
710720
}
711721
}

tests/common/mod.rs

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1578,12 +1578,15 @@ pub(crate) async fn do_channel_full_cycle<E: ElectrumApi>(
15781578
);
15791579

15801580
if disable_node_b_reserve {
1581-
let node_a_outbound_capacity_msat = node_a.list_channels()[0].outbound_capacity_msat;
1582-
let node_a_reserve_msat =
1583-
node_a.list_channels()[0].unspendable_punishment_reserve.unwrap() * 1000;
1584-
let zero_fee_commitments = node_a.list_channels()[0].feerate_sat_per_1000_weight == 0;
1581+
let node_a_channel = node_a.list_channels().into_iter().next().unwrap();
1582+
let node_a_outbound_capacity_msat = node_a_channel.outbound_capacity_msat;
1583+
let node_a_reserve_msat = node_a_channel.unspendable_punishment_reserve.unwrap() * 1000;
1584+
let zero_fee_commitments = node_a_channel
1585+
.channel_type
1586+
.as_ref()
1587+
.map_or(false, |c| c.requires_anchor_zero_fee_commitments());
15851588
let node_a_anchors_msat = if zero_fee_commitments { 0 } else { 2 * 330 * 1000 };
1586-
let funding_amount_msat = node_a.list_channels()[0].channel_value_sats * 1000;
1589+
let funding_amount_msat = node_a_channel.channel_value_sats * 1000;
15871590
// Node B does not have any reserve, so we only subtract a few items on node A's
15881591
// side to arrive at node B's capacity
15891592
let node_b_capacity_msat = funding_amount_msat

tests/integration_tests_rust.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1706,7 +1706,9 @@ async fn splice_channel() {
17061706
let user_channel_id_b = expect_channel_ready_event!(node_b, node_a.node_id());
17071707

17081708
let opening_transaction_fee_sat = 156;
1709-
let zero_fee_commitments = node_a.list_channels()[0].feerate_sat_per_1000_weight == 0;
1709+
let channel = node_a.list_channels().into_iter().next().unwrap();
1710+
let zero_fee_commitments =
1711+
channel.channel_type.as_ref().map_or(false, |c| c.requires_anchor_zero_fee_commitments());
17101712
let closing_transaction_fee_sat = if zero_fee_commitments { 0 } else { 614 };
17111713
let anchor_output_sat = if zero_fee_commitments { 0 } else { 330 };
17121714

0 commit comments

Comments
 (0)