Skip to content

Commit 494d7dd

Browse files
committed
Switch to height-based funding-tx tracking from conf-based tracking
Previously, we expected every block to be connected in-order, allowing us to track confirmations by simply incrementing a counter for each new block connected. In anticipation of moving to a update-height model in the next commit, this moves to tracking confirmations by simply storing the height at which the funding transaction was confirmed. This commit also corrects our "funding was reorganized out of the best chain" heuristic, instead of a flat 6 blocks, it uses half the confirmation count required as the point at which we force-close. Even still, for low confirmation counts (eg 1 block), an ill-timed reorg may still cause spurious force-closes, though that behavior is not new in this commit.
1 parent 8a8c75a commit 494d7dd

File tree

2 files changed

+26
-31
lines changed

2 files changed

+26
-31
lines changed

lightning/src/ln/channel.rs

Lines changed: 24 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -376,13 +376,10 @@ pub(super) struct Channel<Signer: Sign> {
376376

377377
last_sent_closing_fee: Option<(u32, u64, Signature)>, // (feerate, fee, holder_sig)
378378

379-
/// The hash of the block in which the funding transaction reached our CONF_TARGET. We use this
380-
/// to detect unconfirmation after a serialize-unserialize roundtrip where we may not see a full
381-
/// series of block_connected/block_disconnected calls. Obviously this is not a guarantee as we
382-
/// could miss the funding_tx_confirmed_in block as well, but it serves as a useful fallback.
379+
/// The hash of the block in which the funding transaction was included.
383380
funding_tx_confirmed_in: Option<BlockHash>,
381+
funding_tx_confirmation_height: u64,
384382
short_channel_id: Option<u64>,
385-
funding_tx_confirmations: u64,
386383

387384
counterparty_dust_limit_satoshis: u64,
388385
#[cfg(test)]
@@ -441,10 +438,6 @@ struct CommitmentTxInfoCached {
441438
}
442439

443440
pub const OUR_MAX_HTLCS: u16 = 50; //TODO
444-
/// Confirmation count threshold at which we close a channel. Ideally we'd keep the channel around
445-
/// on ice until the funding transaction gets more confirmations, but the LN protocol doesn't
446-
/// really allow for this, so instead we're stuck closing it out at that point.
447-
const UNCONF_THRESHOLD: u32 = 6;
448441
const SPENDING_INPUT_FOR_A_OUTPUT_WEIGHT: u64 = 79; // prevout: 36, nSequence: 4, script len: 1, witness lengths: (3+1)/4, sig: 73/4, if-selector: 1, redeemScript: (6 ops + 2*33 pubkeys + 1*2 delay)/4
449442
const B_OUTPUT_PLUS_SPENDING_INPUT_WEIGHT: u64 = 104; // prevout: 40, nSequence: 4, script len: 1, witness lengths: 3/4, sig: 73/4, pubkey: 33/4, output: 31 (TODO: Wrong? Useless?)
450443

@@ -581,8 +574,8 @@ impl<Signer: Sign> Channel<Signer> {
581574
last_sent_closing_fee: None,
582575

583576
funding_tx_confirmed_in: None,
577+
funding_tx_confirmation_height: 0,
584578
short_channel_id: None,
585-
funding_tx_confirmations: 0,
586579

587580
feerate_per_kw: feerate,
588581
counterparty_dust_limit_satoshis: 0,
@@ -818,8 +811,8 @@ impl<Signer: Sign> Channel<Signer> {
818811
last_sent_closing_fee: None,
819812

820813
funding_tx_confirmed_in: None,
814+
funding_tx_confirmation_height: 0,
821815
short_channel_id: None,
822-
funding_tx_confirmations: 0,
823816

824817
feerate_per_kw: msg.feerate_per_kw,
825818
channel_value_satoshis: msg.funding_satoshis,
@@ -3537,10 +3530,6 @@ impl<Signer: Sign> Channel<Signer> {
35373530
}
35383531
});
35393532

3540-
if self.funding_tx_confirmations > 0 {
3541-
self.funding_tx_confirmations += 1;
3542-
}
3543-
35443533
let non_shutdown_state = self.channel_state & (!MULTI_STATE_FLAGS);
35453534
if non_shutdown_state & !(ChannelState::TheirFundingLocked as u32) == ChannelState::FundingSent as u32 {
35463535
for &(index_in_block, tx) in txdata.iter() {
@@ -3575,7 +3564,8 @@ impl<Signer: Sign> Channel<Signer> {
35753564
}
35763565
}
35773566
}
3578-
self.funding_tx_confirmations = 1;
3567+
self.funding_tx_confirmation_height = height as u64;
3568+
self.funding_tx_confirmed_in = Some(header.block_hash());
35793569
self.short_channel_id = match scid_from_parts(height as u64, index_in_block as u64, txo_idx as u64) {
35803570
Ok(scid) => Some(scid),
35813571
Err(_) => panic!("Block was bogus - either height was > 16 million, had > 16 million transactions, or had > 65k outputs"),
@@ -3585,9 +3575,11 @@ impl<Signer: Sign> Channel<Signer> {
35853575
}
35863576
}
35873577

3578+
35883579
self.update_time_counter = cmp::max(self.update_time_counter, header.time);
3589-
if self.funding_tx_confirmations > 0 {
3590-
if self.funding_tx_confirmations == self.minimum_depth as u64 {
3580+
if self.funding_tx_confirmation_height > 0 {
3581+
let funding_tx_confirmations = height as i64 - self.funding_tx_confirmation_height as i64 + 1;
3582+
if funding_tx_confirmations == self.minimum_depth as i64 {
35913583
let need_commitment_update = if non_shutdown_state == ChannelState::FundingSent as u32 {
35923584
self.channel_state |= ChannelState::OurFundingLocked as u32;
35933585
true
@@ -3606,7 +3598,6 @@ impl<Signer: Sign> Channel<Signer> {
36063598
// funding_tx_confirmed_in and return.
36073599
false
36083600
};
3609-
self.funding_tx_confirmed_in = Some(header.block_hash());
36103601

36113602
//TODO: Note that this must be a duplicate of the previous commitment point they sent us,
36123603
//as otherwise we will have a commitment transaction that they can't revoke (well, kinda,
@@ -3632,16 +3623,20 @@ impl<Signer: Sign> Channel<Signer> {
36323623
/// Called by channelmanager based on chain blocks being disconnected.
36333624
/// Returns true if we need to close the channel now due to funding transaction
36343625
/// unconfirmation/reorg.
3635-
pub fn block_disconnected(&mut self, header: &BlockHeader) -> bool {
3636-
if self.funding_tx_confirmations > 0 {
3637-
self.funding_tx_confirmations -= 1;
3638-
if self.funding_tx_confirmations == UNCONF_THRESHOLD as u64 {
3626+
pub fn block_disconnected(&mut self, header: &BlockHeader, height: u32) -> bool {
3627+
if self.funding_tx_confirmation_height > 0 {
3628+
let funding_tx_confirmations = height as i64 - self.funding_tx_confirmation_height as i64 + 1;
3629+
if funding_tx_confirmations <= 0 {
3630+
self.funding_tx_confirmation_height = 0;
3631+
}
3632+
3633+
let non_shutdown_state = self.channel_state & (!MULTI_STATE_FLAGS);
3634+
if (non_shutdown_state >= ChannelState::ChannelFunded as u32 ||
3635+
(non_shutdown_state & ChannelState::OurFundingLocked as u32) == ChannelState::OurFundingLocked as u32) &&
3636+
funding_tx_confirmations < self.minimum_depth as i64 / 2 {
36393637
return true;
36403638
}
36413639
}
3642-
if Some(header.block_hash()) == self.funding_tx_confirmed_in {
3643-
self.funding_tx_confirmations = self.minimum_depth as u64 - 1;
3644-
}
36453640
false
36463641
}
36473642

@@ -4466,8 +4461,8 @@ impl<Signer: Sign> Writeable for Channel<Signer> {
44664461
}
44674462

44684463
self.funding_tx_confirmed_in.write(writer)?;
4464+
self.funding_tx_confirmation_height.write(writer)?;
44694465
self.short_channel_id.write(writer)?;
4470-
self.funding_tx_confirmations.write(writer)?;
44714466

44724467
self.counterparty_dust_limit_satoshis.write(writer)?;
44734468
self.holder_dust_limit_satoshis.write(writer)?;
@@ -4636,8 +4631,8 @@ impl<'a, Signer: Sign, K: Deref> ReadableArgs<&'a K> for Channel<Signer>
46364631
};
46374632

46384633
let funding_tx_confirmed_in = Readable::read(reader)?;
4634+
let funding_tx_confirmation_height = Readable::read(reader)?;
46394635
let short_channel_id = Readable::read(reader)?;
4640-
let funding_tx_confirmations = Readable::read(reader)?;
46414636

46424637
let counterparty_dust_limit_satoshis = Readable::read(reader)?;
46434638
let holder_dust_limit_satoshis = Readable::read(reader)?;
@@ -4716,8 +4711,8 @@ impl<'a, Signer: Sign, K: Deref> ReadableArgs<&'a K> for Channel<Signer>
47164711
last_sent_closing_fee,
47174712

47184713
funding_tx_confirmed_in,
4714+
funding_tx_confirmation_height,
47194715
short_channel_id,
4720-
funding_tx_confirmations,
47214716

47224717
counterparty_dust_limit_satoshis,
47234718
holder_dust_limit_satoshis,

lightning/src/ln/channelmanager.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3424,7 +3424,7 @@ impl<Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> ChannelMana
34243424

34253425
assert_eq!(*self.last_block_hash.read().unwrap(), header.block_hash(),
34263426
"Blocks must be disconnected in chain-order - the disconnected header must be the last connected header");
3427-
self.latest_block_height.fetch_sub(1, Ordering::AcqRel);
3427+
let new_height = self.latest_block_height.fetch_sub(1, Ordering::AcqRel) as u32 - 1;
34283428
*self.last_block_hash.write().unwrap() = header.prev_blockhash;
34293429

34303430
let mut failed_channels = Vec::new();
@@ -3434,7 +3434,7 @@ impl<Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> ChannelMana
34343434
let short_to_id = &mut channel_state.short_to_id;
34353435
let pending_msg_events = &mut channel_state.pending_msg_events;
34363436
channel_state.by_id.retain(|_, v| {
3437-
if v.block_disconnected(header) {
3437+
if v.block_disconnected(header, new_height) {
34383438
if let Some(short_id) = v.get_short_channel_id() {
34393439
short_to_id.remove(&short_id);
34403440
}

0 commit comments

Comments
 (0)