Skip to content

Commit 90f24a6

Browse files
wpaulinormalonson
andcommitted
Refactor commitment broadcast to always go through OnchainTxHandler
Currently, our holder commitment broadcast only goes through the `OnchainTxHandler` for anchor outputs channels because we can actually bump the commitment transaction fees with it. For non-anchor outputs channels, we would just broadcast once directly via the `ChannelForceClosed` monitor update, without going through the `OnchainTxHandler`. As we add support for async signing, we need to be tolerable to signing failures. A signing failure of our holder commitment will currently panic, but once the panic is removed, we must be able to retry signing once the signer is available. We can easily achieve this via the existing `OnchainTxHandler::rebroadcast_pending_claims`, but this requires that we first queue our holder commitment as a claim. This commit ensures we do so everywhere we need to broadcast a holder commitment transaction, regardless of the channel type. Co-authored-by: Rachel Malonson <[email protected]>
1 parent 7dcee4f commit 90f24a6

File tree

5 files changed

+160
-130
lines changed

5 files changed

+160
-130
lines changed

lightning/src/chain/channelmonitor.rs

Lines changed: 56 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -2659,18 +2659,59 @@ impl<Signer: WriteableEcdsaChannelSigner> ChannelMonitorImpl<Signer> {
26592659
}
26602660
}
26612661

2662-
fn broadcast_latest_holder_commitment_txn<B: Deref, L: Deref>(&mut self, broadcaster: &B, logger: &WithChannelMonitor<L>)
2663-
where B::Target: BroadcasterInterface,
2664-
L::Target: Logger,
2665-
{
2666-
let commit_txs = self.get_latest_holder_commitment_txn(logger);
2667-
let mut txs = vec![];
2668-
for tx in commit_txs.iter() {
2669-
log_info!(logger, "Broadcasting local {}", log_tx!(tx));
2670-
txs.push(tx);
2671-
}
2672-
broadcaster.broadcast_transactions(&txs);
2662+
fn generate_claimable_outpoints_and_watch_outputs(&mut self) -> (Vec<PackageTemplate>, Vec<TransactionOutputs>) {
2663+
let funding_outp = HolderFundingOutput::build(
2664+
self.funding_redeemscript.clone(),
2665+
self.channel_value_satoshis,
2666+
self.onchain_tx_handler.channel_type_features().clone()
2667+
);
2668+
let commitment_package = PackageTemplate::build_package(
2669+
self.funding_info.0.txid.clone(), self.funding_info.0.index as u32,
2670+
PackageSolvingData::HolderFundingOutput(funding_outp),
2671+
self.best_block.height(), self.best_block.height()
2672+
);
2673+
let mut claimable_outpoints = vec![commitment_package];
26732674
self.pending_monitor_events.push(MonitorEvent::HolderForceClosed(self.funding_info.0));
2675+
// Although we aren't signing the transaction directly here, the transaction will be signed
2676+
// in the claim that is queued to OnchainTxHandler. We set holder_tx_signed here to reject
2677+
// new channel updates.
2678+
self.holder_tx_signed = true;
2679+
let mut watch_outputs = Vec::new();
2680+
// We can't broadcast our HTLC transactions while the commitment transaction is
2681+
// unconfirmed. We'll delay doing so until we detect the confirmed commitment in
2682+
// `transactions_confirmed`.
2683+
if !self.onchain_tx_handler.channel_type_features().supports_anchors_zero_fee_htlc_tx() {
2684+
// Because we're broadcasting a commitment transaction, we should construct the package
2685+
// assuming it gets confirmed in the next block. Sadly, we have code which considers
2686+
// "not yet confirmed" things as discardable, so we cannot do that here.
2687+
let (mut new_outpoints, _) = self.get_broadcasted_holder_claims(
2688+
&self.current_holder_commitment_tx, self.best_block.height()
2689+
);
2690+
let unsigned_commitment_tx = self.onchain_tx_handler.get_unsigned_holder_commitment_tx();
2691+
let new_outputs = self.get_broadcasted_holder_watch_outputs(
2692+
&self.current_holder_commitment_tx, &unsigned_commitment_tx
2693+
);
2694+
if !new_outputs.is_empty() {
2695+
watch_outputs.push((self.current_holder_commitment_tx.txid.clone(), new_outputs));
2696+
}
2697+
claimable_outpoints.append(&mut new_outpoints);
2698+
}
2699+
(claimable_outpoints, watch_outputs)
2700+
}
2701+
2702+
pub(crate) fn queue_latest_holder_commitment_txn_for_broadcast<B: Deref, F: Deref, L: Deref>(
2703+
&mut self, broadcaster: &B, fee_estimator: &LowerBoundedFeeEstimator<F>, logger: &WithChannelMonitor<L>
2704+
)
2705+
where
2706+
B::Target: BroadcasterInterface,
2707+
F::Target: FeeEstimator,
2708+
L::Target: Logger,
2709+
{
2710+
let (claimable_outpoints, _) = self.generate_claimable_outpoints_and_watch_outputs();
2711+
self.onchain_tx_handler.update_claims_view_from_requests(
2712+
claimable_outpoints, self.best_block.height(), self.best_block.height(), broadcaster,
2713+
fee_estimator, logger
2714+
);
26742715
}
26752716

26762717
fn update_monitor<B: Deref, F: Deref, L: Deref>(
@@ -2760,26 +2801,7 @@ impl<Signer: WriteableEcdsaChannelSigner> ChannelMonitorImpl<Signer> {
27602801
log_trace!(logger, "Avoiding commitment broadcast, already detected confirmed spend onchain");
27612802
continue;
27622803
}
2763-
self.broadcast_latest_holder_commitment_txn(broadcaster, logger);
2764-
// If the channel supports anchor outputs, we'll need to emit an external
2765-
// event to be consumed such that a child transaction is broadcast with a
2766-
// high enough feerate for the parent commitment transaction to confirm.
2767-
if self.onchain_tx_handler.channel_type_features().supports_anchors_zero_fee_htlc_tx() {
2768-
let funding_output = HolderFundingOutput::build(
2769-
self.funding_redeemscript.clone(), self.channel_value_satoshis,
2770-
self.onchain_tx_handler.channel_type_features().clone(),
2771-
);
2772-
let best_block_height = self.best_block.height();
2773-
let commitment_package = PackageTemplate::build_package(
2774-
self.funding_info.0.txid.clone(), self.funding_info.0.index as u32,
2775-
PackageSolvingData::HolderFundingOutput(funding_output),
2776-
best_block_height, best_block_height
2777-
);
2778-
self.onchain_tx_handler.update_claims_view_from_requests(
2779-
vec![commitment_package], best_block_height, best_block_height,
2780-
broadcaster, &bounded_fee_estimator, logger,
2781-
);
2782-
}
2804+
self.queue_latest_holder_commitment_txn_for_broadcast(broadcaster, &bounded_fee_estimator, logger);
27832805
} else if !self.holder_tx_signed {
27842806
log_error!(logger, "WARNING: You have a potentially-unsafe holder commitment transaction available to broadcast");
27852807
log_error!(logger, " in channel monitor for channel {}!", &self.funding_info.0.to_channel_id());
@@ -3689,29 +3711,9 @@ impl<Signer: WriteableEcdsaChannelSigner> ChannelMonitorImpl<Signer> {
36893711

36903712
let should_broadcast = self.should_broadcast_holder_commitment_txn(logger);
36913713
if should_broadcast {
3692-
let funding_outp = HolderFundingOutput::build(self.funding_redeemscript.clone(), self.channel_value_satoshis, self.onchain_tx_handler.channel_type_features().clone());
3693-
let commitment_package = PackageTemplate::build_package(self.funding_info.0.txid.clone(), self.funding_info.0.index as u32, PackageSolvingData::HolderFundingOutput(funding_outp), self.best_block.height(), self.best_block.height());
3694-
claimable_outpoints.push(commitment_package);
3695-
self.pending_monitor_events.push(MonitorEvent::HolderForceClosed(self.funding_info.0));
3696-
// Although we aren't signing the transaction directly here, the transaction will be signed
3697-
// in the claim that is queued to OnchainTxHandler. We set holder_tx_signed here to reject
3698-
// new channel updates.
3699-
self.holder_tx_signed = true;
3700-
// We can't broadcast our HTLC transactions while the commitment transaction is
3701-
// unconfirmed. We'll delay doing so until we detect the confirmed commitment in
3702-
// `transactions_confirmed`.
3703-
if !self.onchain_tx_handler.channel_type_features().supports_anchors_zero_fee_htlc_tx() {
3704-
// Because we're broadcasting a commitment transaction, we should construct the package
3705-
// assuming it gets confirmed in the next block. Sadly, we have code which considers
3706-
// "not yet confirmed" things as discardable, so we cannot do that here.
3707-
let (mut new_outpoints, _) = self.get_broadcasted_holder_claims(&self.current_holder_commitment_tx, self.best_block.height());
3708-
let unsigned_commitment_tx = self.onchain_tx_handler.get_unsigned_holder_commitment_tx();
3709-
let new_outputs = self.get_broadcasted_holder_watch_outputs(&self.current_holder_commitment_tx, &unsigned_commitment_tx);
3710-
if !new_outputs.is_empty() {
3711-
watch_outputs.push((self.current_holder_commitment_tx.txid.clone(), new_outputs));
3712-
}
3713-
claimable_outpoints.append(&mut new_outpoints);
3714-
}
3714+
let (mut new_outpoints, mut new_outputs) = self.generate_claimable_outpoints_and_watch_outputs();
3715+
claimable_outpoints.append(&mut new_outpoints);
3716+
watch_outputs.append(&mut new_outputs);
37153717
}
37163718

37173719
// Find which on-chain events have reached their confirmation threshold.

lightning/src/ln/functional_tests.rs

Lines changed: 41 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -2273,9 +2273,15 @@ fn channel_monitor_network_test() {
22732273
nodes[1].node.force_close_broadcasting_latest_txn(&chan_1.2, &nodes[0].node.get_our_node_id()).unwrap();
22742274
check_added_monitors!(nodes[1], 1);
22752275
check_closed_broadcast!(nodes[1], true);
2276+
check_closed_event!(nodes[1], 1, ClosureReason::HolderForceClosed, [nodes[0].node.get_our_node_id()], 100000);
22762277
{
22772278
let mut node_txn = test_txn_broadcast(&nodes[1], &chan_1, None, HTLCType::NONE);
22782279
assert_eq!(node_txn.len(), 1);
2280+
mine_transaction(&nodes[1], &node_txn[0]);
2281+
if nodes[1].connect_style.borrow().updates_best_block_first() {
2282+
let _ = nodes[1].tx_broadcaster.txn_broadcast();
2283+
}
2284+
22792285
mine_transaction(&nodes[0], &node_txn[0]);
22802286
check_added_monitors!(nodes[0], 1);
22812287
test_txn_broadcast(&nodes[0], &chan_1, Some(node_txn[0].clone()), HTLCType::NONE);
@@ -2284,7 +2290,6 @@ fn channel_monitor_network_test() {
22842290
assert_eq!(nodes[0].node.list_channels().len(), 0);
22852291
assert_eq!(nodes[1].node.list_channels().len(), 1);
22862292
check_closed_event!(nodes[0], 1, ClosureReason::CommitmentTxConfirmed, [nodes[1].node.get_our_node_id()], 100000);
2287-
check_closed_event!(nodes[1], 1, ClosureReason::HolderForceClosed, [nodes[0].node.get_our_node_id()], 100000);
22882293

22892294
// One pending HTLC is discarded by the force-close:
22902295
let (payment_preimage_1, payment_hash_1, ..) = route_payment(&nodes[1], &[&nodes[2], &nodes[3]], 3_000_000);
@@ -3556,7 +3561,7 @@ fn test_htlc_ignore_latest_remote_commitment() {
35563561
// connect_style.
35573562
return;
35583563
}
3559-
create_announced_chan_between_nodes(&nodes, 0, 1);
3564+
let funding_tx = create_announced_chan_between_nodes(&nodes, 0, 1).3;
35603565

35613566
route_payment(&nodes[0], &[&nodes[1]], 10000000);
35623567
nodes[0].node.force_close_broadcasting_latest_txn(&nodes[0].node.list_channels()[0].channel_id, &nodes[1].node.get_our_node_id()).unwrap();
@@ -3565,11 +3570,12 @@ fn test_htlc_ignore_latest_remote_commitment() {
35653570
check_added_monitors!(nodes[0], 1);
35663571
check_closed_event!(nodes[0], 1, ClosureReason::HolderForceClosed, [nodes[1].node.get_our_node_id()], 100000);
35673572

3568-
let node_txn = nodes[0].tx_broadcaster.txn_broadcasted.lock().unwrap().split_off(0);
3569-
assert_eq!(node_txn.len(), 3);
3570-
assert_eq!(node_txn[0].txid(), node_txn[1].txid());
3573+
let node_txn = nodes[0].tx_broadcaster.unique_txn_broadcast();
3574+
assert_eq!(node_txn.len(), 2);
3575+
check_spends!(node_txn[0], funding_tx);
3576+
check_spends!(node_txn[1], node_txn[0]);
35713577

3572-
let block = create_dummy_block(nodes[1].best_block_hash(), 42, vec![node_txn[0].clone(), node_txn[1].clone()]);
3578+
let block = create_dummy_block(nodes[1].best_block_hash(), 42, vec![node_txn[0].clone()]);
35733579
connect_block(&nodes[1], &block);
35743580
check_closed_broadcast!(nodes[1], true);
35753581
check_added_monitors!(nodes[1], 1);
@@ -3626,7 +3632,7 @@ fn test_force_close_fail_back() {
36263632
check_closed_broadcast!(nodes[2], true);
36273633
check_added_monitors!(nodes[2], 1);
36283634
check_closed_event!(nodes[2], 1, ClosureReason::HolderForceClosed, [nodes[1].node.get_our_node_id()], 100000);
3629-
let tx = {
3635+
let commitment_tx = {
36303636
let mut node_txn = nodes[2].tx_broadcaster.txn_broadcasted.lock().unwrap();
36313637
// Note that we don't bother broadcasting the HTLC-Success transaction here as we don't
36323638
// have a use for it unless nodes[2] learns the preimage somehow, the funds will go
@@ -3635,7 +3641,7 @@ fn test_force_close_fail_back() {
36353641
node_txn.remove(0)
36363642
};
36373643

3638-
mine_transaction(&nodes[1], &tx);
3644+
mine_transaction(&nodes[1], &commitment_tx);
36393645

36403646
// Note no UpdateHTLCs event here from nodes[1] to nodes[0]!
36413647
check_closed_broadcast!(nodes[1], true);
@@ -3647,15 +3653,16 @@ fn test_force_close_fail_back() {
36473653
get_monitor!(nodes[2], payment_event.commitment_msg.channel_id)
36483654
.provide_payment_preimage(&our_payment_hash, &our_payment_preimage, &node_cfgs[2].tx_broadcaster, &LowerBoundedFeeEstimator::new(node_cfgs[2].fee_estimator), &node_cfgs[2].logger);
36493655
}
3650-
mine_transaction(&nodes[2], &tx);
3651-
let node_txn = nodes[2].tx_broadcaster.txn_broadcasted.lock().unwrap();
3652-
assert_eq!(node_txn.len(), 1);
3653-
assert_eq!(node_txn[0].input.len(), 1);
3654-
assert_eq!(node_txn[0].input[0].previous_output.txid, tx.txid());
3655-
assert_eq!(node_txn[0].lock_time, LockTime::ZERO); // Must be an HTLC-Success
3656-
assert_eq!(node_txn[0].input[0].witness.len(), 5); // Must be an HTLC-Success
3656+
mine_transaction(&nodes[2], &commitment_tx);
3657+
let mut node_txn = nodes[2].tx_broadcaster.txn_broadcast();
3658+
assert_eq!(node_txn.len(), if nodes[2].connect_style.borrow().updates_best_block_first() { 2 } else { 1 });
3659+
let htlc_tx = node_txn.pop().unwrap();
3660+
assert_eq!(htlc_tx.input.len(), 1);
3661+
assert_eq!(htlc_tx.input[0].previous_output.txid, commitment_tx.txid());
3662+
assert_eq!(htlc_tx.lock_time, LockTime::ZERO); // Must be an HTLC-Success
3663+
assert_eq!(htlc_tx.input[0].witness.len(), 5); // Must be an HTLC-Success
36573664

3658-
check_spends!(node_txn[0], tx);
3665+
check_spends!(htlc_tx, commitment_tx);
36593666
}
36603667

36613668
#[test]
@@ -8881,7 +8888,12 @@ fn do_test_onchain_htlc_settlement_after_close(broadcast_alice: bool, go_onchain
88818888
assert_eq!(bob_txn.len(), 1);
88828889
check_spends!(bob_txn[0], txn_to_broadcast[0]);
88838890
} else {
8884-
assert_eq!(bob_txn.len(), 2);
8891+
if nodes[1].connect_style.borrow().updates_best_block_first() {
8892+
assert_eq!(bob_txn.len(), 3);
8893+
assert_eq!(bob_txn[0].txid(), bob_txn[1].txid());
8894+
} else {
8895+
assert_eq!(bob_txn.len(), 2);
8896+
}
88858897
check_spends!(bob_txn[0], chan_ab.3);
88868898
}
88878899
}
@@ -8897,15 +8909,16 @@ fn do_test_onchain_htlc_settlement_after_close(broadcast_alice: bool, go_onchain
88978909
// If Alice force-closed, Bob only broadcasts a HTLC-output-claiming transaction. Otherwise,
88988910
// Bob force-closed and broadcasts the commitment transaction along with a
88998911
// HTLC-output-claiming transaction.
8900-
let bob_txn = nodes[1].tx_broadcaster.txn_broadcasted.lock().unwrap().clone();
8912+
let mut bob_txn = nodes[1].tx_broadcaster.txn_broadcasted.lock().unwrap().clone();
89018913
if broadcast_alice {
89028914
assert_eq!(bob_txn.len(), 1);
89038915
check_spends!(bob_txn[0], txn_to_broadcast[0]);
89048916
assert_eq!(bob_txn[0].input[0].witness.last().unwrap().len(), script_weight);
89058917
} else {
8906-
assert_eq!(bob_txn.len(), 2);
8907-
check_spends!(bob_txn[1], txn_to_broadcast[0]);
8908-
assert_eq!(bob_txn[1].input[0].witness.last().unwrap().len(), script_weight);
8918+
assert_eq!(bob_txn.len(), if nodes[1].connect_style.borrow().updates_best_block_first() { 3 } else { 2 });
8919+
let htlc_tx = bob_txn.pop().unwrap();
8920+
check_spends!(htlc_tx, txn_to_broadcast[0]);
8921+
assert_eq!(htlc_tx.input[0].witness.last().unwrap().len(), script_weight);
89098922
}
89108923
}
89118924
}
@@ -9381,8 +9394,12 @@ fn do_test_tx_confirmed_skipping_blocks_immediate_broadcast(test_height_before_t
93819394
// We should broadcast an HTLC transaction spending our funding transaction first
93829395
let spending_txn = nodes[1].tx_broadcaster.txn_broadcasted.lock().unwrap().split_off(0);
93839396
assert_eq!(spending_txn.len(), 2);
9384-
assert_eq!(spending_txn[0].txid(), node_txn[0].txid());
9385-
check_spends!(spending_txn[1], node_txn[0]);
9397+
let htlc_tx = if spending_txn[0].txid() == node_txn[0].txid() {
9398+
&spending_txn[1]
9399+
} else {
9400+
&spending_txn[0]
9401+
};
9402+
check_spends!(htlc_tx, node_txn[0]);
93869403
// We should also generate a SpendableOutputs event with the to_self output (as its
93879404
// timelock is up).
93889405
let descriptor_spend_txn = check_spendable_outputs!(nodes[1], node_cfgs[1].keys_manager);
@@ -9392,7 +9409,7 @@ fn do_test_tx_confirmed_skipping_blocks_immediate_broadcast(test_height_before_t
93929409
// should immediately fail-backwards the HTLC to the previous hop, without waiting for an
93939410
// additional block built on top of the current chain.
93949411
nodes[1].chain_monitor.chain_monitor.transactions_confirmed(
9395-
&nodes[1].get_block_header(conf_height + 1), &[(0, &spending_txn[1])], conf_height + 1);
9412+
&nodes[1].get_block_header(conf_height + 1), &[(0, htlc_tx)], conf_height + 1);
93969413
expect_pending_htlcs_forwardable_and_htlc_handling_failed!(nodes[1], vec![HTLCDestination::NextHopChannel { node_id: Some(nodes[2].node.get_our_node_id()), channel_id: channel_id }]);
93979414
check_added_monitors!(nodes[1], 1);
93989415

0 commit comments

Comments
 (0)