Skip to content

Commit 7093f84

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 876cf15 commit 7093f84

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

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

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

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

36463648
// 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
@@ -2269,9 +2269,15 @@ fn channel_monitor_network_test() {
22692269
nodes[1].node.force_close_broadcasting_latest_txn(&chan_1.2, &nodes[0].node.get_our_node_id()).unwrap();
22702270
check_added_monitors!(nodes[1], 1);
22712271
check_closed_broadcast!(nodes[1], true);
2272+
check_closed_event!(nodes[1], 1, ClosureReason::HolderForceClosed, [nodes[0].node.get_our_node_id()], 100000);
22722273
{
22732274
let mut node_txn = test_txn_broadcast(&nodes[1], &chan_1, None, HTLCType::NONE);
22742275
assert_eq!(node_txn.len(), 1);
2276+
mine_transaction(&nodes[1], &node_txn[0]);
2277+
if nodes[1].connect_style.borrow().updates_best_block_first() {
2278+
let _ = nodes[1].tx_broadcaster.txn_broadcast();
2279+
}
2280+
22752281
mine_transaction(&nodes[0], &node_txn[0]);
22762282
check_added_monitors!(nodes[0], 1);
22772283
test_txn_broadcast(&nodes[0], &chan_1, Some(node_txn[0].clone()), HTLCType::NONE);
@@ -2280,7 +2286,6 @@ fn channel_monitor_network_test() {
22802286
assert_eq!(nodes[0].node.list_channels().len(), 0);
22812287
assert_eq!(nodes[1].node.list_channels().len(), 1);
22822288
check_closed_event!(nodes[0], 1, ClosureReason::CommitmentTxConfirmed, [nodes[1].node.get_our_node_id()], 100000);
2283-
check_closed_event!(nodes[1], 1, ClosureReason::HolderForceClosed, [nodes[0].node.get_our_node_id()], 100000);
22842289

22852290
// One pending HTLC is discarded by the force-close:
22862291
let (payment_preimage_1, payment_hash_1, ..) = route_payment(&nodes[1], &[&nodes[2], &nodes[3]], 3_000_000);
@@ -3551,7 +3556,7 @@ fn test_htlc_ignore_latest_remote_commitment() {
35513556
// connect_style.
35523557
return;
35533558
}
3554-
create_announced_chan_between_nodes(&nodes, 0, 1);
3559+
let funding_tx = create_announced_chan_between_nodes(&nodes, 0, 1).3;
35553560

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

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

3567-
let block = create_dummy_block(nodes[1].best_block_hash(), 42, vec![node_txn[0].clone(), node_txn[1].clone()]);
3573+
let block = create_dummy_block(nodes[1].best_block_hash(), 42, vec![node_txn[0].clone()]);
35683574
connect_block(&nodes[1], &block);
35693575
check_closed_broadcast!(nodes[1], true);
35703576
check_added_monitors!(nodes[1], 1);
@@ -3621,7 +3627,7 @@ fn test_force_close_fail_back() {
36213627
check_closed_broadcast!(nodes[2], true);
36223628
check_added_monitors!(nodes[2], 1);
36233629
check_closed_event!(nodes[2], 1, ClosureReason::HolderForceClosed, [nodes[1].node.get_our_node_id()], 100000);
3624-
let tx = {
3630+
let commitment_tx = {
36253631
let mut node_txn = nodes[2].tx_broadcaster.txn_broadcasted.lock().unwrap();
36263632
// Note that we don't bother broadcasting the HTLC-Success transaction here as we don't
36273633
// have a use for it unless nodes[2] learns the preimage somehow, the funds will go
@@ -3630,7 +3636,7 @@ fn test_force_close_fail_back() {
36303636
node_txn.remove(0)
36313637
};
36323638

3633-
mine_transaction(&nodes[1], &tx);
3639+
mine_transaction(&nodes[1], &commitment_tx);
36343640

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

3653-
check_spends!(node_txn[0], tx);
3660+
check_spends!(htlc_tx, commitment_tx);
36543661
}
36553662

36563663
#[test]
@@ -8851,7 +8858,12 @@ fn do_test_onchain_htlc_settlement_after_close(broadcast_alice: bool, go_onchain
88518858
assert_eq!(bob_txn.len(), 1);
88528859
check_spends!(bob_txn[0], txn_to_broadcast[0]);
88538860
} else {
8854-
assert_eq!(bob_txn.len(), 2);
8861+
if nodes[1].connect_style.borrow().updates_best_block_first() {
8862+
assert_eq!(bob_txn.len(), 3);
8863+
assert_eq!(bob_txn[0].txid(), bob_txn[1].txid());
8864+
} else {
8865+
assert_eq!(bob_txn.len(), 2);
8866+
}
88558867
check_spends!(bob_txn[0], chan_ab.3);
88568868
}
88578869
}
@@ -8867,15 +8879,16 @@ fn do_test_onchain_htlc_settlement_after_close(broadcast_alice: bool, go_onchain
88678879
// If Alice force-closed, Bob only broadcasts a HTLC-output-claiming transaction. Otherwise,
88688880
// Bob force-closed and broadcasts the commitment transaction along with a
88698881
// HTLC-output-claiming transaction.
8870-
let bob_txn = nodes[1].tx_broadcaster.txn_broadcasted.lock().unwrap().clone();
8882+
let mut bob_txn = nodes[1].tx_broadcaster.txn_broadcasted.lock().unwrap().clone();
88718883
if broadcast_alice {
88728884
assert_eq!(bob_txn.len(), 1);
88738885
check_spends!(bob_txn[0], txn_to_broadcast[0]);
88748886
assert_eq!(bob_txn[0].input[0].witness.last().unwrap().len(), script_weight);
88758887
} else {
8876-
assert_eq!(bob_txn.len(), 2);
8877-
check_spends!(bob_txn[1], txn_to_broadcast[0]);
8878-
assert_eq!(bob_txn[1].input[0].witness.last().unwrap().len(), script_weight);
8888+
assert_eq!(bob_txn.len(), if nodes[1].connect_style.borrow().updates_best_block_first() { 3 } else { 2 });
8889+
let htlc_tx = bob_txn.pop().unwrap();
8890+
check_spends!(htlc_tx, txn_to_broadcast[0]);
8891+
assert_eq!(htlc_tx.input[0].witness.last().unwrap().len(), script_weight);
88798892
}
88808893
}
88818894
}
@@ -9351,8 +9364,12 @@ fn do_test_tx_confirmed_skipping_blocks_immediate_broadcast(test_height_before_t
93519364
// We should broadcast an HTLC transaction spending our funding transaction first
93529365
let spending_txn = nodes[1].tx_broadcaster.txn_broadcasted.lock().unwrap().split_off(0);
93539366
assert_eq!(spending_txn.len(), 2);
9354-
assert_eq!(spending_txn[0].txid(), node_txn[0].txid());
9355-
check_spends!(spending_txn[1], node_txn[0]);
9367+
let htlc_tx = if spending_txn[0].txid() == node_txn[0].txid() {
9368+
&spending_txn[1]
9369+
} else {
9370+
&spending_txn[0]
9371+
};
9372+
check_spends!(htlc_tx, node_txn[0]);
93569373
// We should also generate a SpendableOutputs event with the to_self output (as its
93579374
// timelock is up).
93589375
let descriptor_spend_txn = check_spendable_outputs!(nodes[1], node_cfgs[1].keys_manager);
@@ -9362,7 +9379,7 @@ fn do_test_tx_confirmed_skipping_blocks_immediate_broadcast(test_height_before_t
93629379
// should immediately fail-backwards the HTLC to the previous hop, without waiting for an
93639380
// additional block built on top of the current chain.
93649381
nodes[1].chain_monitor.chain_monitor.transactions_confirmed(
9365-
&nodes[1].get_block_header(conf_height + 1), &[(0, &spending_txn[1])], conf_height + 1);
9382+
&nodes[1].get_block_header(conf_height + 1), &[(0, htlc_tx)], conf_height + 1);
93669383
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 }]);
93679384
check_added_monitors!(nodes[1], 1);
93689385

0 commit comments

Comments
 (0)