Skip to content

Commit 62236c7

Browse files
committed
Avoid commitment broadcast upon detected funding spend
There's no need to broadcast our local commitment transaction if we've already seen a confirmed one as it'll be immediately rejected as a duplicate/conflict. This will also help prevent dispatching spurious events for bumping commitment and HTLC transactions through anchor outputs (once implemented in future work) and the dispatch for said events follows the same flow as our usual commitment broadcast.
1 parent 2f4a1f7 commit 62236c7

File tree

3 files changed

+57
-69
lines changed

3 files changed

+57
-69
lines changed

lightning/src/chain/channelmonitor.rs

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -793,7 +793,10 @@ pub(crate) struct ChannelMonitorImpl<Signer: Sign> {
793793
// of block connection between ChannelMonitors and the ChannelManager.
794794
funding_spend_seen: bool,
795795

796+
/// Set to `Some` of the confirmed transaction spending the funding input of the channel after
797+
/// reaching `ANTI_REORG_DELAY` confirmations.
796798
funding_spend_confirmed: Option<Txid>,
799+
797800
confirmed_commitment_tx_counterparty_output: CommitmentTxCounterpartyOutputInfo,
798801
/// The set of HTLCs which have been either claimed or failed on chain and have reached
799802
/// the requisite confirmations on the claim/fail transaction (either ANTI_REORG_DELAY or the
@@ -3068,6 +3071,16 @@ impl<Signer: Sign> ChannelMonitorImpl<Signer> {
30683071
}
30693072

30703073
fn should_broadcast_holder_commitment_txn<L: Deref>(&self, logger: &L) -> bool where L::Target: Logger {
3074+
// There's no need to broadcast our commitment transaction if we've seen one confirmed (even
3075+
// with 1 confirmation) as it'll be rejected as duplicate/conflicting.
3076+
if self.funding_spend_confirmed.is_some() ||
3077+
self.onchain_events_awaiting_threshold_conf.iter().find(|event| match event.event {
3078+
OnchainEvent::FundingSpendConfirmation { .. } => true,
3079+
_ => false,
3080+
}).is_some()
3081+
{
3082+
return false;
3083+
}
30713084
// We need to consider all HTLCs which are:
30723085
// * in any unrevoked counterparty commitment transaction, as they could broadcast said
30733086
// transactions and we'd end up in a race, or

lightning/src/ln/functional_tests.rs

Lines changed: 42 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -1267,44 +1267,32 @@ fn test_duplicate_htlc_different_direction_onchain() {
12671267
connect_blocks(&nodes[0], TEST_FINAL_CLTV - 1); // Confirm blocks until the HTLC expires
12681268

12691269
let claim_txn = nodes[0].tx_broadcaster.txn_broadcasted.lock().unwrap().clone();
1270-
assert_eq!(claim_txn.len(), 8);
1270+
assert_eq!(claim_txn.len(), 5);
12711271

12721272
check_spends!(claim_txn[0], remote_txn[0]); // Immediate HTLC claim with preimage
1273-
12741273
check_spends!(claim_txn[1], chan_1.3); // Alternative commitment tx
12751274
check_spends!(claim_txn[2], claim_txn[1]); // HTLC spend in alternative commitment tx
12761275

1277-
let bump_tx = if claim_txn[1] == claim_txn[4] {
1278-
assert_eq!(claim_txn[1], claim_txn[4]);
1279-
assert_eq!(claim_txn[2], claim_txn[5]);
1280-
1281-
check_spends!(claim_txn[7], claim_txn[1]); // HTLC timeout on alternative commitment tx
1282-
1283-
check_spends!(claim_txn[3], remote_txn[0]); // HTLC timeout on broadcasted commitment tx
1284-
&claim_txn[3]
1276+
check_spends!(claim_txn[3], remote_txn[0]);
1277+
check_spends!(claim_txn[4], remote_txn[0]);
1278+
let preimage_tx = &claim_txn[0];
1279+
let (preimage_bump_tx, timeout_tx) = if claim_txn[3].input[0].previous_output == preimage_tx.input[0].previous_output {
1280+
(&claim_txn[3], &claim_txn[4])
12851281
} else {
1286-
assert_eq!(claim_txn[1], claim_txn[3]);
1287-
assert_eq!(claim_txn[2], claim_txn[4]);
1288-
1289-
check_spends!(claim_txn[5], claim_txn[1]); // HTLC timeout on alternative commitment tx
1290-
1291-
check_spends!(claim_txn[7], remote_txn[0]); // HTLC timeout on broadcasted commitment tx
1292-
1293-
&claim_txn[7]
1282+
(&claim_txn[4], &claim_txn[3])
12941283
};
12951284

1296-
assert_eq!(claim_txn[0].input.len(), 1);
1297-
assert_eq!(bump_tx.input.len(), 1);
1298-
assert_eq!(claim_txn[0].input[0].previous_output, bump_tx.input[0].previous_output);
1285+
assert_eq!(preimage_tx.input.len(), 1);
1286+
assert_eq!(preimage_bump_tx.input.len(), 1);
12991287

1300-
assert_eq!(claim_txn[0].input.len(), 1);
1301-
assert_eq!(claim_txn[0].input[0].witness.last().unwrap().len(), OFFERED_HTLC_SCRIPT_WEIGHT); // HTLC 1 <--> 0, preimage tx
1302-
assert_eq!(remote_txn[0].output[claim_txn[0].input[0].previous_output.vout as usize].value, 800);
1288+
assert_eq!(preimage_tx.input.len(), 1);
1289+
assert_eq!(preimage_tx.input[0].witness.last().unwrap().len(), OFFERED_HTLC_SCRIPT_WEIGHT); // HTLC 1 <--> 0, preimage tx
1290+
assert_eq!(remote_txn[0].output[preimage_tx.input[0].previous_output.vout as usize].value, 800);
13031291

1304-
assert_eq!(claim_txn[6].input.len(), 1);
1305-
assert_eq!(claim_txn[6].input[0].witness.last().unwrap().len(), ACCEPTED_HTLC_SCRIPT_WEIGHT); // HTLC 0 <--> 1, timeout tx
1306-
check_spends!(claim_txn[6], remote_txn[0]);
1307-
assert_eq!(remote_txn[0].output[claim_txn[6].input[0].previous_output.vout as usize].value, 900);
1292+
assert_eq!(timeout_tx.input.len(), 1);
1293+
assert_eq!(timeout_tx.input[0].witness.last().unwrap().len(), ACCEPTED_HTLC_SCRIPT_WEIGHT); // HTLC 0 <--> 1, timeout tx
1294+
check_spends!(timeout_tx, remote_txn[0]);
1295+
assert_eq!(remote_txn[0].output[timeout_tx.input[0].previous_output.vout as usize].value, 900);
13081296

13091297
let events = nodes[0].node.get_and_clear_pending_msg_events();
13101298
assert_eq!(events.len(), 3);
@@ -8100,45 +8088,40 @@ fn test_bump_penalty_txn_on_remote_commitment() {
81008088
let feerate_preimage;
81018089
{
81028090
let mut node_txn = nodes[1].tx_broadcaster.txn_broadcasted.lock().unwrap();
8103-
// 9 transactions including:
8104-
// 1*2 ChannelManager local broadcasts of commitment + HTLC-Success
8105-
// 1*3 ChannelManager local broadcasts of commitment + HTLC-Success + HTLC-Timeout
8106-
// 2 * HTLC-Success (one RBF bump we'll check later)
8107-
// 1 * HTLC-Timeout
8108-
assert_eq!(node_txn.len(), 8);
8091+
// 5 transactions including:
8092+
// local commitment + HTLC-Success
8093+
// preimage and timeout sweeps from remote commitment + preimage sweep bump
8094+
assert_eq!(node_txn.len(), 5);
81098095
assert_eq!(node_txn[0].input.len(), 1);
8110-
assert_eq!(node_txn[6].input.len(), 1);
8096+
assert_eq!(node_txn[3].input.len(), 1);
8097+
assert_eq!(node_txn[4].input.len(), 1);
81118098
check_spends!(node_txn[0], remote_txn[0]);
8112-
check_spends!(node_txn[6], remote_txn[0]);
8113-
8114-
check_spends!(node_txn[1], chan.3);
8115-
check_spends!(node_txn[2], node_txn[1]);
8116-
8117-
if node_txn[0].input[0].previous_output == node_txn[3].input[0].previous_output {
8118-
preimage_bump = node_txn[3].clone();
8119-
check_spends!(node_txn[3], remote_txn[0]);
8099+
check_spends!(node_txn[3], remote_txn[0]);
8100+
check_spends!(node_txn[4], remote_txn[0]);
81208101

8121-
assert_eq!(node_txn[1], node_txn[4]);
8122-
assert_eq!(node_txn[2], node_txn[5]);
8123-
} else {
8124-
preimage_bump = node_txn[7].clone();
8125-
check_spends!(node_txn[7], remote_txn[0]);
8126-
assert_eq!(node_txn[0].input[0].previous_output, node_txn[7].input[0].previous_output);
8127-
8128-
assert_eq!(node_txn[1], node_txn[3]);
8129-
assert_eq!(node_txn[2], node_txn[4]);
8130-
}
8131-
8132-
timeout = node_txn[6].txid();
8133-
let index = node_txn[6].input[0].previous_output.vout;
8134-
let fee = remote_txn[0].output[index as usize].value - node_txn[6].output[0].value;
8135-
feerate_timeout = fee * 1000 / node_txn[6].weight() as u64;
8102+
check_spends!(node_txn[1], chan.3); // local commitment
8103+
check_spends!(node_txn[2], node_txn[1]); // local HTLC-Success
81368104

81378105
preimage = node_txn[0].txid();
81388106
let index = node_txn[0].input[0].previous_output.vout;
81398107
let fee = remote_txn[0].output[index as usize].value - node_txn[0].output[0].value;
81408108
feerate_preimage = fee * 1000 / node_txn[0].weight() as u64;
81418109

8110+
let (preimage_bump_tx, timeout_tx) = if node_txn[3].input[0].previous_output == node_txn[0].input[0].previous_output {
8111+
(node_txn[3].clone(), node_txn[4].clone())
8112+
} else {
8113+
(node_txn[4].clone(), node_txn[3].clone())
8114+
};
8115+
8116+
preimage_bump = preimage_bump_tx;
8117+
check_spends!(preimage_bump, remote_txn[0]);
8118+
assert_eq!(node_txn[0].input[0].previous_output, preimage_bump.input[0].previous_output);
8119+
8120+
timeout = timeout_tx.txid();
8121+
let index = timeout_tx.input[0].previous_output.vout;
8122+
let fee = remote_txn[0].output[index as usize].value - timeout_tx.output[0].value;
8123+
feerate_timeout = fee * 1000 / timeout_tx.weight() as u64;
8124+
81428125
node_txn.clear();
81438126
};
81448127
assert_ne!(feerate_timeout, 0);
@@ -9014,11 +8997,8 @@ fn test_concurrent_monitor_claim() {
90148997
watchtower_alice.chain_monitor.block_connected(&Block { header, txdata: vec![bob_state_y.clone()] }, CHAN_CONFIRM_DEPTH + 2 + TEST_FINAL_CLTV + LATENCY_GRACE_PERIOD_BLOCKS);
90158998
{
90168999
let htlc_txn = chanmon_cfgs[0].tx_broadcaster.txn_broadcasted.lock().unwrap();
9017-
// We broadcast twice the transaction, once due to the HTLC-timeout, once due
9018-
// the onchain detection of the HTLC output
9019-
assert_eq!(htlc_txn.len(), 2);
9000+
assert_eq!(htlc_txn.len(), 1);
90209001
check_spends!(htlc_txn[0], bob_state_y);
9021-
check_spends!(htlc_txn[1], bob_state_y);
90229002
}
90239003
}
90249004

lightning/src/ln/payment_tests.rs

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -508,13 +508,8 @@ fn do_retry_with_no_persist(confirm_before_reload: bool) {
508508
expect_payment_sent!(nodes[0], payment_preimage_1);
509509
connect_blocks(&nodes[0], TEST_FINAL_CLTV*4 + 20);
510510
let as_htlc_timeout_txn = nodes[0].tx_broadcaster.txn_broadcasted.lock().unwrap().split_off(0);
511-
assert_eq!(as_htlc_timeout_txn.len(), 3);
512-
let (first_htlc_timeout_tx, second_htlc_timeout_tx) = if as_htlc_timeout_txn[0] == as_commitment_tx {
513-
(&as_htlc_timeout_txn[1], &as_htlc_timeout_txn[2])
514-
} else {
515-
assert_eq!(as_htlc_timeout_txn[2], as_commitment_tx);
516-
(&as_htlc_timeout_txn[0], &as_htlc_timeout_txn[1])
517-
};
511+
assert_eq!(as_htlc_timeout_txn.len(), 2);
512+
let (first_htlc_timeout_tx, second_htlc_timeout_tx) = (&as_htlc_timeout_txn[0], &as_htlc_timeout_txn[1]);
518513
check_spends!(first_htlc_timeout_tx, as_commitment_tx);
519514
check_spends!(second_htlc_timeout_tx, as_commitment_tx);
520515
if first_htlc_timeout_tx.input[0].previous_output == bs_htlc_claim_txn[0].input[0].previous_output {

0 commit comments

Comments
 (0)