Skip to content

Commit 12c0a08

Browse files
committed
Decide on close-broadcasting commitment txn based on channel state
In a previous commit, we removed the ability for users to pick whether we will broadcast a commitment transaction on channel closure. However, that doesn't mean that there is no value in never broadcasting commitment transactions on channel closure. Rather, we use it to avoid broadcasting transactions which we know cannot confirm if the channel's funding transaction was not broadcasted. Here we make this relationship more formal by splitting the force-closure handling logic in `Channel` into the existing `ChannelContext::force_shutdown` as well as a new `ChannelContext::abandon_unfunded_chan`. `ChannelContext::force_shutdown` is the only public method, but it delegates to `abandon_unfunded_chan` based on the channel's state. This has the nice side effect of avoiding commitment transaction broadcasting when a batch open fails to get past the funding stage.
1 parent 1f46eab commit 12c0a08

File tree

4 files changed

+127
-80
lines changed

4 files changed

+127
-80
lines changed

lightning/src/events/mod.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -325,7 +325,9 @@ pub enum ClosureReason {
325325
/// Whether or not the latest transaction was broadcasted when the channel was force
326326
/// closed.
327327
///
328-
/// TODO: Update docs on when this will happen!
328+
/// This will be set to `Some(true)` for any channels closed after their funding
329+
/// transaction was (or might have been) broadcasted, and `Some(false)` for any channels
330+
/// closed prior to their funding transaction being broadcasted.
329331
///
330332
/// This will be `None` for objects generated or written by LDK 0.0.123 and
331333
/// earlier.

lightning/src/ln/channel.rs

Lines changed: 90 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1773,11 +1773,9 @@ where
17731773
}
17741774
}
17751775

1776-
pub fn force_shutdown(
1777-
&mut self, should_broadcast: bool, closure_reason: ClosureReason,
1778-
) -> ShutdownResult {
1776+
pub fn force_shutdown(&mut self, closure_reason: ClosureReason) -> ShutdownResult {
17791777
let (funding, context) = self.funding_and_context_mut();
1780-
context.force_shutdown(funding, should_broadcast, closure_reason)
1778+
context.force_shutdown(funding, closure_reason)
17811779
}
17821780

17831781
#[rustfmt::skip]
@@ -5305,20 +5303,88 @@ where
53055303
self.unbroadcasted_funding_txid(funding).filter(|_| self.is_batch_funding())
53065304
}
53075305

5308-
/// Gets the latest commitment transaction and any dependent transactions for relay (forcing
5309-
/// shutdown of this channel - no more calls into this Channel may be made afterwards except
5310-
/// those explicitly stated to be allowed after shutdown completes, eg some simple getters).
5311-
/// Also returns the list of payment_hashes for channels which we can safely fail backwards
5312-
/// immediately (others we will have to allow to time out).
5306+
/// Shuts down this channel (no more calls into this Channel may be made afterwards except
5307+
/// those explicitly stated to be alowed after shutdown, eg some simple getters).
5308+
///
5309+
/// Only allowed for channels which never been used (i.e. have never broadcasted their funding
5310+
/// transaction).
5311+
fn abandon_unfunded_chan(
5312+
&mut self, funding: &FundingScope, mut closure_reason: ClosureReason,
5313+
) -> ShutdownResult {
5314+
assert!(!matches!(self.channel_state, ChannelState::ShutdownComplete));
5315+
let pre_funding = matches!(self.channel_state, ChannelState::NegotiatingFunding(_));
5316+
let funded = matches!(self.channel_state, ChannelState::FundingNegotiated(_));
5317+
let awaiting_ready = matches!(self.channel_state, ChannelState::AwaitingChannelReady(_));
5318+
// TODO: allow pre-initial-monitor-storage but post-lock-in (is that a thing) closure?
5319+
assert!(pre_funding || funded || awaiting_ready);
5320+
5321+
let unbroadcasted_batch_funding_txid = self.unbroadcasted_batch_funding_txid(funding);
5322+
let unbroadcasted_funding_tx = self.unbroadcasted_funding(funding);
5323+
5324+
let monitor_update = if let Some(funding_txo) = funding.get_funding_txo() {
5325+
// If we haven't yet exchanged funding signatures (ie channel_state < AwaitingChannelReady),
5326+
// returning a channel monitor update here would imply a channel monitor update before
5327+
// we even registered the channel monitor to begin with, which is invalid.
5328+
// Thus, if we aren't actually at a point where we could conceivably broadcast the
5329+
// funding transaction, don't return a funding txo (which prevents providing the
5330+
// monitor update to the user, even if we return one).
5331+
// See test_duplicate_chan_id and test_pre_lockin_no_chan_closed_update for more.
5332+
if !self.channel_state.is_pre_funded_state() {
5333+
self.latest_monitor_update_id += 1;
5334+
let update = ChannelMonitorUpdate {
5335+
update_id: self.latest_monitor_update_id,
5336+
updates: vec![ChannelMonitorUpdateStep::ChannelForceClosed {
5337+
should_broadcast: false,
5338+
}],
5339+
channel_id: Some(self.channel_id()),
5340+
};
5341+
Some((self.get_counterparty_node_id(), funding_txo, self.channel_id(), update))
5342+
} else {
5343+
None
5344+
}
5345+
} else {
5346+
None
5347+
};
5348+
5349+
if let ClosureReason::HolderForceClosed { ref mut broadcasted_latest_txn, .. } =
5350+
&mut closure_reason
5351+
{
5352+
*broadcasted_latest_txn = Some(false);
5353+
}
5354+
5355+
self.channel_state = ChannelState::ShutdownComplete;
5356+
self.update_time_counter += 1;
5357+
ShutdownResult {
5358+
closure_reason,
5359+
monitor_update,
5360+
dropped_outbound_htlcs: Vec::new(),
5361+
unbroadcasted_batch_funding_txid,
5362+
channel_id: self.channel_id,
5363+
user_channel_id: self.user_id,
5364+
channel_capacity_satoshis: funding.get_value_satoshis(),
5365+
counterparty_node_id: self.counterparty_node_id,
5366+
unbroadcasted_funding_tx,
5367+
is_manual_broadcast: self.is_manual_broadcast,
5368+
channel_funding_txo: funding.get_funding_txo(),
5369+
last_local_balance_msat: funding.value_to_self_msat,
5370+
}
5371+
}
5372+
5373+
/// Shuts down this channel (no more calls into this Channel may be made afterwards except
5374+
/// those explicitly stated to be alowed after shutdown, eg some simple getters).
53135375
pub fn force_shutdown(
5314-
&mut self, funding: &FundingScope, should_broadcast: bool, closure_reason: ClosureReason,
5376+
&mut self, funding: &FundingScope, mut closure_reason: ClosureReason,
53155377
) -> ShutdownResult {
53165378
// Note that we MUST only generate a monitor update that indicates force-closure - we're
53175379
// called during initialization prior to the chain_monitor in the encompassing ChannelManager
53185380
// being fully configured in some cases. Thus, its likely any monitor events we generate will
53195381
// be delayed in being processed! See the docs for `ChannelManagerReadArgs` for more.
53205382
assert!(!matches!(self.channel_state, ChannelState::ShutdownComplete));
53215383

5384+
if !self.is_funding_broadcast() {
5385+
return self.abandon_unfunded_chan(funding, closure_reason);
5386+
}
5387+
53225388
// We go ahead and "free" any holding cell HTLCs or HTLCs we haven't yet committed to and
53235389
// return them to fail the payment.
53245390
let mut dropped_outbound_htlcs = Vec::with_capacity(self.holding_cell_htlc_updates.len());
@@ -5349,7 +5415,7 @@ where
53495415
let update = ChannelMonitorUpdate {
53505416
update_id: self.latest_monitor_update_id,
53515417
updates: vec![ChannelMonitorUpdateStep::ChannelForceClosed {
5352-
should_broadcast,
5418+
should_broadcast: true,
53535419
}],
53545420
channel_id: Some(self.channel_id()),
53555421
};
@@ -5363,6 +5429,12 @@ where
53635429
let unbroadcasted_batch_funding_txid = self.unbroadcasted_batch_funding_txid(funding);
53645430
let unbroadcasted_funding_tx = self.unbroadcasted_funding(funding);
53655431

5432+
if let ClosureReason::HolderForceClosed { ref mut broadcasted_latest_txn, .. } =
5433+
&mut closure_reason
5434+
{
5435+
*broadcasted_latest_txn = Some(true);
5436+
}
5437+
53665438
self.channel_state = ChannelState::ShutdownComplete;
53675439
self.update_time_counter += 1;
53685440
ShutdownResult {
@@ -6012,10 +6084,8 @@ where
60126084
&self.context
60136085
}
60146086

6015-
pub fn force_shutdown(
6016-
&mut self, closure_reason: ClosureReason, should_broadcast: bool,
6017-
) -> ShutdownResult {
6018-
self.context.force_shutdown(&self.funding, should_broadcast, closure_reason)
6087+
pub fn force_shutdown(&mut self, closure_reason: ClosureReason) -> ShutdownResult {
6088+
self.context.force_shutdown(&self.funding, closure_reason)
60196089
}
60206090

60216091
#[rustfmt::skip]
@@ -7889,7 +7959,7 @@ where
78897959
(closing_signed, signed_tx, shutdown_result)
78907960
}
78917961
Err(err) => {
7892-
let shutdown = self.context.force_shutdown(&self.funding, true, ClosureReason::ProcessingError {err: err.to_string()});
7962+
let shutdown = self.context.force_shutdown(&self.funding, ClosureReason::ProcessingError {err: err.to_string()});
78937963
(None, None, Some(shutdown))
78947964
}
78957965
}
@@ -10967,6 +11037,10 @@ impl<SP: Deref> OutboundV1Channel<SP>
1096711037
where
1096811038
SP::Target: SignerProvider,
1096911039
{
11040+
pub fn abandon_unfunded_chan(&mut self, closure_reason: ClosureReason) -> ShutdownResult {
11041+
self.context.abandon_unfunded_chan(&self.funding, closure_reason)
11042+
}
11043+
1097011044
#[allow(dead_code)] // TODO(dual_funding): Remove once opending V2 channels is enabled.
1097111045
#[rustfmt::skip]
1097211046
pub fn new<ES: Deref, F: Deref, L: Deref>(

lightning/src/ln/channelmanager.rs

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -3243,7 +3243,7 @@ macro_rules! convert_channel_err {
32433243
($self: ident, $peer_state: expr, $err: expr, $funded_channel: expr, $channel_id: expr, FUNDED_CHANNEL) => { {
32443244
let mut do_close = |reason| {
32453245
(
3246-
$funded_channel.force_shutdown(reason, true),
3246+
$funded_channel.force_shutdown(reason),
32473247
$self.get_channel_update_for_broadcast(&$funded_channel).ok(),
32483248
)
32493249
};
@@ -3253,7 +3253,7 @@ macro_rules! convert_channel_err {
32533253
convert_channel_err!($self, $peer_state, $err, $funded_channel, do_close, locked_close, $channel_id, _internal)
32543254
} };
32553255
($self: ident, $peer_state: expr, $err: expr, $channel: expr, $channel_id: expr, UNFUNDED_CHANNEL) => { {
3256-
let mut do_close = |reason| { ($channel.force_shutdown(true, reason), None) };
3256+
let mut do_close = |reason| { ($channel.force_shutdown(reason), None) };
32573257
let locked_close = |_, chan: &mut Channel<_>| { locked_close_channel!($self, chan.context(), UNFUNDED); };
32583258
convert_channel_err!($self, $peer_state, $err, $channel, do_close, locked_close, $channel_id, _internal)
32593259
} };
@@ -4430,6 +4430,8 @@ where
44304430
let _persistence_guard = PersistenceNotifierGuard::notify_on_drop(self);
44314431
log_debug!(self.logger,
44324432
"Force-closing channel, The error message sent to the peer : {}", error_message);
4433+
// No matter what value for `broadcast_latest_txn` we set here, `Channel` will override it
4434+
// and set the appropriate value.
44334435
let reason = ClosureReason::HolderForceClosed {
44344436
broadcasted_latest_txn: Some(true),
44354437
message: error_message,
@@ -5521,12 +5523,12 @@ where
55215523
let mut peer_state_lock = peer_state_mutex.lock().unwrap();
55225524
let peer_state = &mut *peer_state_lock;
55235525

5524-
macro_rules! close_chan { ($err: expr, $api_err: expr, $chan: expr) => { {
5526+
macro_rules! abandon_chan { ($err: expr, $api_err: expr, $chan: expr) => { {
55255527
let counterparty;
55265528
let err = if let ChannelError::Close((msg, reason)) = $err {
55275529
let channel_id = $chan.context.channel_id();
55285530
counterparty = $chan.context.get_counterparty_node_id();
5529-
let shutdown_res = $chan.context.force_shutdown(&$chan.funding, false, reason);
5531+
let shutdown_res = $chan.abandon_unfunded_chan(reason);
55305532
MsgHandleErrInternal::from_finish_shutdown(msg, channel_id, shutdown_res, None)
55315533
} else { unreachable!(); };
55325534

@@ -5546,7 +5548,7 @@ where
55465548
Err(err) => {
55475549
let chan_err = ChannelError::close(err.to_owned());
55485550
let api_err = APIError::APIMisuseError { err: err.to_owned() };
5549-
return close_chan!(chan_err, api_err, chan);
5551+
return abandon_chan!(chan_err, api_err, chan);
55505552
},
55515553
}
55525554

@@ -5556,7 +5558,7 @@ where
55565558
Ok(funding_msg) => (chan, funding_msg),
55575559
Err((mut chan, chan_err)) => {
55585560
let api_err = APIError::ChannelUnavailable { err: "Signer refused to sign the initial commitment transaction".to_owned() };
5559-
return close_chan!(chan_err, api_err, chan);
5561+
return abandon_chan!(chan_err, api_err, chan);
55605562
}
55615563
}
55625564
},
@@ -5585,7 +5587,7 @@ where
55855587
let chan_err = ChannelError::close(err.to_owned());
55865588
let api_err = APIError::APIMisuseError { err: err.to_owned() };
55875589
chan.unset_funding_info();
5588-
return close_chan!(chan_err, api_err, chan);
5590+
return abandon_chan!(chan_err, api_err, chan);
55895591
},
55905592
hash_map::Entry::Vacant(e) => {
55915593
if let Some(msg) = msg_opt {
@@ -14494,7 +14496,7 @@ where
1449414496
log_error!(logger, " The ChannelMonitor for channel {} is at counterparty commitment transaction number {} but the ChannelManager is at counterparty commitment transaction number {}.",
1449514497
&channel.context.channel_id(), monitor.get_cur_counterparty_commitment_number(), channel.get_cur_counterparty_commitment_transaction_number());
1449614498
}
14497-
let mut shutdown_result = channel.context.force_shutdown(&channel.funding, true, ClosureReason::OutdatedChannelManager);
14499+
let mut shutdown_result = channel.force_shutdown(ClosureReason::OutdatedChannelManager);
1449814500
if shutdown_result.unbroadcasted_batch_funding_txid.is_some() {
1449914501
return Err(DecodeError::InvalidValue);
1450014502
}
@@ -14567,7 +14569,6 @@ where
1456714569
// If we were persisted and shut down while the initial ChannelMonitor persistence
1456814570
// was in-progress, we never broadcasted the funding transaction and can still
1456914571
// safely discard the channel.
14570-
let _ = channel.context.force_shutdown(&channel.funding, false, ClosureReason::DisconnectedPeer);
1457114572
channel_closures.push_back((events::Event::ChannelClosed {
1457214573
channel_id: channel.context.channel_id(),
1457314574
user_channel_id: channel.context.get_user_id(),

lightning/src/ln/functional_tests.rs

Lines changed: 24 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -11418,14 +11418,10 @@ pub fn test_close_in_funding_batch() {
1141811418
_ => panic!("Unexpected message."),
1141911419
}
1142011420

11421-
// We broadcast the commitment transaction as part of the force-close.
11422-
{
11423-
let broadcasted_txs = nodes[0].tx_broadcaster.txn_broadcast();
11424-
assert_eq!(broadcasted_txs.len(), 1);
11425-
assert!(broadcasted_txs[0].compute_txid() != tx.compute_txid());
11426-
assert_eq!(broadcasted_txs[0].input.len(), 1);
11427-
assert_eq!(broadcasted_txs[0].input[0].previous_output.txid, tx.compute_txid());
11428-
}
11421+
// Because the funding was never broadcasted, we should never bother to broadcast the
11422+
// commitment transactions either.
11423+
let broadcasted_txs = nodes[0].tx_broadcaster.txn_broadcast();
11424+
assert_eq!(broadcasted_txs.len(), 0);
1142911425

1143011426
// All channels in the batch should close immediately.
1143111427
check_closed_events(
@@ -11524,15 +11520,10 @@ pub fn test_batch_funding_close_after_funding_signed() {
1152411520
_ => panic!("Unexpected message."),
1152511521
}
1152611522

11527-
// TODO: We shouldn't broadcast any commitment transaction here as we have not yet broadcasted
11528-
// the funding transaction.
11529-
{
11530-
let broadcasted_txs = nodes[0].tx_broadcaster.txn_broadcast();
11531-
assert_eq!(broadcasted_txs.len(), 2);
11532-
assert!(broadcasted_txs[0].compute_txid() != tx.compute_txid());
11533-
assert_eq!(broadcasted_txs[0].input.len(), 1);
11534-
assert_eq!(broadcasted_txs[0].input[0].previous_output.txid, tx.compute_txid());
11535-
}
11523+
// Because the funding was never broadcasted, we should never bother to broadcast the
11524+
// commitment transactions either.
11525+
let broadcasted_txs = nodes[0].tx_broadcaster.txn_broadcast();
11526+
assert_eq!(broadcasted_txs.len(), 0);
1153611527

1153711528
// All channels in the batch should close immediately.
1153811529
check_closed_events(
@@ -11559,7 +11550,8 @@ pub fn test_batch_funding_close_after_funding_signed() {
1155911550
assert!(nodes[0].node.list_channels().is_empty());
1156011551
}
1156111552

11562-
fn do_test_funding_and_commitment_tx_confirm_same_block(confirm_remote_commitment: bool) {
11553+
#[xtest(feature = "_externalize_tests")]
11554+
pub fn test_funding_and_commitment_tx_confirm_same_block() {
1156311555
// Tests that a node will forget the channel (when it only requires 1 confirmation) if the
1156411556
// funding and commitment transaction confirm in the same block.
1156511557
let chanmon_cfgs = create_chanmon_cfgs(2);
@@ -11573,6 +11565,9 @@ fn do_test_funding_and_commitment_tx_confirm_same_block(confirm_remote_commitmen
1157311565
);
1157411566
let mut nodes = create_network(2, &node_cfgs, &node_chanmgrs);
1157511567

11568+
let node_a_id = nodes[0].node.get_our_node_id();
11569+
let node_b_id = nodes[1].node.get_our_node_id();
11570+
1157611571
let funding_tx = create_chan_between_nodes_with_value_init(&nodes[0], &nodes[1], 1_000_000, 0);
1157711572
let chan_id = ChannelId::v1_from_funding_outpoint(chain::transaction::OutPoint {
1157811573
txid: funding_tx.compute_txid(),
@@ -11582,55 +11577,30 @@ fn do_test_funding_and_commitment_tx_confirm_same_block(confirm_remote_commitmen
1158211577
assert_eq!(nodes[0].node.list_channels().len(), 1);
1158311578
assert_eq!(nodes[1].node.list_channels().len(), 1);
1158411579

11585-
let (closing_node, other_node) =
11586-
if confirm_remote_commitment { (&nodes[1], &nodes[0]) } else { (&nodes[0], &nodes[1]) };
11587-
let closing_node_id = closing_node.node.get_our_node_id();
11588-
let other_node_id = other_node.node.get_our_node_id();
11589-
11590-
let message = "Channel force-closed".to_owned();
11591-
closing_node
11592-
.node
11593-
.force_close_broadcasting_latest_txn(&chan_id, &other_node_id, message.clone())
11594-
.unwrap();
11595-
let mut msg_events = closing_node.node.get_and_clear_pending_msg_events();
11596-
assert_eq!(msg_events.len(), 1);
11597-
match msg_events.pop().unwrap() {
11598-
MessageSendEvent::HandleError {
11599-
action: msgs::ErrorAction::SendErrorMessage { .. },
11600-
..
11601-
} => {},
11602-
_ => panic!("Unexpected event"),
11603-
}
11604-
check_added_monitors(closing_node, 1);
11605-
let reason = ClosureReason::HolderForceClosed { broadcasted_latest_txn: Some(true), message };
11606-
check_closed_event(closing_node, 1, reason, false, &[other_node_id], 1_000_000);
11607-
1160811580
let commitment_tx = {
11609-
let mut txn = closing_node.tx_broadcaster.txn_broadcast();
11581+
let mon = get_monitor!(nodes[0], chan_id);
11582+
let mut txn = mon.unsafe_get_latest_holder_commitment_txn(&nodes[0].logger);
1161011583
assert_eq!(txn.len(), 1);
11611-
let commitment_tx = txn.pop().unwrap();
11612-
check_spends!(commitment_tx, funding_tx);
11613-
commitment_tx
11584+
txn.pop().unwrap()
1161411585
};
1161511586

1161611587
mine_transactions(&nodes[0], &[&funding_tx, &commitment_tx]);
1161711588
mine_transactions(&nodes[1], &[&funding_tx, &commitment_tx]);
1161811589

11619-
check_closed_broadcast(other_node, 1, true);
11620-
check_added_monitors(other_node, 1);
11590+
check_closed_broadcast(&nodes[0], 1, true);
11591+
check_added_monitors(&nodes[0], 1);
11592+
let reason = ClosureReason::CommitmentTxConfirmed;
11593+
check_closed_event(&nodes[0], 1, reason, false, &[node_b_id], 1_000_000);
11594+
11595+
check_closed_broadcast(&nodes[1], 1, true);
11596+
check_added_monitors(&nodes[1], 1);
1162111597
let reason = ClosureReason::CommitmentTxConfirmed;
11622-
check_closed_event(other_node, 1, reason, false, &[closing_node_id], 1_000_000);
11598+
check_closed_event(&nodes[1], 1, reason, false, &[node_a_id], 1_000_000);
1162311599

1162411600
assert!(nodes[0].node.list_channels().is_empty());
1162511601
assert!(nodes[1].node.list_channels().is_empty());
1162611602
}
1162711603

11628-
#[xtest(feature = "_externalize_tests")]
11629-
pub fn test_funding_and_commitment_tx_confirm_same_block() {
11630-
do_test_funding_and_commitment_tx_confirm_same_block(false);
11631-
do_test_funding_and_commitment_tx_confirm_same_block(true);
11632-
}
11633-
1163411604
#[xtest(feature = "_externalize_tests")]
1163511605
pub fn test_accept_inbound_channel_errors_queued() {
1163611606
// For manually accepted inbound channels, tests that a close error is correctly handled

0 commit comments

Comments
 (0)