Skip to content

Commit d99e59b

Browse files
committed
Always emit bump events, even when fees are sufficient
Currently, the anchor commitment bump events are bypassed when the commitment transaction has sufficient fees. However, this makes it difficult for users to defer force-closures to a trusted party (such as an LSP) while not maintaining reserves. Broadcasting a commitment transaction without maintaining reserves would make HTLCs unclaimable against that commitment transaction. In this change, anchor commitment bump events will always be emitted so users can capture and choose not to process them.
1 parent 192618b commit d99e59b

File tree

6 files changed

+99
-42
lines changed

6 files changed

+99
-42
lines changed

lightning/src/chain/onchaintx.rs

Lines changed: 1 addition & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ use bitcoin::secp256k1::{ecdsa::Signature, Secp256k1};
2323
use bitcoin::transaction::OutPoint as BitcoinOutPoint;
2424
use bitcoin::transaction::Transaction;
2525

26-
use crate::chain::chaininterface::{compute_feerate_sat_per_1000_weight, ConfirmationTarget};
26+
use crate::chain::chaininterface::ConfirmationTarget;
2727
use crate::chain::chaininterface::{BroadcasterInterface, FeeEstimator, LowerBoundedFeeEstimator};
2828
use crate::chain::channelmonitor::ANTI_REORG_DELAY;
2929
use crate::chain::package::{PackageSolvingData, PackageTemplate};
@@ -670,19 +670,8 @@ impl<ChannelSigner: EcdsaChannelSigner> OnchainTxHandler<ChannelSigner> {
670670

671671
let fee_sat = input_amount_sats - tx.output.iter()
672672
.map(|output| output.value.to_sat()).sum::<u64>();
673-
let commitment_tx_feerate_sat_per_1000_weight =
674-
compute_feerate_sat_per_1000_weight(fee_sat, tx.weight().to_wu());
675673
let package_target_feerate_sat_per_1000_weight = cached_request
676674
.compute_package_feerate(fee_estimator, conf_target, feerate_strategy);
677-
if commitment_tx_feerate_sat_per_1000_weight >= package_target_feerate_sat_per_1000_weight {
678-
log_debug!(logger, "Pre-signed commitment {} already has feerate {} sat/kW above required {} sat/kW",
679-
tx.compute_txid(), commitment_tx_feerate_sat_per_1000_weight,
680-
package_target_feerate_sat_per_1000_weight);
681-
// The commitment transaction already meets the required feerate and doesn't
682-
// need a CPFP. We still want to return something other than the event to
683-
// register the claim.
684-
return Some((new_timer, 0, OnchainClaim::Tx(MaybeSignedTransaction(tx))));
685-
}
686675

687676
// We'll locate an anchor output we can spend within the commitment transaction.
688677
let channel_parameters = output.channel_parameters.as_ref()

lightning/src/events/bump_transaction/mod.rs

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,9 @@ pub mod sync;
1616
use alloc::collections::BTreeMap;
1717
use core::ops::Deref;
1818

19-
use crate::chain::chaininterface::{fee_for_weight, BroadcasterInterface};
19+
use crate::chain::chaininterface::{
20+
compute_feerate_sat_per_1000_weight, fee_for_weight, BroadcasterInterface,
21+
};
2022
use crate::chain::ClaimId;
2123
use crate::io_extras::sink;
2224
use crate::ln::chan_utils;
@@ -123,7 +125,9 @@ pub enum BumpTransactionEvent {
123125
/// and child anchor transactions), possibly resulting in a loss of funds. Once the transaction
124126
/// is constructed, it must be fully signed for and broadcast by the consumer of the event
125127
/// along with the `commitment_tx` enclosed. Note that the `commitment_tx` must always be
126-
/// broadcast first, as the child anchor transaction depends on it.
128+
/// broadcast first, as the child anchor transaction depends on it. It is also possible that the
129+
/// feerate of the commitment transaction is already sufficient, in which case the child anchor
130+
/// transaction is not needed and only the commitment transaction should be broadcast.
127131
///
128132
/// The consumer should be able to sign for any of the additional inputs included within the
129133
/// child anchor transaction. To sign its anchor input, an [`EcdsaChannelSigner`] should be
@@ -658,6 +662,19 @@ where
658662
commitment_tx: &Transaction, commitment_tx_fee_sat: u64,
659663
anchor_descriptor: &AnchorDescriptor,
660664
) -> Result<(), ()> {
665+
// First, check if the commitment transaction has sufficient fees on its own.
666+
let commitment_tx_feerate_sat_per_1000_weight = compute_feerate_sat_per_1000_weight(
667+
commitment_tx_fee_sat,
668+
commitment_tx.weight().to_wu(),
669+
);
670+
if commitment_tx_feerate_sat_per_1000_weight >= package_target_feerate_sat_per_1000_weight {
671+
log_debug!(self.logger, "Pre-signed commitment {} already has feerate {} sat/kW above required {} sat/kW, broadcasting.",
672+
commitment_tx.compute_txid(), commitment_tx_feerate_sat_per_1000_weight,
673+
package_target_feerate_sat_per_1000_weight);
674+
self.broadcaster.broadcast_transactions(&[&commitment_tx]);
675+
return Ok(());
676+
}
677+
661678
// Our commitment transaction already has fees allocated to it, so we should take them into
662679
// account. We do so by pretending the commitment transaction's fee and weight are part of
663680
// the anchor input.

lightning/src/ln/async_signer_tests.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1051,6 +1051,9 @@ fn do_test_async_holder_signatures(anchors: bool, remote_commitment: bool) {
10511051
&nodes[0].logger,
10521052
);
10531053
}
1054+
if anchors {
1055+
handle_bump_close_event(closing_node);
1056+
}
10541057

10551058
let commitment_tx = {
10561059
let mut txn = closing_node.tx_broadcaster.txn_broadcast();

lightning/src/ln/functional_test_utils.rs

Lines changed: 26 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2211,21 +2211,37 @@ macro_rules! check_closed_event {
22112211
};
22122212
}
22132213

2214-
pub fn handle_bump_htlc_event(node: &Node, count: usize) {
2214+
pub fn handle_bump_events(node: &Node, expected_close: bool, expected_htlc_count: usize) {
22152215
let events = node.chain_monitor.chain_monitor.get_and_clear_pending_events();
2216-
assert_eq!(events.len(), count);
2217-
for event in events {
2216+
let mut close = false;
2217+
let mut htlc_count = 0;
2218+
for event in &events {
22182219
match event {
2219-
Event::BumpTransaction(bump_event) => {
2220-
if let BumpTransactionEvent::HTLCResolution { .. } = &bump_event {
2221-
} else {
2222-
panic!();
2223-
}
2224-
node.bump_tx_handler.handle_event(&bump_event);
2220+
Event::BumpTransaction(bump @ BumpTransactionEvent::ChannelClose { .. }) => {
2221+
close = true;
2222+
node.bump_tx_handler.handle_event(&bump);
22252223
},
2226-
_ => panic!(),
2224+
Event::BumpTransaction(bump @ BumpTransactionEvent::HTLCResolution { .. }) => {
2225+
htlc_count += 1;
2226+
node.bump_tx_handler.handle_event(&bump);
2227+
},
2228+
_ => panic!("Unexpected non-bump event: {:?}.", event),
22272229
}
22282230
}
2231+
assert_eq!(close, expected_close, "Expected a bump close event, found {:?}.", events);
2232+
assert_eq!(
2233+
htlc_count, expected_htlc_count,
2234+
"Expected {} bump HTLC events, found {:?}",
2235+
expected_htlc_count, events
2236+
);
2237+
}
2238+
2239+
pub fn handle_bump_close_event(node: &Node) {
2240+
handle_bump_events(node, true, 0);
2241+
}
2242+
2243+
pub fn handle_bump_htlc_event(node: &Node, count: usize) {
2244+
handle_bump_events(node, false, count);
22292245
}
22302246

22312247
pub fn close_channel<'a, 'b, 'c>(

lightning/src/ln/monitor_tests.rs

Lines changed: 22 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -896,6 +896,9 @@ fn do_test_balances_on_local_commitment_htlcs(anchors: bool) {
896896
check_closed_broadcast!(nodes[0], true);
897897
let reason = ClosureReason::HolderForceClosed { broadcasted_latest_txn: Some(true), message };
898898
check_closed_event!(nodes[0], 1, reason, [nodes[1].node.get_our_node_id()], 1000000);
899+
if anchors {
900+
handle_bump_close_event(&nodes[0]);
901+
}
899902
let commitment_tx = {
900903
let mut txn = nodes[0].tx_broadcaster.unique_txn_broadcast();
901904
assert_eq!(txn.len(), 1);
@@ -905,9 +908,15 @@ fn do_test_balances_on_local_commitment_htlcs(anchors: bool) {
905908
};
906909
let commitment_tx_conf_height_a = block_from_scid(mine_transaction(&nodes[0], &commitment_tx));
907910
if nodes[0].connect_style.borrow().updates_best_block_first() {
911+
if anchors {
912+
handle_bump_close_event(&nodes[0]);
913+
}
908914
let mut txn = nodes[0].tx_broadcaster.txn_broadcast();
909-
assert_eq!(txn.len(), 1);
915+
assert_eq!(txn.len(), if anchors { 2 } else { 1 });
910916
assert_eq!(txn[0].compute_txid(), commitment_tx.compute_txid());
917+
if anchors {
918+
check_spends!(txn[1], txn[0]); // Anchor output spend.
919+
}
911920
}
912921

913922
let htlc_balance_known_preimage = Balance::MaybeTimeoutClaimableHTLC {
@@ -2486,6 +2495,7 @@ fn do_test_yield_anchors_events(have_htlcs: bool) {
24862495
nodes[1].node.force_close_broadcasting_latest_txn(&chan_id, &nodes[0].node.get_our_node_id(), "".to_string()).unwrap();
24872496
}
24882497
{
2498+
handle_bump_close_event(&nodes[1]);
24892499
let txn = nodes[1].tx_broadcaster.txn_broadcast();
24902500
assert_eq!(txn.len(), 1);
24912501
check_spends!(txn[0], funding_tx);
@@ -2553,15 +2563,18 @@ fn do_test_yield_anchors_events(have_htlcs: bool) {
25532563
}
25542564

25552565
{
2566+
if nodes[1].connect_style.borrow().updates_best_block_first() {
2567+
handle_bump_close_event(&nodes[1]);
2568+
}
25562569
let mut txn = nodes[1].tx_broadcaster.unique_txn_broadcast();
25572570
// Both HTLC claims are pinnable at this point,
25582571
// and will be broadcast in a single transaction.
2559-
assert_eq!(txn.len(), if nodes[1].connect_style.borrow().updates_best_block_first() { 2 } else { 1 });
2572+
assert_eq!(txn.len(), if nodes[1].connect_style.borrow().updates_best_block_first() { 3 } else { 1 });
25602573
if nodes[1].connect_style.borrow().updates_best_block_first() {
2561-
let new_commitment_tx = txn.remove(0);
2562-
check_spends!(new_commitment_tx, funding_tx);
2574+
check_spends!(txn[1], funding_tx);
2575+
check_spends!(txn[2], txn[1]); // Anchor output spend.
25632576
}
2564-
let htlc_claim_tx = txn.pop().unwrap();
2577+
let htlc_claim_tx = &txn[0];
25652578
assert_eq!(htlc_claim_tx.input.len(), 2);
25662579
assert_eq!(htlc_claim_tx.input[0].previous_output.vout, 2);
25672580
assert_eq!(htlc_claim_tx.input[1].previous_output.vout, 3);
@@ -2952,6 +2965,7 @@ fn do_test_anchors_monitor_fixes_counterparty_payment_script_on_reload(confirm_c
29522965
let reason = ClosureReason::HolderForceClosed { broadcasted_latest_txn: Some(true), message };
29532966
check_closed_event!(&nodes[0], 1, reason, false,
29542967
[nodes[1].node.get_our_node_id()], 100000);
2968+
handle_bump_close_event(&nodes[0]);
29552969

29562970
let commitment_tx = {
29572971
let mut txn = nodes[0].tx_broadcaster.unique_txn_broadcast();
@@ -3036,6 +3050,9 @@ fn do_test_monitor_claims_with_random_signatures(anchors: bool, confirm_counterp
30363050
get_monitor!(closing_node, chan_id).broadcast_latest_holder_commitment_txn(
30373051
&closing_node.tx_broadcaster, &closing_node.fee_estimator, &closing_node.logger
30383052
);
3053+
if anchors {
3054+
handle_bump_close_event(&closing_node);
3055+
}
30393056

30403057
// The commitment transaction comes first.
30413058
let commitment_tx = {

lightning/src/ln/reorg_tests.rs

Lines changed: 28 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -844,6 +844,9 @@ fn do_test_retries_own_commitment_broadcast_after_reorg(anchors: bool, revoked_c
844844
check_closed_broadcast(&nodes[0], 1, true);
845845
check_added_monitors(&nodes[0], 1);
846846
check_closed_event(&nodes[0], 1, ClosureReason::HTLCsTimedOut, false, &[nodes[1].node.get_our_node_id()], 100_000);
847+
if anchors {
848+
handle_bump_close_event(&nodes[0]);
849+
}
847850

848851
{
849852
let mut txn = nodes[0].tx_broadcaster.txn_broadcast();
@@ -870,6 +873,9 @@ fn do_test_retries_own_commitment_broadcast_after_reorg(anchors: bool, revoked_c
870873
check_added_monitors(&nodes[1], 1);
871874
let reason = ClosureReason::HolderForceClosed { broadcasted_latest_txn: Some(true), message };
872875
check_closed_event(&nodes[1], 1, reason, false, &[nodes[0].node.get_our_node_id()], 100_000);
876+
if anchors {
877+
handle_bump_close_event(&nodes[1]);
878+
}
873879

874880
let commitment_b = {
875881
let mut txn = nodes[1].tx_broadcaster.txn_broadcast();
@@ -882,13 +888,23 @@ fn do_test_retries_own_commitment_broadcast_after_reorg(anchors: bool, revoked_c
882888
// Confirm B's commitment, A should now broadcast an HTLC timeout for commitment B.
883889
mine_transaction(&nodes[0], &commitment_b);
884890
{
885-
let mut txn = nodes[0].tx_broadcaster.txn_broadcast();
886891
if nodes[0].connect_style.borrow().updates_best_block_first() {
887892
// `commitment_a` is rebroadcast because the best block was updated prior to seeing
888893
// `commitment_b`.
889-
assert_eq!(txn.len(), 2);
890-
check_spends!(txn.last().unwrap(), commitment_b);
894+
if anchors {
895+
handle_bump_close_event(&nodes[0]);
896+
let mut txn = nodes[0].tx_broadcaster.txn_broadcast();
897+
assert_eq!(txn.len(), 3);
898+
check_spends!(txn[0], commitment_b);
899+
check_spends!(txn[1], funding_tx);
900+
check_spends!(txn[2], txn[1]); // Anchor output spend transaction.
901+
} else {
902+
let mut txn = nodes[0].tx_broadcaster.txn_broadcast();
903+
assert_eq!(txn.len(), 2);
904+
check_spends!(txn.last().unwrap(), commitment_b);
905+
}
891906
} else {
907+
let mut txn = nodes[0].tx_broadcaster.txn_broadcast();
892908
assert_eq!(txn.len(), 1);
893909
check_spends!(txn[0], commitment_b);
894910
}
@@ -898,11 +914,15 @@ fn do_test_retries_own_commitment_broadcast_after_reorg(anchors: bool, revoked_c
898914
// blocks, one to get us back to the original height, and another to retry our pending claims.
899915
disconnect_blocks(&nodes[0], 1);
900916
connect_blocks(&nodes[0], 2);
917+
if anchors {
918+
handle_bump_close_event(&nodes[0]);
919+
}
901920
{
902921
let mut txn = nodes[0].tx_broadcaster.unique_txn_broadcast();
903922
if anchors {
904-
assert_eq!(txn.len(), 1);
923+
assert_eq!(txn.len(), 2);
905924
check_spends!(txn[0], funding_tx);
925+
check_spends!(txn[1], txn[0]); // Anchor output spend.
906926
} else {
907927
assert_eq!(txn.len(), 2);
908928
check_spends!(txn[0], txn[1]); // HTLC timeout A
@@ -977,6 +997,7 @@ fn do_test_split_htlc_expiry_tracking(use_third_htlc: bool, reorg_out: bool) {
977997
let message = "Channel force-closed".to_owned();
978998
let reason = ClosureReason::HolderForceClosed { broadcasted_latest_txn: Some(true), message };
979999
check_closed_event(&nodes[1], 1, reason, false, &[node_a_id], 10_000_000);
1000+
handle_bump_close_event(&nodes[1]);
9801001

9811002
let mut txn = nodes[1].tx_broadcaster.txn_broadcast();
9821003
assert_eq!(txn.len(), 1);
@@ -990,19 +1011,13 @@ fn do_test_split_htlc_expiry_tracking(use_third_htlc: bool, reorg_out: bool) {
9901011
check_added_monitors(&nodes[0], 1);
9911012

9921013
mine_transaction(&nodes[1], &commitment_tx);
993-
let mut bump_events = nodes[1].chain_monitor.chain_monitor.get_and_clear_pending_events();
994-
assert_eq!(bump_events.len(), 1);
995-
match bump_events.pop().unwrap() {
996-
Event::BumpTransaction(bump_event) => {
997-
nodes[1].bump_tx_handler.handle_event(&bump_event);
998-
},
999-
ev => panic!("Unexpected event {ev:?}"),
1000-
}
1014+
handle_bump_events(&nodes[1], nodes[1].connect_style.borrow().updates_best_block_first(), 1);
10011015

10021016
let mut txn = nodes[1].tx_broadcaster.txn_broadcast();
10031017
if nodes[1].connect_style.borrow().updates_best_block_first() {
1004-
assert_eq!(txn.len(), 2, "{txn:?}");
1018+
assert_eq!(txn.len(), 3, "{txn:?}");
10051019
check_spends!(txn[0], funding_tx);
1020+
check_spends!(txn[1], txn[0]); // Anchor output spend.
10061021
} else {
10071022
assert_eq!(txn.len(), 1, "{txn:?}");
10081023
}

0 commit comments

Comments
 (0)