Skip to content

Commit c422e4b

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 e6ea987 commit c422e4b

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
@@ -327,7 +327,9 @@ pub enum ClosureReason {
327327
/// Whether or not the latest transaction was broadcasted when the channel was force
328328
/// closed.
329329
///
330-
/// TODO: Update docs on when this will happen!
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.

lightning/src/ln/channel.rs

Lines changed: 90 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1775,11 +1775,9 @@ where
17751775
}
17761776
}
17771777

1778-
pub fn force_shutdown(
1779-
&mut self, should_broadcast: bool, closure_reason: ClosureReason,
1780-
) -> ShutdownResult {
1778+
pub fn force_shutdown(&mut self, closure_reason: ClosureReason) -> ShutdownResult {
17811779
let (funding, context) = self.funding_and_context_mut();
1782-
context.force_shutdown(funding, should_broadcast, closure_reason)
1780+
context.force_shutdown(funding, closure_reason)
17831781
}
17841782

17851783
#[rustfmt::skip]
@@ -5340,20 +5338,88 @@ where
53405338
self.unbroadcasted_funding_txid(funding).filter(|_| self.is_batch_funding())
53415339
}
53425340

5343-
/// Gets the latest commitment transaction and any dependent transactions for relay (forcing
5344-
/// shutdown of this channel - no more calls into this Channel may be made afterwards except
5345-
/// those explicitly stated to be allowed after shutdown completes, eg some simple getters).
5346-
/// Also returns the list of payment_hashes for channels which we can safely fail backwards
5347-
/// immediately (others we will have to allow to time out).
5341+
/// Shuts down this channel (no more calls into this Channel may be made afterwards except
5342+
/// those explicitly stated to be alowed after shutdown, eg some simple getters).
5343+
///
5344+
/// Only allowed for channels which never been used (i.e. have never broadcasted their funding
5345+
/// transaction).
5346+
fn abandon_unfunded_chan(
5347+
&mut self, funding: &FundingScope, mut closure_reason: ClosureReason,
5348+
) -> ShutdownResult {
5349+
assert!(!matches!(self.channel_state, ChannelState::ShutdownComplete));
5350+
let pre_funding = matches!(self.channel_state, ChannelState::NegotiatingFunding(_));
5351+
let funded = matches!(self.channel_state, ChannelState::FundingNegotiated(_));
5352+
let awaiting_ready = matches!(self.channel_state, ChannelState::AwaitingChannelReady(_));
5353+
// TODO: allow pre-initial-monitor-storage but post-lock-in (is that a thing) closure?
5354+
assert!(pre_funding || funded || awaiting_ready);
5355+
5356+
let unbroadcasted_batch_funding_txid = self.unbroadcasted_batch_funding_txid(funding);
5357+
let unbroadcasted_funding_tx = self.unbroadcasted_funding(funding);
5358+
5359+
let monitor_update = if let Some(funding_txo) = funding.get_funding_txo() {
5360+
// If we haven't yet exchanged funding signatures (ie channel_state < AwaitingChannelReady),
5361+
// returning a channel monitor update here would imply a channel monitor update before
5362+
// we even registered the channel monitor to begin with, which is invalid.
5363+
// Thus, if we aren't actually at a point where we could conceivably broadcast the
5364+
// funding transaction, don't return a funding txo (which prevents providing the
5365+
// monitor update to the user, even if we return one).
5366+
// See test_duplicate_chan_id and test_pre_lockin_no_chan_closed_update for more.
5367+
if !self.channel_state.is_pre_funded_state() {
5368+
self.latest_monitor_update_id += 1;
5369+
let update = ChannelMonitorUpdate {
5370+
update_id: self.latest_monitor_update_id,
5371+
updates: vec![ChannelMonitorUpdateStep::ChannelForceClosed {
5372+
should_broadcast: false,
5373+
}],
5374+
channel_id: Some(self.channel_id()),
5375+
};
5376+
Some((self.get_counterparty_node_id(), funding_txo, self.channel_id(), update))
5377+
} else {
5378+
None
5379+
}
5380+
} else {
5381+
None
5382+
};
5383+
5384+
if let ClosureReason::HolderForceClosed { ref mut broadcasted_latest_txn, .. } =
5385+
&mut closure_reason
5386+
{
5387+
*broadcasted_latest_txn = Some(false);
5388+
}
5389+
5390+
self.channel_state = ChannelState::ShutdownComplete;
5391+
self.update_time_counter += 1;
5392+
ShutdownResult {
5393+
closure_reason,
5394+
monitor_update,
5395+
dropped_outbound_htlcs: Vec::new(),
5396+
unbroadcasted_batch_funding_txid,
5397+
channel_id: self.channel_id,
5398+
user_channel_id: self.user_id,
5399+
channel_capacity_satoshis: funding.get_value_satoshis(),
5400+
counterparty_node_id: self.counterparty_node_id,
5401+
unbroadcasted_funding_tx,
5402+
is_manual_broadcast: self.is_manual_broadcast,
5403+
channel_funding_txo: funding.get_funding_txo(),
5404+
last_local_balance_msat: funding.value_to_self_msat,
5405+
}
5406+
}
5407+
5408+
/// Shuts down this channel (no more calls into this Channel may be made afterwards except
5409+
/// those explicitly stated to be alowed after shutdown, eg some simple getters).
53485410
pub fn force_shutdown(
5349-
&mut self, funding: &FundingScope, should_broadcast: bool, closure_reason: ClosureReason,
5411+
&mut self, funding: &FundingScope, mut closure_reason: ClosureReason,
53505412
) -> ShutdownResult {
53515413
// Note that we MUST only generate a monitor update that indicates force-closure - we're
53525414
// called during initialization prior to the chain_monitor in the encompassing ChannelManager
53535415
// being fully configured in some cases. Thus, its likely any monitor events we generate will
53545416
// be delayed in being processed! See the docs for `ChannelManagerReadArgs` for more.
53555417
assert!(!matches!(self.channel_state, ChannelState::ShutdownComplete));
53565418

5419+
if !self.is_funding_broadcast() {
5420+
return self.abandon_unfunded_chan(funding, closure_reason);
5421+
}
5422+
53575423
// We go ahead and "free" any holding cell HTLCs or HTLCs we haven't yet committed to and
53585424
// return them to fail the payment.
53595425
let mut dropped_outbound_htlcs = Vec::with_capacity(self.holding_cell_htlc_updates.len());
@@ -5384,7 +5450,7 @@ where
53845450
let update = ChannelMonitorUpdate {
53855451
update_id: self.latest_monitor_update_id,
53865452
updates: vec![ChannelMonitorUpdateStep::ChannelForceClosed {
5387-
should_broadcast,
5453+
should_broadcast: true,
53885454
}],
53895455
channel_id: Some(self.channel_id()),
53905456
};
@@ -5398,6 +5464,12 @@ where
53985464
let unbroadcasted_batch_funding_txid = self.unbroadcasted_batch_funding_txid(funding);
53995465
let unbroadcasted_funding_tx = self.unbroadcasted_funding(funding);
54005466

5467+
if let ClosureReason::HolderForceClosed { ref mut broadcasted_latest_txn, .. } =
5468+
&mut closure_reason
5469+
{
5470+
*broadcasted_latest_txn = Some(true);
5471+
}
5472+
54015473
self.channel_state = ChannelState::ShutdownComplete;
54025474
self.update_time_counter += 1;
54035475
ShutdownResult {
@@ -6047,10 +6119,8 @@ where
60476119
&self.context
60486120
}
60496121

6050-
pub fn force_shutdown(
6051-
&mut self, closure_reason: ClosureReason, should_broadcast: bool,
6052-
) -> ShutdownResult {
6053-
self.context.force_shutdown(&self.funding, should_broadcast, closure_reason)
6122+
pub fn force_shutdown(&mut self, closure_reason: ClosureReason) -> ShutdownResult {
6123+
self.context.force_shutdown(&self.funding, closure_reason)
60546124
}
60556125

60566126
#[rustfmt::skip]
@@ -8124,7 +8194,7 @@ where
81248194
(closing_signed, signed_tx, shutdown_result)
81258195
}
81268196
Err(err) => {
8127-
let shutdown = self.context.force_shutdown(&self.funding, true, ClosureReason::ProcessingError {err: err.to_string()});
8197+
let shutdown = self.context.force_shutdown(&self.funding, ClosureReason::ProcessingError {err: err.to_string()});
81288198
(None, None, Some(shutdown))
81298199
}
81308200
}
@@ -11200,6 +11270,10 @@ impl<SP: Deref> OutboundV1Channel<SP>
1120011270
where
1120111271
SP::Target: SignerProvider,
1120211272
{
11273+
pub fn abandon_unfunded_chan(&mut self, closure_reason: ClosureReason) -> ShutdownResult {
11274+
self.context.abandon_unfunded_chan(&self.funding, closure_reason)
11275+
}
11276+
1120311277
#[allow(dead_code)] // TODO(dual_funding): Remove once opending V2 channels is enabled.
1120411278
#[rustfmt::skip]
1120511279
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
@@ -3245,7 +3245,7 @@ macro_rules! convert_channel_err {
32453245
($self: ident, $peer_state: expr, $err: expr, $funded_channel: expr, $channel_id: expr, FUNDED_CHANNEL) => { {
32463246
let mut do_close = |reason| {
32473247
(
3248-
$funded_channel.force_shutdown(reason, true),
3248+
$funded_channel.force_shutdown(reason),
32493249
$self.get_channel_update_for_broadcast(&$funded_channel).ok(),
32503250
)
32513251
};
@@ -3255,7 +3255,7 @@ macro_rules! convert_channel_err {
32553255
convert_channel_err!($self, $peer_state, $err, $funded_channel, do_close, locked_close, $channel_id, _internal)
32563256
} };
32573257
($self: ident, $peer_state: expr, $err: expr, $channel: expr, $channel_id: expr, UNFUNDED_CHANNEL) => { {
3258-
let mut do_close = |reason| { ($channel.force_shutdown(true, reason), None) };
3258+
let mut do_close = |reason| { ($channel.force_shutdown(reason), None) };
32593259
let locked_close = |_, chan: &mut Channel<_>| { locked_close_channel!($self, chan.context(), UNFUNDED); };
32603260
convert_channel_err!($self, $peer_state, $err, $channel, do_close, locked_close, $channel_id, _internal)
32613261
} };
@@ -4432,6 +4432,8 @@ where
44324432
let _persistence_guard = PersistenceNotifierGuard::notify_on_drop(self);
44334433
log_debug!(self.logger,
44344434
"Force-closing channel, The error message sent to the peer : {}", error_message);
4435+
// No matter what value for `broadcast_latest_txn` we set here, `Channel` will override it
4436+
// and set the appropriate value.
44354437
let reason = ClosureReason::HolderForceClosed {
44364438
broadcasted_latest_txn: Some(true),
44374439
message: error_message,
@@ -5547,12 +5549,12 @@ where
55475549
let mut peer_state_lock = peer_state_mutex.lock().unwrap();
55485550
let peer_state = &mut *peer_state_lock;
55495551

5550-
macro_rules! close_chan { ($err: expr, $api_err: expr, $chan: expr) => { {
5552+
macro_rules! abandon_chan { ($err: expr, $api_err: expr, $chan: expr) => { {
55515553
let counterparty;
55525554
let err = if let ChannelError::Close((msg, reason)) = $err {
55535555
let channel_id = $chan.context.channel_id();
55545556
counterparty = $chan.context.get_counterparty_node_id();
5555-
let shutdown_res = $chan.context.force_shutdown(&$chan.funding, false, reason);
5557+
let shutdown_res = $chan.abandon_unfunded_chan(reason);
55565558
MsgHandleErrInternal::from_finish_shutdown(msg, channel_id, shutdown_res, None)
55575559
} else { unreachable!(); };
55585560

@@ -5572,7 +5574,7 @@ where
55725574
Err(err) => {
55735575
let chan_err = ChannelError::close(err.to_owned());
55745576
let api_err = APIError::APIMisuseError { err: err.to_owned() };
5575-
return close_chan!(chan_err, api_err, chan);
5577+
return abandon_chan!(chan_err, api_err, chan);
55765578
},
55775579
}
55785580

@@ -5582,7 +5584,7 @@ where
55825584
Ok(funding_msg) => (chan, funding_msg),
55835585
Err((mut chan, chan_err)) => {
55845586
let api_err = APIError::ChannelUnavailable { err: "Signer refused to sign the initial commitment transaction".to_owned() };
5585-
return close_chan!(chan_err, api_err, chan);
5587+
return abandon_chan!(chan_err, api_err, chan);
55865588
}
55875589
}
55885590
},
@@ -5611,7 +5613,7 @@ where
56115613
let chan_err = ChannelError::close(err.to_owned());
56125614
let api_err = APIError::APIMisuseError { err: err.to_owned() };
56135615
chan.unset_funding_info();
5614-
return close_chan!(chan_err, api_err, chan);
5616+
return abandon_chan!(chan_err, api_err, chan);
56155617
},
56165618
hash_map::Entry::Vacant(e) => {
56175619
if let Some(msg) = msg_opt {
@@ -14629,7 +14631,7 @@ where
1462914631
log_error!(logger, " The ChannelMonitor for channel {} is at counterparty commitment transaction number {} but the ChannelManager is at counterparty commitment transaction number {}.",
1463014632
&channel.context.channel_id(), monitor.get_cur_counterparty_commitment_number(), channel.get_cur_counterparty_commitment_transaction_number());
1463114633
}
14632-
let mut shutdown_result = channel.context.force_shutdown(&channel.funding, true, ClosureReason::OutdatedChannelManager);
14634+
let mut shutdown_result = channel.force_shutdown(ClosureReason::OutdatedChannelManager);
1463314635
if shutdown_result.unbroadcasted_batch_funding_txid.is_some() {
1463414636
return Err(DecodeError::InvalidValue);
1463514637
}
@@ -14702,7 +14704,6 @@ where
1470214704
// If we were persisted and shut down while the initial ChannelMonitor persistence
1470314705
// was in-progress, we never broadcasted the funding transaction and can still
1470414706
// safely discard the channel.
14705-
let _ = channel.context.force_shutdown(&channel.funding, false, ClosureReason::DisconnectedPeer);
1470614707
channel_closures.push_back((events::Event::ChannelClosed {
1470714708
channel_id: channel.context.channel_id(),
1470814709
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)