Skip to content

Commit d9422ca

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 1876e67 commit d9422ca

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
@@ -2604,18 +2604,59 @@ impl<Signer: WriteableEcdsaChannelSigner> ChannelMonitorImpl<Signer> {
26042604
}
26052605
}
26062606

2607-
pub(crate) fn broadcast_latest_holder_commitment_txn<B: Deref, L: Deref>(&mut self, broadcaster: &B, logger: &L)
2608-
where B::Target: BroadcasterInterface,
2609-
L::Target: Logger,
2610-
{
2611-
let commit_txs = self.get_latest_holder_commitment_txn(logger);
2612-
let mut txs = vec![];
2613-
for tx in commit_txs.iter() {
2614-
log_info!(logger, "Broadcasting local {}", log_tx!(tx));
2615-
txs.push(tx);
2616-
}
2617-
broadcaster.broadcast_transactions(&txs);
2607+
fn generate_claimable_outpoints_and_watch_outputs(&mut self) -> (Vec<PackageTemplate>, Vec<TransactionOutputs>) {
2608+
let funding_outp = HolderFundingOutput::build(
2609+
self.funding_redeemscript.clone(),
2610+
self.channel_value_satoshis,
2611+
self.onchain_tx_handler.channel_type_features().clone()
2612+
);
2613+
let commitment_package = PackageTemplate::build_package(
2614+
self.funding_info.0.txid.clone(), self.funding_info.0.index as u32,
2615+
PackageSolvingData::HolderFundingOutput(funding_outp),
2616+
self.best_block.height(), self.best_block.height()
2617+
);
2618+
let mut claimable_outpoints = vec![commitment_package];
26182619
self.pending_monitor_events.push(MonitorEvent::HolderForceClosed(self.funding_info.0));
2620+
// Although we aren't signing the transaction directly here, the transaction will be signed
2621+
// in the claim that is queued to OnchainTxHandler. We set holder_tx_signed here to reject
2622+
// new channel updates.
2623+
self.holder_tx_signed = true;
2624+
let mut watch_outputs = Vec::new();
2625+
// We can't broadcast our HTLC transactions while the commitment transaction is
2626+
// unconfirmed. We'll delay doing so until we detect the confirmed commitment in
2627+
// `transactions_confirmed`.
2628+
if !self.onchain_tx_handler.channel_type_features().supports_anchors_zero_fee_htlc_tx() {
2629+
// Because we're broadcasting a commitment transaction, we should construct the package
2630+
// assuming it gets confirmed in the next block. Sadly, we have code which considers
2631+
// "not yet confirmed" things as discardable, so we cannot do that here.
2632+
let (mut new_outpoints, _) = self.get_broadcasted_holder_claims(
2633+
&self.current_holder_commitment_tx, self.best_block.height()
2634+
);
2635+
let unsigned_commitment_tx = self.onchain_tx_handler.get_unsigned_holder_commitment_tx();
2636+
let new_outputs = self.get_broadcasted_holder_watch_outputs(
2637+
&self.current_holder_commitment_tx, &unsigned_commitment_tx
2638+
);
2639+
if !new_outputs.is_empty() {
2640+
watch_outputs.push((self.current_holder_commitment_tx.txid.clone(), new_outputs));
2641+
}
2642+
claimable_outpoints.append(&mut new_outpoints);
2643+
}
2644+
(claimable_outpoints, watch_outputs)
2645+
}
2646+
2647+
pub(crate) fn queue_latest_holder_commitment_txn_for_broadcast<B: Deref, F: Deref, L: Deref>(
2648+
&mut self, broadcaster: &B, fee_estimator: &LowerBoundedFeeEstimator<F>, logger: &L
2649+
)
2650+
where
2651+
B::Target: BroadcasterInterface,
2652+
F::Target: FeeEstimator,
2653+
L::Target: Logger,
2654+
{
2655+
let (claimable_outpoints, _) = self.generate_claimable_outpoints_and_watch_outputs();
2656+
self.onchain_tx_handler.update_claims_view_from_requests(
2657+
claimable_outpoints, self.best_block.height(), self.best_block.height(), broadcaster,
2658+
fee_estimator, logger
2659+
);
26192660
}
26202661

26212662
pub fn update_monitor<B: Deref, F: Deref, L: Deref>(&mut self, updates: &ChannelMonitorUpdate, broadcaster: &B, fee_estimator: &F, logger: &L) -> Result<(), ()>
@@ -2703,26 +2744,7 @@ impl<Signer: WriteableEcdsaChannelSigner> ChannelMonitorImpl<Signer> {
27032744
log_trace!(logger, "Avoiding commitment broadcast, already detected confirmed spend onchain");
27042745
continue;
27052746
}
2706-
self.broadcast_latest_holder_commitment_txn(broadcaster, logger);
2707-
// If the channel supports anchor outputs, we'll need to emit an external
2708-
// event to be consumed such that a child transaction is broadcast with a
2709-
// high enough feerate for the parent commitment transaction to confirm.
2710-
if self.onchain_tx_handler.channel_type_features().supports_anchors_zero_fee_htlc_tx() {
2711-
let funding_output = HolderFundingOutput::build(
2712-
self.funding_redeemscript.clone(), self.channel_value_satoshis,
2713-
self.onchain_tx_handler.channel_type_features().clone(),
2714-
);
2715-
let best_block_height = self.best_block.height();
2716-
let commitment_package = PackageTemplate::build_package(
2717-
self.funding_info.0.txid.clone(), self.funding_info.0.index as u32,
2718-
PackageSolvingData::HolderFundingOutput(funding_output),
2719-
best_block_height, best_block_height
2720-
);
2721-
self.onchain_tx_handler.update_claims_view_from_requests(
2722-
vec![commitment_package], best_block_height, best_block_height,
2723-
broadcaster, &bounded_fee_estimator, logger,
2724-
);
2725-
}
2747+
self.queue_latest_holder_commitment_txn_for_broadcast(broadcaster, &bounded_fee_estimator, logger);
27262748
} else if !self.holder_tx_signed {
27272749
log_error!(logger, "WARNING: You have a potentially-unsafe holder commitment transaction available to broadcast");
27282750
log_error!(logger, " in channel monitor for channel {}!", &self.funding_info.0.to_channel_id());
@@ -3625,29 +3647,9 @@ impl<Signer: WriteableEcdsaChannelSigner> ChannelMonitorImpl<Signer> {
36253647

36263648
let should_broadcast = self.should_broadcast_holder_commitment_txn(logger);
36273649
if should_broadcast {
3628-
let funding_outp = HolderFundingOutput::build(self.funding_redeemscript.clone(), self.channel_value_satoshis, self.onchain_tx_handler.channel_type_features().clone());
3629-
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());
3630-
claimable_outpoints.push(commitment_package);
3631-
self.pending_monitor_events.push(MonitorEvent::HolderForceClosed(self.funding_info.0));
3632-
// Although we aren't signing the transaction directly here, the transaction will be signed
3633-
// in the claim that is queued to OnchainTxHandler. We set holder_tx_signed here to reject
3634-
// new channel updates.
3635-
self.holder_tx_signed = true;
3636-
// We can't broadcast our HTLC transactions while the commitment transaction is
3637-
// unconfirmed. We'll delay doing so until we detect the confirmed commitment in
3638-
// `transactions_confirmed`.
3639-
if !self.onchain_tx_handler.channel_type_features().supports_anchors_zero_fee_htlc_tx() {
3640-
// Because we're broadcasting a commitment transaction, we should construct the package
3641-
// assuming it gets confirmed in the next block. Sadly, we have code which considers
3642-
// "not yet confirmed" things as discardable, so we cannot do that here.
3643-
let (mut new_outpoints, _) = self.get_broadcasted_holder_claims(&self.current_holder_commitment_tx, self.best_block.height());
3644-
let unsigned_commitment_tx = self.onchain_tx_handler.get_unsigned_holder_commitment_tx();
3645-
let new_outputs = self.get_broadcasted_holder_watch_outputs(&self.current_holder_commitment_tx, &unsigned_commitment_tx);
3646-
if !new_outputs.is_empty() {
3647-
watch_outputs.push((self.current_holder_commitment_tx.txid.clone(), new_outputs));
3648-
}
3649-
claimable_outpoints.append(&mut new_outpoints);
3650-
}
3650+
let (mut new_outpoints, mut new_outputs) = self.generate_claimable_outpoints_and_watch_outputs();
3651+
claimable_outpoints.append(&mut new_outpoints);
3652+
watch_outputs.append(&mut new_outputs);
36513653
}
36523654

36533655
// 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
@@ -2270,9 +2270,15 @@ fn channel_monitor_network_test() {
22702270
nodes[1].node.force_close_broadcasting_latest_txn(&chan_1.2, &nodes[0].node.get_our_node_id()).unwrap();
22712271
check_added_monitors!(nodes[1], 1);
22722272
check_closed_broadcast!(nodes[1], true);
2273+
check_closed_event!(nodes[1], 1, ClosureReason::HolderForceClosed, [nodes[0].node.get_our_node_id()], 100000);
22732274
{
22742275
let mut node_txn = test_txn_broadcast(&nodes[1], &chan_1, None, HTLCType::NONE);
22752276
assert_eq!(node_txn.len(), 1);
2277+
mine_transaction(&nodes[1], &node_txn[0]);
2278+
if nodes[1].connect_style.borrow().updates_best_block_first() {
2279+
let _ = nodes[1].tx_broadcaster.txn_broadcast();
2280+
}
2281+
22762282
mine_transaction(&nodes[0], &node_txn[0]);
22772283
check_added_monitors!(nodes[0], 1);
22782284
test_txn_broadcast(&nodes[0], &chan_1, Some(node_txn[0].clone()), HTLCType::NONE);
@@ -2281,7 +2287,6 @@ fn channel_monitor_network_test() {
22812287
assert_eq!(nodes[0].node.list_channels().len(), 0);
22822288
assert_eq!(nodes[1].node.list_channels().len(), 1);
22832289
check_closed_event!(nodes[0], 1, ClosureReason::CommitmentTxConfirmed, [nodes[1].node.get_our_node_id()], 100000);
2284-
check_closed_event!(nodes[1], 1, ClosureReason::HolderForceClosed, [nodes[0].node.get_our_node_id()], 100000);
22852290

22862291
// One pending HTLC is discarded by the force-close:
22872292
let (payment_preimage_1, payment_hash_1, ..) = route_payment(&nodes[1], &[&nodes[2], &nodes[3]], 3_000_000);
@@ -3552,7 +3557,7 @@ fn test_htlc_ignore_latest_remote_commitment() {
35523557
// connect_style.
35533558
return;
35543559
}
3555-
create_announced_chan_between_nodes(&nodes, 0, 1);
3560+
let funding_tx = create_announced_chan_between_nodes(&nodes, 0, 1).3;
35563561

35573562
route_payment(&nodes[0], &[&nodes[1]], 10000000);
35583563
nodes[0].node.force_close_broadcasting_latest_txn(&nodes[0].node.list_channels()[0].channel_id, &nodes[1].node.get_our_node_id()).unwrap();
@@ -3561,11 +3566,12 @@ fn test_htlc_ignore_latest_remote_commitment() {
35613566
check_added_monitors!(nodes[0], 1);
35623567
check_closed_event!(nodes[0], 1, ClosureReason::HolderForceClosed, [nodes[1].node.get_our_node_id()], 100000);
35633568

3564-
let node_txn = nodes[0].tx_broadcaster.txn_broadcasted.lock().unwrap().split_off(0);
3565-
assert_eq!(node_txn.len(), 3);
3566-
assert_eq!(node_txn[0].txid(), node_txn[1].txid());
3569+
let node_txn = nodes[0].tx_broadcaster.unique_txn_broadcast();
3570+
assert_eq!(node_txn.len(), 2);
3571+
check_spends!(node_txn[0], funding_tx);
3572+
check_spends!(node_txn[1], node_txn[0]);
35673573

3568-
let block = create_dummy_block(nodes[1].best_block_hash(), 42, vec![node_txn[0].clone(), node_txn[1].clone()]);
3574+
let block = create_dummy_block(nodes[1].best_block_hash(), 42, vec![node_txn[0].clone()]);
35693575
connect_block(&nodes[1], &block);
35703576
check_closed_broadcast!(nodes[1], true);
35713577
check_added_monitors!(nodes[1], 1);
@@ -3622,7 +3628,7 @@ fn test_force_close_fail_back() {
36223628
check_closed_broadcast!(nodes[2], true);
36233629
check_added_monitors!(nodes[2], 1);
36243630
check_closed_event!(nodes[2], 1, ClosureReason::HolderForceClosed, [nodes[1].node.get_our_node_id()], 100000);
3625-
let tx = {
3631+
let commitment_tx = {
36263632
let mut node_txn = nodes[2].tx_broadcaster.txn_broadcasted.lock().unwrap();
36273633
// Note that we don't bother broadcasting the HTLC-Success transaction here as we don't
36283634
// have a use for it unless nodes[2] learns the preimage somehow, the funds will go
@@ -3631,7 +3637,7 @@ fn test_force_close_fail_back() {
36313637
node_txn.remove(0)
36323638
};
36333639

3634-
mine_transaction(&nodes[1], &tx);
3640+
mine_transaction(&nodes[1], &commitment_tx);
36353641

36363642
// Note no UpdateHTLCs event here from nodes[1] to nodes[0]!
36373643
check_closed_broadcast!(nodes[1], true);
@@ -3643,15 +3649,16 @@ fn test_force_close_fail_back() {
36433649
get_monitor!(nodes[2], payment_event.commitment_msg.channel_id)
36443650
.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);
36453651
}
3646-
mine_transaction(&nodes[2], &tx);
3647-
let node_txn = nodes[2].tx_broadcaster.txn_broadcasted.lock().unwrap();
3648-
assert_eq!(node_txn.len(), 1);
3649-
assert_eq!(node_txn[0].input.len(), 1);
3650-
assert_eq!(node_txn[0].input[0].previous_output.txid, tx.txid());
3651-
assert_eq!(node_txn[0].lock_time, LockTime::ZERO); // Must be an HTLC-Success
3652-
assert_eq!(node_txn[0].input[0].witness.len(), 5); // Must be an HTLC-Success
3652+
mine_transaction(&nodes[2], &commitment_tx);
3653+
let mut node_txn = nodes[2].tx_broadcaster.txn_broadcast();
3654+
assert_eq!(node_txn.len(), if nodes[2].connect_style.borrow().updates_best_block_first() { 2 } else { 1 });
3655+
let htlc_tx = node_txn.pop().unwrap();
3656+
assert_eq!(htlc_tx.input.len(), 1);
3657+
assert_eq!(htlc_tx.input[0].previous_output.txid, commitment_tx.txid());
3658+
assert_eq!(htlc_tx.lock_time, LockTime::ZERO); // Must be an HTLC-Success
3659+
assert_eq!(htlc_tx.input[0].witness.len(), 5); // Must be an HTLC-Success
36533660

3654-
check_spends!(node_txn[0], tx);
3661+
check_spends!(htlc_tx, commitment_tx);
36553662
}
36563663

36573664
#[test]
@@ -8876,7 +8883,12 @@ fn do_test_onchain_htlc_settlement_after_close(broadcast_alice: bool, go_onchain
88768883
assert_eq!(bob_txn.len(), 1);
88778884
check_spends!(bob_txn[0], txn_to_broadcast[0]);
88788885
} else {
8879-
assert_eq!(bob_txn.len(), 2);
8886+
if nodes[1].connect_style.borrow().updates_best_block_first() {
8887+
assert_eq!(bob_txn.len(), 3);
8888+
assert_eq!(bob_txn[0].txid(), bob_txn[1].txid());
8889+
} else {
8890+
assert_eq!(bob_txn.len(), 2);
8891+
}
88808892
check_spends!(bob_txn[0], chan_ab.3);
88818893
}
88828894
}
@@ -8892,15 +8904,16 @@ fn do_test_onchain_htlc_settlement_after_close(broadcast_alice: bool, go_onchain
88928904
// If Alice force-closed, Bob only broadcasts a HTLC-output-claiming transaction. Otherwise,
88938905
// Bob force-closed and broadcasts the commitment transaction along with a
88948906
// HTLC-output-claiming transaction.
8895-
let bob_txn = nodes[1].tx_broadcaster.txn_broadcasted.lock().unwrap().clone();
8907+
let mut bob_txn = nodes[1].tx_broadcaster.txn_broadcasted.lock().unwrap().clone();
88968908
if broadcast_alice {
88978909
assert_eq!(bob_txn.len(), 1);
88988910
check_spends!(bob_txn[0], txn_to_broadcast[0]);
88998911
assert_eq!(bob_txn[0].input[0].witness.last().unwrap().len(), script_weight);
89008912
} else {
8901-
assert_eq!(bob_txn.len(), 2);
8902-
check_spends!(bob_txn[1], txn_to_broadcast[0]);
8903-
assert_eq!(bob_txn[1].input[0].witness.last().unwrap().len(), script_weight);
8913+
assert_eq!(bob_txn.len(), if nodes[1].connect_style.borrow().updates_best_block_first() { 3 } else { 2 });
8914+
let htlc_tx = bob_txn.pop().unwrap();
8915+
check_spends!(htlc_tx, txn_to_broadcast[0]);
8916+
assert_eq!(htlc_tx.input[0].witness.last().unwrap().len(), script_weight);
89048917
}
89058918
}
89068919
}
@@ -9376,8 +9389,12 @@ fn do_test_tx_confirmed_skipping_blocks_immediate_broadcast(test_height_before_t
93769389
// We should broadcast an HTLC transaction spending our funding transaction first
93779390
let spending_txn = nodes[1].tx_broadcaster.txn_broadcasted.lock().unwrap().split_off(0);
93789391
assert_eq!(spending_txn.len(), 2);
9379-
assert_eq!(spending_txn[0].txid(), node_txn[0].txid());
9380-
check_spends!(spending_txn[1], node_txn[0]);
9392+
let htlc_tx = if spending_txn[0].txid() == node_txn[0].txid() {
9393+
&spending_txn[1]
9394+
} else {
9395+
&spending_txn[0]
9396+
};
9397+
check_spends!(htlc_tx, node_txn[0]);
93819398
// We should also generate a SpendableOutputs event with the to_self output (as its
93829399
// timelock is up).
93839400
let descriptor_spend_txn = check_spendable_outputs!(nodes[1], node_cfgs[1].keys_manager);
@@ -9387,7 +9404,7 @@ fn do_test_tx_confirmed_skipping_blocks_immediate_broadcast(test_height_before_t
93879404
// should immediately fail-backwards the HTLC to the previous hop, without waiting for an
93889405
// additional block built on top of the current chain.
93899406
nodes[1].chain_monitor.chain_monitor.transactions_confirmed(
9390-
&nodes[1].get_block_header(conf_height + 1), &[(0, &spending_txn[1])], conf_height + 1);
9407+
&nodes[1].get_block_header(conf_height + 1), &[(0, htlc_tx)], conf_height + 1);
93919408
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 }]);
93929409
check_added_monitors!(nodes[1], 1);
93939410

0 commit comments

Comments
 (0)