Skip to content

Commit 03cb83c

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 fe826e7 commit 03cb83c

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
@@ -765,7 +765,10 @@ pub(crate) struct ChannelMonitorImpl<Signer: Sign> {
765765
// of block connection between ChannelMonitors and the ChannelManager.
766766
funding_spend_seen: bool,
767767

768+
/// Set to `Some` of the confirmed transaction spending the funding input of the channel after
769+
/// reaching `ANTI_REORG_DELAY` confirmations.
768770
funding_spend_confirmed: Option<Txid>,
771+
769772
confirmed_commitment_tx_counterparty_output: CommitmentTxCounterpartyOutputInfo,
770773
/// The set of HTLCs which have been either claimed or failed on chain and have reached
771774
/// the requisite confirmations on the claim/fail transaction (either ANTI_REORG_DELAY or the
@@ -3042,6 +3045,16 @@ impl<Signer: Sign> ChannelMonitorImpl<Signer> {
30423045
}
30433046

30443047
fn should_broadcast_holder_commitment_txn<L: Deref>(&self, logger: &L) -> bool where L::Target: Logger {
3048+
// There's no need to broadcast our commitment transaction if we've seen one confirmed (even
3049+
// with 1 confirmation) as it'll be rejected as duplicate/conflicting.
3050+
if self.funding_spend_confirmed.is_some() ||
3051+
self.onchain_events_awaiting_threshold_conf.iter().find(|event| match event.event {
3052+
OnchainEvent::FundingSpendConfirmation { .. } => true,
3053+
_ => false,
3054+
}).is_some()
3055+
{
3056+
return false;
3057+
}
30453058
// We need to consider all HTLCs which are:
30463059
// * in any unrevoked counterparty commitment transaction, as they could broadcast said
30473060
// 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)