Skip to content

Commit 2323b89

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 d0e4783 commit 2323b89

File tree

3 files changed

+54
-69
lines changed

3 files changed

+54
-69
lines changed

lightning/src/chain/channelmonitor.rs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3042,6 +3042,16 @@ impl<Signer: Sign> ChannelMonitorImpl<Signer> {
30423042
}
30433043

30443044
fn should_broadcast_holder_commitment_txn<L: Deref>(&self, logger: &L) -> bool where L::Target: Logger {
3045+
// There's no need to broadcast our commitment transaction if we've seen one confirmed (even
3046+
// with 1 confirmation) as it'll be rejected as duplicate/conflicting.
3047+
//
3048+
// TODO: This is currently never reset to false if the spend seen is unconfirmed, which will
3049+
// cause us to not broadcast even if we have an HTLC to claim on-chain. However, resetting
3050+
// it to false may have unintended side-effects on channel monitor updates. Perhaps we
3051+
// should introduce a new struct member for our broadcast purpose?
3052+
if self.funding_spend_seen {
3053+
return false;
3054+
}
30453055
// We need to consider all HTLCs which are:
30463056
// * in any unrevoked counterparty commitment transaction, as they could broadcast said
30473057
// 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);
@@ -8036,45 +8024,40 @@ fn test_bump_penalty_txn_on_remote_commitment() {
80368024
let feerate_preimage;
80378025
{
80388026
let mut node_txn = nodes[1].tx_broadcaster.txn_broadcasted.lock().unwrap();
8039-
// 9 transactions including:
8040-
// 1*2 ChannelManager local broadcasts of commitment + HTLC-Success
8041-
// 1*3 ChannelManager local broadcasts of commitment + HTLC-Success + HTLC-Timeout
8042-
// 2 * HTLC-Success (one RBF bump we'll check later)
8043-
// 1 * HTLC-Timeout
8044-
assert_eq!(node_txn.len(), 8);
8027+
// 5 transactions including:
8028+
// local commitment + HTLC-Success
8029+
// preimage and timeout sweeps from remote commitment + preimage sweep bump
8030+
assert_eq!(node_txn.len(), 5);
80458031
assert_eq!(node_txn[0].input.len(), 1);
8046-
assert_eq!(node_txn[6].input.len(), 1);
8032+
assert_eq!(node_txn[3].input.len(), 1);
8033+
assert_eq!(node_txn[4].input.len(), 1);
80478034
check_spends!(node_txn[0], remote_txn[0]);
8048-
check_spends!(node_txn[6], remote_txn[0]);
8049-
8050-
check_spends!(node_txn[1], chan.3);
8051-
check_spends!(node_txn[2], node_txn[1]);
8052-
8053-
if node_txn[0].input[0].previous_output == node_txn[3].input[0].previous_output {
8054-
preimage_bump = node_txn[3].clone();
8055-
check_spends!(node_txn[3], remote_txn[0]);
8035+
check_spends!(node_txn[3], remote_txn[0]);
8036+
check_spends!(node_txn[4], remote_txn[0]);
80568037

8057-
assert_eq!(node_txn[1], node_txn[4]);
8058-
assert_eq!(node_txn[2], node_txn[5]);
8059-
} else {
8060-
preimage_bump = node_txn[7].clone();
8061-
check_spends!(node_txn[7], remote_txn[0]);
8062-
assert_eq!(node_txn[0].input[0].previous_output, node_txn[7].input[0].previous_output);
8063-
8064-
assert_eq!(node_txn[1], node_txn[3]);
8065-
assert_eq!(node_txn[2], node_txn[4]);
8066-
}
8067-
8068-
timeout = node_txn[6].txid();
8069-
let index = node_txn[6].input[0].previous_output.vout;
8070-
let fee = remote_txn[0].output[index as usize].value - node_txn[6].output[0].value;
8071-
feerate_timeout = fee * 1000 / node_txn[6].weight() as u64;
8038+
check_spends!(node_txn[1], chan.3); // local commitment
8039+
check_spends!(node_txn[2], node_txn[1]); // local HTLC-Success
80728040

80738041
preimage = node_txn[0].txid();
80748042
let index = node_txn[0].input[0].previous_output.vout;
80758043
let fee = remote_txn[0].output[index as usize].value - node_txn[0].output[0].value;
80768044
feerate_preimage = fee * 1000 / node_txn[0].weight() as u64;
80778045

8046+
let (preimage_bump_tx, timeout_tx) = if node_txn[3].input[0].previous_output == node_txn[0].input[0].previous_output {
8047+
(node_txn[3].clone(), node_txn[4].clone())
8048+
} else {
8049+
(node_txn[4].clone(), node_txn[3].clone())
8050+
};
8051+
8052+
preimage_bump = preimage_bump_tx;
8053+
check_spends!(preimage_bump, remote_txn[0]);
8054+
assert_eq!(node_txn[0].input[0].previous_output, preimage_bump.input[0].previous_output);
8055+
8056+
timeout = timeout_tx.txid();
8057+
let index = timeout_tx.input[0].previous_output.vout;
8058+
let fee = remote_txn[0].output[index as usize].value - timeout_tx.output[0].value;
8059+
feerate_timeout = fee * 1000 / timeout_tx.weight() as u64;
8060+
80788061
node_txn.clear();
80798062
};
80808063
assert_ne!(feerate_timeout, 0);
@@ -8950,11 +8933,8 @@ fn test_concurrent_monitor_claim() {
89508933
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);
89518934
{
89528935
let htlc_txn = chanmon_cfgs[0].tx_broadcaster.txn_broadcasted.lock().unwrap();
8953-
// We broadcast twice the transaction, once due to the HTLC-timeout, once due
8954-
// the onchain detection of the HTLC output
8955-
assert_eq!(htlc_txn.len(), 2);
8936+
assert_eq!(htlc_txn.len(), 1);
89568937
check_spends!(htlc_txn[0], bob_state_y);
8957-
check_spends!(htlc_txn[1], bob_state_y);
89588938
}
89598939
}
89608940

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)