Skip to content

Commit 70cfd9c

Browse files
authored
Merge pull request #3881 from TheBlueMatt/2025-06-fc-always-broadcast
Somewhat clean up closure pipelines
2 parents b939100 + 6f56dbc commit 70cfd9c

17 files changed

+649
-658
lines changed

lightning-persister/src/fs_store.rs

Lines changed: 18 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -592,23 +592,19 @@ mod tests {
592592
let node_cfgs = create_node_cfgs(2, &chanmon_cfgs);
593593
let node_chanmgrs = create_node_chanmgrs(2, &node_cfgs, &[None, None]);
594594
let nodes = create_network(2, &node_cfgs, &node_chanmgrs);
595+
596+
let node_a_id = nodes[0].node.get_our_node_id();
597+
595598
let chan = create_announced_chan_between_nodes(&nodes, 0, 1);
596-
let error_message = "Channel force-closed";
599+
600+
let message = "Channel force-closed".to_owned();
597601
nodes[1]
598602
.node
599-
.force_close_broadcasting_latest_txn(
600-
&chan.2,
601-
&nodes[0].node.get_our_node_id(),
602-
error_message.to_string(),
603-
)
603+
.force_close_broadcasting_latest_txn(&chan.2, &node_a_id, message.clone())
604604
.unwrap();
605-
check_closed_event!(
606-
nodes[1],
607-
1,
608-
ClosureReason::HolderForceClosed { broadcasted_latest_txn: Some(true) },
609-
[nodes[0].node.get_our_node_id()],
610-
100000
611-
);
605+
let reason =
606+
ClosureReason::HolderForceClosed { broadcasted_latest_txn: Some(true), message };
607+
check_closed_event!(nodes[1], 1, reason, [node_a_id], 100000);
612608
let mut added_monitors = nodes[1].chain_monitor.added_monitors.lock().unwrap();
613609

614610
// Set the store's directory to read-only, which should result in
@@ -640,23 +636,19 @@ mod tests {
640636
let node_cfgs = create_node_cfgs(2, &chanmon_cfgs);
641637
let node_chanmgrs = create_node_chanmgrs(2, &node_cfgs, &[None, None]);
642638
let nodes = create_network(2, &node_cfgs, &node_chanmgrs);
639+
640+
let node_a_id = nodes[0].node.get_our_node_id();
641+
643642
let chan = create_announced_chan_between_nodes(&nodes, 0, 1);
644-
let error_message = "Channel force-closed";
643+
644+
let message = "Channel force-closed".to_owned();
645645
nodes[1]
646646
.node
647-
.force_close_broadcasting_latest_txn(
648-
&chan.2,
649-
&nodes[0].node.get_our_node_id(),
650-
error_message.to_string(),
651-
)
647+
.force_close_broadcasting_latest_txn(&chan.2, &node_a_id, message.clone())
652648
.unwrap();
653-
check_closed_event!(
654-
nodes[1],
655-
1,
656-
ClosureReason::HolderForceClosed { broadcasted_latest_txn: Some(true) },
657-
[nodes[0].node.get_our_node_id()],
658-
100000
659-
);
649+
let reason =
650+
ClosureReason::HolderForceClosed { broadcasted_latest_txn: Some(true), message };
651+
check_closed_event!(nodes[1], 1, reason, [node_a_id], 100000);
660652
let mut added_monitors = nodes[1].chain_monitor.added_monitors.lock().unwrap();
661653
let update_map = nodes[1].chain_monitor.latest_monitor_update_id.lock().unwrap();
662654
let update_id = update_map.get(&added_monitors[0].1.channel_id()).unwrap();

lightning-persister/src/test_utils.rs

Lines changed: 7 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -137,6 +137,8 @@ pub(crate) fn do_test_store<K: KVStore + Sync>(store_0: &K, store_1: &K) {
137137
let node_chanmgrs = create_node_chanmgrs(2, &node_cfgs, &[None, None]);
138138
let nodes = create_network(2, &node_cfgs, &node_chanmgrs);
139139

140+
let node_b_id = nodes[1].node.get_our_node_id();
141+
140142
// Check that the persisted channel data is empty before any channels are
141143
// open.
142144
let mut persisted_chan_data_0 =
@@ -178,22 +180,14 @@ pub(crate) fn do_test_store<K: KVStore + Sync>(store_0: &K, store_1: &K) {
178180

179181
// Force close because cooperative close doesn't result in any persisted
180182
// updates.
181-
let error_message = "Channel force-closed";
183+
let message = "Channel force-closed".to_owned();
184+
let chan_id = nodes[0].node.list_channels()[0].channel_id;
182185
nodes[0]
183186
.node
184-
.force_close_broadcasting_latest_txn(
185-
&nodes[0].node.list_channels()[0].channel_id,
186-
&nodes[1].node.get_our_node_id(),
187-
error_message.to_string(),
188-
)
187+
.force_close_broadcasting_latest_txn(&chan_id, &node_b_id, message.clone())
189188
.unwrap();
190-
check_closed_event!(
191-
nodes[0],
192-
1,
193-
ClosureReason::HolderForceClosed { broadcasted_latest_txn: Some(true) },
194-
[nodes[1].node.get_our_node_id()],
195-
100000
196-
);
189+
let reason = ClosureReason::HolderForceClosed { broadcasted_latest_txn: Some(true), message };
190+
check_closed_event!(nodes[0], 1, reason, [node_b_id], 100000);
197191
check_closed_broadcast!(nodes[0], true);
198192
check_added_monitors!(nodes[0], 1);
199193

lightning/src/chain/chainmonitor.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1477,12 +1477,13 @@ mod tests {
14771477

14781478
// Test that monitors with pending_claims are persisted on every block.
14791479
// Now, close channel_2 i.e. b/w node-0 and node-2 to create pending_claim in node[0].
1480+
let message = "Channel force-closed".to_owned();
14801481
nodes[0]
14811482
.node
1482-
.force_close_broadcasting_latest_txn(&channel_2, &node_c_id, "closed".to_string())
1483+
.force_close_broadcasting_latest_txn(&channel_2, &node_c_id, message.clone())
14831484
.unwrap();
14841485
let closure_reason =
1485-
ClosureReason::HolderForceClosed { broadcasted_latest_txn: Some(true) };
1486+
ClosureReason::HolderForceClosed { broadcasted_latest_txn: Some(true), message };
14861487
check_closed_event!(&nodes[0], 1, closure_reason, false, [node_c_id], 1000000);
14871488
check_closed_broadcast(&nodes[0], 1, true);
14881489
let close_tx = nodes[0].tx_broadcaster.txn_broadcasted.lock().unwrap().split_off(0);

lightning/src/chain/channelmonitor.rs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3646,7 +3646,11 @@ impl<Signer: EcdsaChannelSigner> ChannelMonitorImpl<Signer> {
36463646
F::Target: FeeEstimator,
36473647
L::Target: Logger,
36483648
{
3649-
let (claimable_outpoints, _) = self.generate_claimable_outpoints_and_watch_outputs(ClosureReason::HolderForceClosed { broadcasted_latest_txn: Some(true) });
3649+
let reason = ClosureReason::HolderForceClosed {
3650+
broadcasted_latest_txn: Some(true),
3651+
message: "ChannelMonitor-initiated commitment transaction broadcast".to_owned(),
3652+
};
3653+
let (claimable_outpoints, _) = self.generate_claimable_outpoints_and_watch_outputs(reason);
36503654
let conf_target = self.closure_conf_target();
36513655
self.onchain_tx_handler.update_claims_view_from_requests(
36523656
claimable_outpoints, self.best_block.height, self.best_block.height, broadcaster,

lightning/src/events/mod.rs

Lines changed: 42 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -318,23 +318,30 @@ pub enum ClosureReason {
318318
/// [`UntrustedString`]: crate::types::string::UntrustedString
319319
peer_msg: UntrustedString,
320320
},
321-
/// Closure generated from [`ChannelManager::force_close_channel`], called by the user.
321+
/// Closure generated from [`ChannelManager::force_close_broadcasting_latest_txn`] or
322+
/// [`ChannelManager::force_close_all_channels_broadcasting_latest_txn`], called by the user.
322323
///
323-
/// [`ChannelManager::force_close_channel`]: crate::ln::channelmanager::ChannelManager::force_close_channel.
324+
/// [`ChannelManager::force_close_broadcasting_latest_txn`]: crate::ln::channelmanager::ChannelManager::force_close_broadcasting_latest_txn
325+
/// [`ChannelManager::force_close_all_channels_broadcasting_latest_txn`]: crate::ln::channelmanager::ChannelManager::force_close_all_channels_broadcasting_latest_txn
324326
HolderForceClosed {
325327
/// Whether or not the latest transaction was broadcasted when the channel was force
326328
/// closed.
327329
///
328-
/// Channels closed using [`ChannelManager::force_close_broadcasting_latest_txn`] will have
329-
/// this field set to true, whereas channels closed using [`ChannelManager::force_close_without_broadcasting_txn`]
330-
/// or force-closed prior to being funded will have this field set to false.
330+
/// This will be set to `Some(true)` for any channels closed after their funding
331+
/// transaction was (or might have been) broadcasted, and `Some(false)` for any channels
332+
/// closed prior to their funding transaction being broadcasted.
331333
///
332334
/// This will be `None` for objects generated or written by LDK 0.0.123 and
333335
/// earlier.
334-
///
335-
/// [`ChannelManager::force_close_broadcasting_latest_txn`]: crate::ln::channelmanager::ChannelManager::force_close_broadcasting_latest_txn.
336-
/// [`ChannelManager::force_close_without_broadcasting_txn`]: crate::ln::channelmanager::ChannelManager::force_close_without_broadcasting_txn.
337336
broadcasted_latest_txn: Option<bool>,
337+
/// The error message provided to [`ChannelManager::force_close_broadcasting_latest_txn`] or
338+
/// [`ChannelManager::force_close_all_channels_broadcasting_latest_txn`].
339+
///
340+
/// This will be the empty string for objects generated or written by LDK 0.1 and earlier.
341+
///
342+
/// [`ChannelManager::force_close_broadcasting_latest_txn`]: crate::ln::channelmanager::ChannelManager::force_close_broadcasting_latest_txn
343+
/// [`ChannelManager::force_close_all_channels_broadcasting_latest_txn`]: crate::ln::channelmanager::ChannelManager::force_close_all_channels_broadcasting_latest_txn
344+
message: String,
338345
},
339346
/// The channel was closed after negotiating a cooperative close and we've now broadcasted
340347
/// the cooperative close transaction. Note the shutdown may have been initiated by us.
@@ -356,7 +363,8 @@ pub enum ClosureReason {
356363
/// commitment transaction came from our counterparty, but it may also have come from
357364
/// a copy of our own `ChannelMonitor`.
358365
CommitmentTxConfirmed,
359-
/// The funding transaction failed to confirm in a timely manner on an inbound channel.
366+
/// The funding transaction failed to confirm in a timely manner on an inbound channel or the
367+
/// counterparty failed to fund the channel in a timely manner.
360368
FundingTimedOut,
361369
/// Closure generated from processing an event, likely a HTLC forward/relay/reception.
362370
ProcessingError {
@@ -383,6 +391,12 @@ pub enum ClosureReason {
383391
/// The counterparty requested a cooperative close of a channel that had not been funded yet.
384392
/// The channel has been immediately closed.
385393
CounterpartyCoopClosedUnfundedChannel,
394+
/// We requested a cooperative close of a channel that had not been funded yet.
395+
/// The channel has been immediately closed.
396+
///
397+
/// Note that events containing this variant will be lost on downgrade to a version of LDK
398+
/// prior to 0.2.
399+
LocallyCoopClosedUnfundedChannel,
386400
/// Another channel in the same funding batch closed before the funding transaction
387401
/// was ready to be broadcast.
388402
FundingBatchClosure,
@@ -412,12 +426,13 @@ impl core::fmt::Display for ClosureReason {
412426
ClosureReason::CounterpartyForceClosed { peer_msg } => {
413427
f.write_fmt(format_args!("counterparty force-closed with message: {}", peer_msg))
414428
},
415-
ClosureReason::HolderForceClosed { broadcasted_latest_txn } => {
416-
f.write_str("user force-closed the channel")?;
429+
ClosureReason::HolderForceClosed { broadcasted_latest_txn, message } => {
430+
f.write_str("user force-closed the channel with the message \"")?;
431+
f.write_str(message)?;
417432
if let Some(brodcasted) = broadcasted_latest_txn {
418433
write!(
419434
f,
420-
" and {} the latest transaction",
435+
"\" and {} the latest transaction",
421436
if *brodcasted { "broadcasted" } else { "elected not to broadcast" }
422437
)
423438
} else {
@@ -454,6 +469,9 @@ impl core::fmt::Display for ClosureReason {
454469
ClosureReason::CounterpartyCoopClosedUnfundedChannel => {
455470
f.write_str("the peer requested the unfunded channel be closed")
456471
},
472+
ClosureReason::LocallyCoopClosedUnfundedChannel => {
473+
f.write_str("we requested the unfunded channel be closed")
474+
},
457475
ClosureReason::FundingBatchClosure => {
458476
f.write_str("another channel in the same funding batch closed")
459477
},
@@ -472,7 +490,10 @@ impl core::fmt::Display for ClosureReason {
472490
impl_writeable_tlv_based_enum_upgradable!(ClosureReason,
473491
(0, CounterpartyForceClosed) => { (1, peer_msg, required) },
474492
(1, FundingTimedOut) => {},
475-
(2, HolderForceClosed) => { (1, broadcasted_latest_txn, option) },
493+
(2, HolderForceClosed) => {
494+
(1, broadcasted_latest_txn, option),
495+
(3, message, (default_value, String::new())),
496+
},
476497
(6, CommitmentTxConfirmed) => {},
477498
(4, LegacyCooperativeClosure) => {},
478499
(8, ProcessingError) => { (1, err, required) },
@@ -487,6 +508,7 @@ impl_writeable_tlv_based_enum_upgradable!(ClosureReason,
487508
(0, peer_feerate_sat_per_kw, required),
488509
(2, required_feerate_sat_per_kw, required),
489510
},
511+
(25, LocallyCoopClosedUnfundedChannel) => {},
490512
);
491513

492514
/// The type of HTLC handling performed in [`Event::HTLCHandlingFailed`].
@@ -1461,7 +1483,7 @@ pub enum Event {
14611483
///
14621484
/// To accept the request (and in the case of a dual-funded channel, not contribute funds),
14631485
/// call [`ChannelManager::accept_inbound_channel`].
1464-
/// To reject the request, call [`ChannelManager::force_close_without_broadcasting_txn`].
1486+
/// To reject the request, call [`ChannelManager::force_close_broadcasting_latest_txn`].
14651487
/// Note that a ['ChannelClosed`] event will _not_ be triggered if the channel is rejected.
14661488
///
14671489
/// The event is only triggered when a new open channel request is received and the
@@ -1472,27 +1494,27 @@ pub enum Event {
14721494
/// returning `Err(ReplayEvent ())`) and won't be persisted across restarts.
14731495
///
14741496
/// [`ChannelManager::accept_inbound_channel`]: crate::ln::channelmanager::ChannelManager::accept_inbound_channel
1475-
/// [`ChannelManager::force_close_without_broadcasting_txn`]: crate::ln::channelmanager::ChannelManager::force_close_without_broadcasting_txn
1497+
/// [`ChannelManager::force_close_broadcasting_latest_txn`]: crate::ln::channelmanager::ChannelManager::force_close_broadcasting_latest_txn
14761498
/// [`UserConfig::manually_accept_inbound_channels`]: crate::util::config::UserConfig::manually_accept_inbound_channels
14771499
OpenChannelRequest {
14781500
/// The temporary channel ID of the channel requested to be opened.
14791501
///
14801502
/// When responding to the request, the `temporary_channel_id` should be passed
14811503
/// back to the ChannelManager through [`ChannelManager::accept_inbound_channel`] to accept,
1482-
/// or through [`ChannelManager::force_close_without_broadcasting_txn`] to reject.
1504+
/// or through [`ChannelManager::force_close_broadcasting_latest_txn`] to reject.
14831505
///
14841506
/// [`ChannelManager::accept_inbound_channel`]: crate::ln::channelmanager::ChannelManager::accept_inbound_channel
1485-
/// [`ChannelManager::force_close_without_broadcasting_txn`]: crate::ln::channelmanager::ChannelManager::force_close_without_broadcasting_txn
1507+
/// [`ChannelManager::force_close_broadcasting_latest_txn`]: crate::ln::channelmanager::ChannelManager::force_close_broadcasting_latest_txn
14861508
temporary_channel_id: ChannelId,
14871509
/// The node_id of the counterparty requesting to open the channel.
14881510
///
14891511
/// When responding to the request, the `counterparty_node_id` should be passed
14901512
/// back to the `ChannelManager` through [`ChannelManager::accept_inbound_channel`] to
1491-
/// accept the request, or through [`ChannelManager::force_close_without_broadcasting_txn`] to reject the
1492-
/// request.
1513+
/// accept the request, or through [`ChannelManager::force_close_broadcasting_latest_txn`]
1514+
/// to reject the request.
14931515
///
14941516
/// [`ChannelManager::accept_inbound_channel`]: crate::ln::channelmanager::ChannelManager::accept_inbound_channel
1495-
/// [`ChannelManager::force_close_without_broadcasting_txn`]: crate::ln::channelmanager::ChannelManager::force_close_without_broadcasting_txn
1517+
/// [`ChannelManager::force_close_broadcasting_latest_txn`]: crate::ln::channelmanager::ChannelManager::force_close_broadcasting_latest_txn
14961518
counterparty_node_id: PublicKey,
14971519
/// The channel value of the requested channel.
14981520
funding_satoshis: u64,

lightning/src/ln/async_signer_tests.rs

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1011,17 +1011,18 @@ fn do_test_async_holder_signatures(anchors: bool, remote_commitment: bool) {
10111011
// Route an HTLC and set the signer as unavailable.
10121012
let (_, _, chan_id, funding_tx) = create_announced_chan_between_nodes(&nodes, 0, 1);
10131013
route_payment(&nodes[0], &[&nodes[1]], 1_000_000);
1014-
let error_message = "Channel force-closed";
10151014

10161015
if remote_commitment {
1016+
let message = "Channel force-closed".to_owned();
10171017
// Make the counterparty broadcast its latest commitment.
10181018
nodes[1]
10191019
.node
1020-
.force_close_broadcasting_latest_txn(&chan_id, &node_a_id, error_message.to_string())
1020+
.force_close_broadcasting_latest_txn(&chan_id, &node_a_id, message.clone())
10211021
.unwrap();
10221022
check_added_monitors(&nodes[1], 1);
10231023
check_closed_broadcast(&nodes[1], 1, true);
1024-
let reason = ClosureReason::HolderForceClosed { broadcasted_latest_txn: Some(true) };
1024+
let reason =
1025+
ClosureReason::HolderForceClosed { broadcasted_latest_txn: Some(true), message };
10251026
check_closed_event(&nodes[1], 1, reason, false, &[node_a_id], 100_000);
10261027
} else {
10271028
nodes[0].disable_channel_signer_op(&node_b_id, &chan_id, SignerOp::SignHolderCommitment);

0 commit comments

Comments
 (0)