Skip to content
Open
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
21 changes: 21 additions & 0 deletions src/ffi/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ pub use bitcoin::{Address, BlockHash, FeeRate, Network, OutPoint, ScriptBuf, Txi
pub use lightning::chain::channelmonitor::BalanceSource;
use lightning::events::PaidBolt12Invoice as LdkPaidBolt12Invoice;
pub use lightning::events::{ClosureReason, PaymentFailureReason};
pub use lightning::ln::channel_state::ChannelShutdownState;
use lightning::ln::channelmanager::PaymentId;
use lightning::ln::msgs::DecodeError;
pub use lightning::ln::types::ChannelId;
Expand Down Expand Up @@ -1408,6 +1409,26 @@ uniffi::custom_type!(LSPSDateTime, String, {
},
});

/// The shutdown state of a channel as returned in [`ChannelDetails::channel_shutdown_state`].
///
/// [`ChannelDetails::channel_shutdown_state`]: crate::ChannelDetails::channel_shutdown_state
#[uniffi::remote(Enum)]
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum ChannelShutdownState {
/// Channel has not sent or received a shutdown message.
NotShuttingDown,
/// Local node has sent a shutdown message for this channel.
ShutdownInitiated,
/// Shutdown message exchanges have concluded and the channels are in the midst of
/// resolving all existing open HTLCs before closing can continue.
ResolvingHTLCs,
/// All HTLCs have been resolved, nodes are currently negotiating channel close onchain fee rates.
NegotiatingClosingFee,
/// We've successfully negotiated a closing_signed dance. At this point `ChannelManager` is about
/// to drop the channel.
ShutdownComplete,
}

/// The reason the channel was closed. See individual variants for more details.
#[uniffi::remote(Enum)]
#[derive(Clone, Debug, PartialEq, Eq)]
Expand Down
7 changes: 5 additions & 2 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -145,7 +145,7 @@ pub use lightning;
use lightning::chain::BestBlock;
use lightning::impl_writeable_tlv_based;
use lightning::ln::chan_utils::FUNDING_TRANSACTION_WITNESS_WEIGHT;
use lightning::ln::channel_state::{ChannelDetails as LdkChannelDetails, ChannelShutdownState};
use lightning::ln::channel_state::ChannelDetails as LdkChannelDetails;
use lightning::ln::channelmanager::PaymentId;
use lightning::ln::msgs::SocketAddress;
use lightning::routing::gossip::NodeAlias;
Expand Down Expand Up @@ -173,7 +173,10 @@ use types::{
HRNResolver, KeysManager, OnionMessenger, PaymentStore, PeerManager, Router, Scorer, Sweeper,
Wallet,
};
pub use types::{ChannelDetails, CustomTlvRecord, PeerDetails, SyncAndAsyncKVStore, UserChannelId};
pub use types::{
ChannelDetails, ChannelShutdownState, CustomTlvRecord, PeerDetails, SyncAndAsyncKVStore,
UserChannelId,
};
pub use vss_client;

use crate::scoring::setup_background_pathfinding_scores_sync;
Expand Down
6 changes: 6 additions & 0 deletions src/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ use bitcoin_payment_instructions::onion_message_resolver::LDKOnionMessageDNSSECH
use lightning::chain::chainmonitor;
use lightning::impl_writeable_tlv_based;
use lightning::ln::channel_state::ChannelDetails as LdkChannelDetails;
pub use lightning::ln::channel_state::ChannelShutdownState;
use lightning::ln::msgs::{RoutingMessageHandler, SocketAddress};
use lightning::ln::peer_handler::IgnoringMessageHandler;
use lightning::ln::types::ChannelId;
Expand Down Expand Up @@ -529,6 +530,10 @@ pub struct ChannelDetails {
pub inbound_htlc_maximum_msat: Option<u64>,
/// Set of configurable parameters that affect channel operation.
pub config: ChannelConfig,
/// The current shutdown state of the channel, if any.
///
/// Returns `None` for `ChannelDetails` serialized on LDK versions prior to 0.0.116.
pub channel_shutdown_state: Option<ChannelShutdownState>,
}

impl From<LdkChannelDetails> for ChannelDetails {
Expand Down Expand Up @@ -584,6 +589,7 @@ impl From<LdkChannelDetails> for ChannelDetails {
inbound_htlc_maximum_msat: value.inbound_htlc_maximum_msat,
// unwrap safety: `config` is only `None` for LDK objects serialized prior to 0.0.109.
config: value.config.map(|c| c.into()).unwrap(),
channel_shutdown_state: value.channel_shutdown_state,
}
}
}
Expand Down
54 changes: 52 additions & 2 deletions tests/common/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,8 @@ use ldk_node::entropy::{generate_entropy_mnemonic, NodeEntropy};
use ldk_node::io::sqlite_store::SqliteStore;
use ldk_node::payment::{PaymentDirection, PaymentKind, PaymentStatus};
use ldk_node::{
Builder, CustomTlvRecord, Event, LightningBalance, Node, NodeError, PendingSweepBalance,
UserChannelId,
Builder, ChannelShutdownState, CustomTlvRecord, Event, LightningBalance, Node, NodeError,
PendingSweepBalance, UserChannelId,
};
use lightning::io;
use lightning::ln::msgs::SocketAddress;
Expand Down Expand Up @@ -918,6 +918,28 @@ pub(crate) async fn do_channel_full_cycle<E: ElectrumApi>(
let user_channel_id_a = expect_channel_ready_event!(node_a, node_b.node_id());
let user_channel_id_b = expect_channel_ready_event!(node_b, node_a.node_id());

// After channel_ready, no shutdown should be in progress on either side.
for channel in node_a.list_channels() {
assert!(
matches!(
channel.channel_shutdown_state,
None | Some(ChannelShutdownState::NotShuttingDown)
),
"Expected no shutdown in progress on node_a, got {:?}",
channel.channel_shutdown_state,
);
}
for channel in node_b.list_channels() {
assert!(
matches!(
channel.channel_shutdown_state,
None | Some(ChannelShutdownState::NotShuttingDown)
),
"Expected no shutdown in progress on node_b, got {:?}",
channel.channel_shutdown_state,
);
}

println!("\nB receive");
let invoice_amount_1_msat = 2500_000;
let invoice_description: Bolt11InvoiceDescription =
Expand Down Expand Up @@ -1233,6 +1255,20 @@ pub(crate) async fn do_channel_full_cycle<E: ElectrumApi>(
expect_channel_ready_event!(node_a, node_b.node_id());
expect_channel_ready_event!(node_b, node_a.node_id());

// After the splice-out, the channel must still report no shutdown in progress.
for channel in node_a.list_channels() {
assert!(matches!(
channel.channel_shutdown_state,
None | Some(ChannelShutdownState::NotShuttingDown)
));
}
for channel in node_b.list_channels() {
assert!(matches!(
channel.channel_shutdown_state,
None | Some(ChannelShutdownState::NotShuttingDown)
));
}

assert_eq!(
node_a
.list_payments_with_filter(|p| p.direction == PaymentDirection::Inbound
Expand All @@ -1255,6 +1291,20 @@ pub(crate) async fn do_channel_full_cycle<E: ElectrumApi>(
expect_channel_ready_event!(node_a, node_b.node_id());
expect_channel_ready_event!(node_b, node_a.node_id());

// After the splice-in, the channel must still report no shutdown in progress.
for channel in node_a.list_channels() {
assert!(matches!(
channel.channel_shutdown_state,
None | Some(ChannelShutdownState::NotShuttingDown)
));
}
for channel in node_b.list_channels() {
assert!(matches!(
channel.channel_shutdown_state,
None | Some(ChannelShutdownState::NotShuttingDown)
));
}

assert_eq!(
node_a
.list_payments_with_filter(|p| p.direction == PaymentDirection::Outbound
Expand Down
132 changes: 77 additions & 55 deletions tests/integration_tests_rust.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ use ldk_node::payment::{
ConfirmationStatus, PaymentDetails, PaymentDirection, PaymentKind, PaymentStatus,
UnifiedPaymentResult,
};
use ldk_node::{Builder, Event, NodeError};
use ldk_node::{Builder, ChannelShutdownState, Event, NodeError};
use lightning::ln::channelmanager::PaymentId;
use lightning::routing::gossip::{NodeAlias, NodeId};
use lightning::routing::router::RouteParametersConfig;
Expand Down Expand Up @@ -2108,24 +2108,26 @@ async fn lsps2_client_trusts_lsp() {

service_node.sync_wallets().unwrap();
client_node.sync_wallets().unwrap();
assert_eq!(
client_node
.list_channels()
.iter()
.find(|c| c.counterparty_node_id == service_node_id)
.unwrap()
.confirmations,
Some(0)
);
assert_eq!(
service_node
.list_channels()
.iter()
.find(|c| c.counterparty_node_id == client_node_id)
.unwrap()
.confirmations,
Some(0)
);
let client_channel = client_node
.list_channels()
.into_iter()
.find(|c| c.counterparty_node_id == service_node_id)
.unwrap();
assert_eq!(client_channel.confirmations, Some(0));
assert!(matches!(
client_channel.channel_shutdown_state,
None | Some(ChannelShutdownState::NotShuttingDown)
));
let service_channel = service_node
.list_channels()
.into_iter()
.find(|c| c.counterparty_node_id == client_node_id)
.unwrap();
assert_eq!(service_channel.confirmations, Some(0));
assert!(matches!(
service_channel.channel_shutdown_state,
None | Some(ChannelShutdownState::NotShuttingDown)
));

// Now claim the JIT payment, which should release the funding transaction
let service_fee_msat = (jit_amount_msat * channel_opening_fee_ppm as u64) / 1_000_000;
Expand All @@ -2152,24 +2154,26 @@ async fn lsps2_client_trusts_lsp() {
generate_blocks_and_wait(&bitcoind.client, &electrsd.client, 6).await;
service_node.sync_wallets().unwrap();
client_node.sync_wallets().unwrap();
assert_eq!(
client_node
.list_channels()
.iter()
.find(|c| c.counterparty_node_id == service_node_id)
.unwrap()
.confirmations,
Some(6)
);
assert_eq!(
service_node
.list_channels()
.iter()
.find(|c| c.counterparty_node_id == client_node_id)
.unwrap()
.confirmations,
Some(6)
);
let client_channel = client_node
.list_channels()
.into_iter()
.find(|c| c.counterparty_node_id == service_node_id)
.unwrap();
assert_eq!(client_channel.confirmations, Some(6));
assert!(matches!(
client_channel.channel_shutdown_state,
None | Some(ChannelShutdownState::NotShuttingDown)
));
let service_channel = service_node
.list_channels()
.into_iter()
.find(|c| c.counterparty_node_id == client_node_id)
.unwrap();
assert_eq!(service_channel.confirmations, Some(6));
assert!(matches!(
service_channel.channel_shutdown_state,
None | Some(ChannelShutdownState::NotShuttingDown)
));
}

#[tokio::test(flavor = "multi_thread", worker_threads = 1)]
Expand Down Expand Up @@ -2280,24 +2284,26 @@ async fn lsps2_lsp_trusts_client_but_client_does_not_claim() {
generate_blocks_and_wait(&bitcoind.client, &electrsd.client, 6).await;
service_node.sync_wallets().unwrap();
client_node.sync_wallets().unwrap();
assert_eq!(
client_node
.list_channels()
.iter()
.find(|c| c.counterparty_node_id == service_node_id)
.unwrap()
.confirmations,
Some(6)
);
assert_eq!(
service_node
.list_channels()
.iter()
.find(|c| c.counterparty_node_id == client_node_id)
.unwrap()
.confirmations,
Some(6)
);
let client_channel = client_node
.list_channels()
.into_iter()
.find(|c| c.counterparty_node_id == service_node_id)
.unwrap();
assert_eq!(client_channel.confirmations, Some(6));
assert!(matches!(
client_channel.channel_shutdown_state,
None | Some(ChannelShutdownState::NotShuttingDown)
));
let service_channel = service_node
.list_channels()
.into_iter()
.find(|c| c.counterparty_node_id == client_node_id)
.unwrap();
assert_eq!(service_channel.confirmations, Some(6));
assert!(matches!(
service_channel.channel_shutdown_state,
None | Some(ChannelShutdownState::NotShuttingDown)
));
}

#[tokio::test(flavor = "multi_thread", worker_threads = 1)]
Expand Down Expand Up @@ -2672,6 +2678,10 @@ async fn open_channel_with_all_with_anchors() {
assert!(channel.channel_value_sats > premine_amount_sat - anchor_reserve_sat - 500);
assert_eq!(channel.counterparty_node_id, node_b.node_id());
assert_eq!(channel.funding_txo.unwrap(), funding_txo);
assert!(matches!(
channel.channel_shutdown_state,
None | Some(ChannelShutdownState::NotShuttingDown)
));

node_a.stop().unwrap();
node_b.stop().unwrap();
Expand Down Expand Up @@ -2723,6 +2733,10 @@ async fn open_channel_with_all_without_anchors() {
assert!(channel.channel_value_sats > premine_amount_sat - 500);
assert_eq!(channel.counterparty_node_id, node_b.node_id());
assert_eq!(channel.funding_txo.unwrap(), funding_txo);
assert!(matches!(
channel.channel_shutdown_state,
None | Some(ChannelShutdownState::NotShuttingDown)
));

node_a.stop().unwrap();
node_b.stop().unwrap();
Expand Down Expand Up @@ -2766,6 +2780,10 @@ async fn splice_in_with_all_balance() {
assert_eq!(channels.len(), 1);
assert_eq!(channels[0].channel_value_sats, channel_amount_sat);
assert_eq!(channels[0].funding_txo.unwrap(), funding_txo);
assert!(matches!(
channels[0].channel_shutdown_state,
None | Some(ChannelShutdownState::NotShuttingDown)
));

let balance_before_splice = node_a.list_balances().spendable_onchain_balance_sats;
assert!(balance_before_splice > 0);
Expand All @@ -2787,6 +2805,10 @@ async fn splice_in_with_all_balance() {
let channels = node_a.list_channels();
assert_eq!(channels.len(), 1);
let channel = &channels[0];
assert!(matches!(
channel.channel_shutdown_state,
None | Some(ChannelShutdownState::NotShuttingDown)
));
assert!(
channel.channel_value_sats > premine_amount_sat - anchor_reserve_sat - 1000,
"Channel value {} should be close to premined amount {} minus anchor reserve {} and fees",
Expand Down
Loading