Skip to content

Commit dac2cc2

Browse files
committed
Increase min CLTV delta and delta before CLTV at which chans close
In the previous commit it was observed that we actually have to run the whole "get a transaction confirmed" process from start to finish twice to claim an HTLC on an anchor channel. This leaves us with only 9 blocks to get each transaction confirmed, which is quite aggressive. Here we double this threshold, force-closing channels which have an expiring HTLC 36 blocks before expiry instead of 18. We also increase the minimum CLTV expiry delta to 48 to ensure we have at least a few blocks after the transactions get confirmed before we need to fail the inbound edge of a forwarded HTLC back. We do not change the default CLTV expiry delta of 72 blocks.
1 parent 95933c2 commit dac2cc2

File tree

3 files changed

+20
-26
lines changed

3 files changed

+20
-26
lines changed

lightning/src/chain/channelmonitor.rs

+5-5
Original file line numberDiff line numberDiff line change
@@ -222,13 +222,13 @@ impl_writeable_tlv_based!(HTLCUpdate, {
222222
/// transaction.
223223
pub(crate) const COUNTERPARTY_CLAIMABLE_WITHIN_BLOCKS_PINNABLE: u32 = 12;
224224

225-
/// When we go to force-close a channel because an HTLC is expiring, we should ensure that the
226-
/// HTLC(s) expiring are not considered pinnable, allowing us to aggregate them with other HTLC(s)
227-
/// expiring at the same time.
228-
const _: () = assert!(CLTV_CLAIM_BUFFER > COUNTERPARTY_CLAIMABLE_WITHIN_BLOCKS_PINNABLE);
225+
/// When we go to force-close a channel because an HTLC is expiring, by the time we've gotten the
226+
/// commitment transaction confirmed, we should ensure that the HTLC(s) expiring are not considered
227+
/// pinnable, allowing us to aggregate them with other HTLC(s) expiring at the same time.
228+
const _: () = assert!(MAX_BLOCKS_FOR_CONF > COUNTERPARTY_CLAIMABLE_WITHIN_BLOCKS_PINNABLE);
229229

230230
/// The upper bound on how many blocks we think it can take for us to get a transaction confirmed.
231-
pub(crate) const MAX_BLOCKS_FOR_CONF: u32 = 9;
231+
pub(crate) const MAX_BLOCKS_FOR_CONF: u32 = 18;
232232

233233
/// If an HTLC expires within this many blocks, force-close the channel to broadcast the
234234
/// HTLC-Success transaction.

lightning/src/ln/channelmanager.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -2823,7 +2823,7 @@ pub(crate) const MAX_LOCAL_BREAKDOWN_TIMEOUT: u16 = 2 * 6 * 24 * 7;
28232823
// i.e. the node we forwarded the payment on to should always have enough room to reliably time out
28242824
// the HTLC via a full update_fail_htlc/commitment_signed dance before we hit the
28252825
// CLTV_CLAIM_BUFFER point (we static assert that it's at least 3 blocks more).
2826-
pub const MIN_CLTV_EXPIRY_DELTA: u16 = 6*7;
2826+
pub const MIN_CLTV_EXPIRY_DELTA: u16 = 6*8;
28272827
// This should be long enough to allow a payment path drawn across multiple routing hops with substantial
28282828
// `cltv_expiry_delta`. Indeed, the length of those values is the reaction delay offered to a routing node
28292829
// in case of HTLC on-chain settlement. While appearing less competitive, a node operator could decide to

lightning/src/ln/functional_tests.rs

+14-20
Original file line numberDiff line numberDiff line change
@@ -3494,7 +3494,7 @@ fn do_test_htlc_on_chain_timeout(connect_style: ConnectStyle) {
34943494
let node_txn = nodes[0].tx_broadcaster.txn_broadcasted.lock().unwrap().clone(); // 1 timeout tx
34953495
assert_eq!(node_txn.len(), 1);
34963496
check_spends!(node_txn[0], commitment_tx[0]);
3497-
assert_eq!(node_txn[0].clone().input[0].witness.last().unwrap().len(), ACCEPTED_HTLC_SCRIPT_WEIGHT);
3497+
assert_eq!(node_txn[0].clone().input[0].witness.last().unwrap().len(), ACCEPTED_HTLC_SCRIPT_WEIGHT + 1);
34983498
}
34993499

35003500
#[test]
@@ -9321,25 +9321,19 @@ fn do_test_onchain_htlc_settlement_after_close(broadcast_alice: bool, go_onchain
93219321
// Step (6):
93229322
// Finally, check that Bob broadcasted a preimage-claiming transaction for the HTLC output on the
93239323
// broadcasted commitment transaction.
9324-
{
9325-
let script_weight = match broadcast_alice {
9326-
true => OFFERED_HTLC_SCRIPT_WEIGHT,
9327-
false => ACCEPTED_HTLC_SCRIPT_WEIGHT
9328-
};
9329-
// If Alice force-closed, Bob only broadcasts a HTLC-output-claiming transaction. Otherwise,
9330-
// Bob force-closed and broadcasts the commitment transaction along with a
9331-
// HTLC-output-claiming transaction.
9332-
let mut bob_txn = nodes[1].tx_broadcaster.txn_broadcasted.lock().unwrap().clone();
9333-
if broadcast_alice {
9334-
assert_eq!(bob_txn.len(), 1);
9335-
check_spends!(bob_txn[0], txn_to_broadcast[0]);
9336-
assert_eq!(bob_txn[0].input[0].witness.last().unwrap().len(), script_weight);
9337-
} else {
9338-
assert_eq!(bob_txn.len(), if nodes[1].connect_style.borrow().updates_best_block_first() { 3 } else { 2 });
9339-
let htlc_tx = bob_txn.pop().unwrap();
9340-
check_spends!(htlc_tx, txn_to_broadcast[0]);
9341-
assert_eq!(htlc_tx.input[0].witness.last().unwrap().len(), script_weight);
9342-
}
9324+
// If Alice force-closed, Bob only broadcasts a HTLC-output-claiming transaction. Otherwise,
9325+
// Bob force-closed and broadcasts the commitment transaction along with a
9326+
// HTLC-output-claiming transaction.
9327+
let mut bob_txn = nodes[1].tx_broadcaster.txn_broadcasted.lock().unwrap().clone();
9328+
if broadcast_alice {
9329+
assert_eq!(bob_txn.len(), 1);
9330+
check_spends!(bob_txn[0], txn_to_broadcast[0]);
9331+
assert_eq!(bob_txn[0].input[0].witness.last().unwrap().len(), OFFERED_HTLC_SCRIPT_WEIGHT);
9332+
} else {
9333+
assert_eq!(bob_txn.len(), if nodes[1].connect_style.borrow().updates_best_block_first() { 3 } else { 2 });
9334+
let htlc_tx = bob_txn.pop().unwrap();
9335+
check_spends!(htlc_tx, txn_to_broadcast[0]);
9336+
assert_eq!(htlc_tx.input[0].witness.last().unwrap().len(), ACCEPTED_HTLC_SCRIPT_WEIGHT + 1);
93439337
}
93449338
}
93459339

0 commit comments

Comments
 (0)