From 2918c4ab31241954a0cccf70652d9df9368cf6f2 Mon Sep 17 00:00:00 2001 From: optout <13562139+optout21@users.noreply.github.com> Date: Thu, 16 Nov 2023 09:06:27 +0100 Subject: [PATCH] Refactor channel funding transaction fields --- lightning/src/ln/chan_utils.rs | 206 ++++++++++++++++++++++++++++- lightning/src/ln/channel.rs | 83 +++++------- lightning/src/ln/channelmanager.rs | 4 +- 3 files changed, 241 insertions(+), 52 deletions(-) diff --git a/lightning/src/ln/chan_utils.rs b/lightning/src/ln/chan_utils.rs index 1c068025b8f..f09fa8d8b0f 100644 --- a/lightning/src/ln/chan_utils.rs +++ b/lightning/src/ln/chan_utils.rs @@ -19,7 +19,7 @@ use bitcoin::util::address::Payload; use bitcoin::hashes::{Hash, HashEngine}; use bitcoin::hashes::sha256::Hash as Sha256; use bitcoin::hashes::ripemd160::Hash as Ripemd160; -use bitcoin::hash_types::{Txid, PubkeyHash, WPubkeyHash}; +use bitcoin::hash_types::{BlockHash, Txid, PubkeyHash, WPubkeyHash}; use crate::chain::chaininterface::fee_for_weight; use crate::chain::package::WEIGHT_REVOKED_OUTPUT; @@ -858,6 +858,210 @@ pub fn build_anchor_input_witness(funding_key: &PublicKey, funding_sig: &Signatu ret } +pub(crate) struct ChannelFundingTransaction { + tx: Option, + txo: Option, + /// The hash of the block in which the funding transaction was included. + tx_confirmed_in: Option, + tx_confirmation_height: Option, +} + +/// Stores into about a funding transaction: +/// - TX outpoint and/or the full Transaction +/// - confirmation block/height for confirmed transactions +impl ChannelFundingTransaction { + pub(crate) fn new_empty() -> Self { + Self { tx: None, txo: None, tx_confirmed_in: None, tx_confirmation_height: None } + } + + pub(crate) fn get_tx(&self) -> Option<&Transaction> { self.tx.as_ref() } + + pub(crate) fn set_tx(&mut self, tx: Transaction) { + self.tx = Some(tx); + } + + pub(crate) fn set_txo(&mut self, txo: chain::transaction::OutPoint) { + self.txo = Some(txo); + } + + pub(crate) fn is_confirmed(&self) -> bool { + self.tx_confirmation_height.is_some() && self.tx_confirmed_in.is_some() + } + + /// Returns the current number of confirmations + pub(crate) fn get_tx_confirmations(&mut self, height: u32) -> Option { + match self.tx_confirmation_height { + // We either haven't seen any confirmation yet, or observed a reorg. + None => None, + Some(h) => { + let confs = height as i64 - h as i64 + 1; + // Reset on reorg + if confs <= 0 { + self.tx_confirmation_height = None; + } + Some(confs) + } + } + } + + /// Returns the current number of confirmations + pub(crate) fn get_tx_confirmations_nocheck(&self, height: u32) -> Option { + match self.tx_confirmation_height { + // We either haven't seen any confirmation yet, or observed a reorg. + None => None, + Some(h) => height.checked_sub(h).map(|c| c + 1) + } + } + + fn set_confirmed(&mut self, block_hash: BlockHash, block_height: u32) { + // TODO check if confirmed already + self.tx_confirmed_in = Some(block_hash); + self.tx_confirmation_height = Some(block_height); + } + + // fn reset_unconfirmed(&mut self) { + // self.tx_confirmed_in = None; + // self.tx_confirmation_height = None; + // } + + pub(crate) fn get_tx_confirmed_in(&self) -> Option { self.tx_confirmed_in } + pub(crate) fn get_tx_confirmation_height(&self) -> Option { self.tx_confirmation_height } +} + +impl Writeable for ChannelFundingTransaction { + fn write(&self, writer: &mut W) -> Result<(), io::Error> { + self.tx.write(writer)?; + self.txo.write(writer)?; + self.tx_confirmed_in.write(writer)?; + self.tx_confirmation_height.write(writer)?; + Ok(()) + } +} + +impl Readable for ChannelFundingTransaction { + fn read(reader: &mut R) -> Result { + let tx = Readable::read(reader)?; + let txo = Readable::read(reader)?; + let tx_confirmed_in = Readable::read(reader)?; + let tx_confirmation_height = Readable::read(reader)?; + Ok(Self { tx, txo, tx_confirmed_in, tx_confirmation_height }) + } +} + +/// Stores info about zero or one funding transaction: +/// - none in case of unfunded channels +/// 1 in case of funded channels (can be uncofirmed or confirmed) +/// It is prepared to handle multiple funding transaction candidates (e.g. in case of Splicing) +pub(crate) struct ChannelFundingTransactions { + tx: Option, +} + +impl ChannelFundingTransactions { + pub(crate) fn new_empty() -> Self { + Self { tx: None } + } + + pub(crate) fn is_some(&self) -> bool { + self.tx.is_some() + } + + pub(crate) fn set_tx(&mut self, tx: Transaction) { + if let Some(cft) = self.tx.as_mut() { + cft.set_tx(tx); + } else { + let mut cft = ChannelFundingTransaction::new_empty(); + cft.set_tx(tx); + self.tx = Some(cft); + } + } + + pub(crate) fn set_txo(&mut self, txo: chain::transaction::OutPoint) { + if let Some(cft) = self.tx.as_mut() { + cft.set_txo(txo); + } else { + let mut cft = ChannelFundingTransaction::new_empty(); + cft.set_txo(txo); + self.tx = Some(cft); + } + } + + pub(crate) fn is_confirmed(&self) -> bool { + self.tx.as_ref().map_or(false, |tx| tx.is_confirmed()) + // match &self.tx { + // None => false, + // Some(tx) => tx.is_confirmed(), + // } + } + + pub(crate) fn is_unconfirmed(&self) -> bool { + self.tx.as_ref().map_or(true, |tx| !tx.is_confirmed()) + } + + pub(crate) fn set_confirmed(&mut self, block_hash: BlockHash, block_height: u32) { + if let Some(tx) = self.tx.as_mut() { + tx.set_confirmed(block_hash, block_height); + } else { + panic!("Set_confirmed() invoked, but there is no funding tx!"); + } + } + + pub(crate) fn get_tx(&self) -> Option { + match &self.tx { + None => None, + Some(tx) => match tx.get_tx() { + None => None, + Some(tx) => Some(tx.clone()), + } + } + } + + pub(crate) fn tx_take(&mut self) -> Option { + match self.tx.take() { + None => None, + Some(tx) => match tx.get_tx() { + None => None, + Some(tx) => Some(tx.clone()) + } + } + } + + /// Returns the block hash in the funding transaction was confirmed. + pub(crate) fn get_tx_confirmed_in(&self) -> Option { + match &self.tx { + None => None, + Some(tx) => tx.get_tx_confirmed_in(), + } + } + + pub(crate) fn get_tx_confirmation_height(&self) -> Option { + self.tx.as_ref().map_or(None, |tx| tx.get_tx_confirmation_height()) + } + + /// Returns the current number of confirmations + pub(crate) fn get_tx_confirmations(&mut self, height: u32) -> Option { + self.tx.as_mut().map_or(None, |tx| tx.get_tx_confirmations(height)) + } + + /// Returns the current number of confirmations + pub(crate) fn get_tx_confirmations_nocheck(&self, height: u32) -> Option { + self.tx.as_ref().map_or(None, |tx| tx.get_tx_confirmations_nocheck(height)) + } +} + +impl Writeable for ChannelFundingTransactions { + fn write(&self, writer: &mut W) -> Result<(), io::Error> { + self.tx.write(writer)?; + Ok(()) + } +} + +impl Readable for ChannelFundingTransactions { + fn read(reader: &mut R) -> Result { + let tx = Readable::read(reader)?; + Ok(Self { tx }) + } +} + /// Per-channel data used to build transactions in conjunction with the per-commitment data (CommitmentTransaction). /// The fields are organized by holder/counterparty. /// diff --git a/lightning/src/ln/channel.rs b/lightning/src/ln/channel.rs index f499127bc36..5ca7f7a5289 100644 --- a/lightning/src/ln/channel.rs +++ b/lightning/src/ln/channel.rs @@ -29,7 +29,7 @@ use crate::ln::msgs; use crate::ln::msgs::DecodeError; use crate::ln::script::{self, ShutdownScript}; use crate::ln::channelmanager::{self, CounterpartyForwardingInfo, PendingHTLCStatus, HTLCSource, SentHTLCId, HTLCFailureMsg, PendingHTLCInfo, RAACommitmentOrder, BREAKDOWN_TIMEOUT, MIN_CLTV_EXPIRY_DELTA, MAX_LOCAL_BREAKDOWN_TIMEOUT, ChannelShutdownState}; -use crate::ln::chan_utils::{CounterpartyCommitmentSecrets, TxCreationKeys, HTLCOutputInCommitment, htlc_success_tx_weight, htlc_timeout_tx_weight, make_funding_redeemscript, ChannelPublicKeys, CommitmentTransaction, HolderCommitmentTransaction, ChannelTransactionParameters, CounterpartyChannelTransactionParameters, MAX_HTLCS, get_commitment_transaction_number_obscure_factor, ClosingTransaction}; +use crate::ln::chan_utils::{CounterpartyCommitmentSecrets, TxCreationKeys, HTLCOutputInCommitment, htlc_success_tx_weight, htlc_timeout_tx_weight, make_funding_redeemscript, ChannelPublicKeys, CommitmentTransaction, HolderCommitmentTransaction, ChannelFundingTransactions, ChannelTransactionParameters, CounterpartyChannelTransactionParameters, MAX_HTLCS, get_commitment_transaction_number_obscure_factor, ClosingTransaction}; use crate::ln::chan_utils; use crate::ln::onion_utils::HTLCFailReason; use crate::chain::BestBlock; @@ -830,8 +830,6 @@ pub(super) struct ChannelContext where SP::Target: SignerProvider { expecting_peer_commitment_signed: bool, /// The hash of the block in which the funding transaction was included. - funding_tx_confirmed_in: Option, - funding_tx_confirmation_height: u32, short_channel_id: Option, /// Either the height at which this channel was created or the height at which it was last /// serialized if it was serialized by versions prior to 0.0.103. @@ -875,7 +873,7 @@ pub(super) struct ChannelContext where SP::Target: SignerProvider { counterparty_forwarding_info: Option, pub(crate) channel_transaction_parameters: ChannelTransactionParameters, - funding_transaction: Option, + pub(crate) funding_transaction: ChannelFundingTransactions, is_batch_funding: Option<()>, counterparty_cur_commitment_point: Option, @@ -1113,17 +1111,12 @@ impl ChannelContext where SP::Target: SignerProvider { /// Returns the block hash in which our funding transaction was confirmed. pub fn get_funding_tx_confirmed_in(&self) -> Option { - self.funding_tx_confirmed_in + self.funding_transaction.get_tx_confirmed_in() } /// Returns the current number of confirmations on the funding transaction. - pub fn get_funding_tx_confirmations(&self, height: u32) -> u32 { - if self.funding_tx_confirmation_height == 0 { - // We either haven't seen any confirmation yet, or observed a reorg. - return 0; - } - - height.checked_sub(self.funding_tx_confirmation_height).map_or(0, |c| c + 1) + pub fn get_funding_tx_confirmations_nocheck(&self, height: u32) -> Option { + self.funding_transaction.get_tx_confirmations_nocheck(height) } fn get_holder_selected_contest_delay(&self) -> u16 { @@ -2048,7 +2041,7 @@ impl ChannelContext where SP::Target: SignerProvider { /// Returns the transaction if there is a pending funding transaction that is yet to be /// broadcast. pub fn unbroadcasted_funding(&self) -> Option { - self.if_unbroadcasted_funding(|| self.funding_transaction.clone()) + self.if_unbroadcasted_funding(|| self.funding_transaction.get_tx() ) } /// Returns the transaction ID if there is a pending funding transaction that is yet to be @@ -3896,7 +3889,7 @@ impl Channel where // first received the funding_signed. let mut funding_broadcastable = if self.context.is_outbound() && self.context.channel_state & !STATE_FLAGS >= ChannelState::FundingSent as u32 && self.context.channel_state & ChannelState::WaitingForBatch as u32 == 0 { - self.context.funding_transaction.take() + self.context.funding_transaction.tx_take() } else { None }; // That said, if the funding transaction is already confirmed (ie we're active with a // minimum_depth over 0) don't bother re-broadcasting the confirmed funding tx. @@ -4931,16 +4924,17 @@ impl Channel where // Called: // * always when a new block/transactions are confirmed with the new height // * when funding is signed with a height of 0 - if self.context.funding_tx_confirmation_height == 0 && self.context.minimum_depth != Some(0) { + if self.context.funding_transaction.get_tx_confirmation_height().is_none() && self.context.minimum_depth != Some(0) { return None; } - let funding_tx_confirmations = height as i64 - self.context.funding_tx_confirmation_height as i64 + 1; - if funding_tx_confirmations <= 0 { - self.context.funding_tx_confirmation_height = 0; - } + let funding_tx_confirmations = self.context.funding_transaction.get_tx_confirmations(height); + // TODO reset on reorg + // if funding_tx_confirmations <= 0 { + // self.context.funding_tx_confirmation_height2 = 0; + // } - if funding_tx_confirmations < self.context.minimum_depth.unwrap_or(0) as i64 { + if funding_tx_confirmations.unwrap_or(0) < self.context.minimum_depth.unwrap_or(0) as i64 { return None; } @@ -4964,7 +4958,7 @@ impl Channel where // We got a reorg but not enough to trigger a force close, just ignore. false } else { - if self.context.funding_tx_confirmation_height != 0 && self.context.channel_state & !STATE_FLAGS < ChannelState::ChannelReady as u32 { + if self.context.funding_transaction.get_tx_confirmation_height().is_some() && self.context.channel_state & !STATE_FLAGS < ChannelState::ChannelReady as u32 { // We should never see a funding transaction on-chain until we've received // funding_signed (if we're an outbound channel), or seen funding_generated (if we're // an inbound channel - before that we have no known funding TXID). The fuzzer, @@ -5012,7 +5006,7 @@ impl Channel where for &(index_in_block, tx) in txdata.iter() { // Check if the transaction is the expected funding transaction, and if it is, // check that it pays the right amount to the right script. - if self.context.funding_tx_confirmation_height == 0 { + if self.context.funding_transaction.get_tx_confirmation_height().is_none() { if tx.txid() == funding_txo.txid { let txo_idx = funding_txo.index as usize; if txo_idx >= tx.output.len() || tx.output[txo_idx].script_pubkey != self.context.get_funding_redeemscript().to_v0_p2wsh() || @@ -5042,8 +5036,8 @@ impl Channel where } } } - self.context.funding_tx_confirmation_height = height; - self.context.funding_tx_confirmed_in = Some(*block_hash); + self.context.funding_transaction.set_txo(funding_txo); + self.context.funding_transaction.set_confirmed(*block_hash, height); self.context.short_channel_id = match scid_from_parts(height as u64, index_in_block as u64, txo_idx as u64) { Ok(scid) => Some(scid), Err(_) => panic!("Block was bogus - either height was > 16 million, had > 16 million transactions, or had > 65k outputs"), @@ -5137,13 +5131,13 @@ impl Channel where let non_shutdown_state = self.context.channel_state & (!MULTI_STATE_FLAGS); if non_shutdown_state & !STATE_FLAGS >= ChannelState::ChannelReady as u32 || (non_shutdown_state & ChannelState::OurChannelReady as u32) == ChannelState::OurChannelReady as u32 { - let mut funding_tx_confirmations = height as i64 - self.context.funding_tx_confirmation_height as i64 + 1; - if self.context.funding_tx_confirmation_height == 0 { + let funding_tx_confirmations = self.context.funding_transaction.get_tx_confirmations(height).unwrap_or(0); + // if self.context.funding_tx_confirmation_height2 == 0 { // Note that check_get_channel_ready may reset funding_tx_confirmation_height to // zero if it has been reorged out, however in either case, our state flags // indicate we've already sent a channel_ready - funding_tx_confirmations = 0; - } + // funding_tx_confirmations = 0; + // } // If we've sent channel_ready (or have both sent and received channel_ready), and // the funding transaction has become unconfirmed, @@ -5154,12 +5148,12 @@ impl Channel where // 0-conf channel, but not doing so may lead to the // `ChannelManager::short_to_chan_info` map being inconsistent, so we currently have // to. - if funding_tx_confirmations == 0 && self.context.funding_tx_confirmed_in.is_some() { + if funding_tx_confirmations == 0 && self.context.funding_transaction.get_tx_confirmed_in().is_some() { let err_reason = format!("Funding transaction was un-confirmed. Locked at {} confs, now have {} confs.", self.context.minimum_depth.unwrap(), funding_tx_confirmations); return Err(ClosureReason::ProcessingError { err: err_reason }); } - } else if !self.context.is_outbound() && self.context.funding_tx_confirmed_in.is_none() && + } else if !self.context.is_outbound() && self.context.funding_transaction.get_tx_confirmed_in().is_none() && height >= self.context.channel_creation_height + FUNDING_CONF_DEADLINE_BLOCKS { log_info!(logger, "Closing channel {} due to funding timeout", &self.context.channel_id); // If funding_tx_confirmed_in is unset, the channel must not be active @@ -5178,10 +5172,10 @@ impl Channel where /// force-close the channel, but may also indicate a harmless reorganization of a block or two /// before the channel has reached channel_ready and we can just wait for more blocks. pub fn funding_transaction_unconfirmed(&mut self, logger: &L) -> Result<(), ClosureReason> where L::Target: Logger { - if self.context.funding_tx_confirmation_height != 0 { + if self.context.funding_transaction.get_tx_confirmation_height().is_some() { // We handle the funding disconnection by calling best_block_updated with a height one // below where our funding was connected, implying a reorg back to conf_height - 1. - let reorg_height = self.context.funding_tx_confirmation_height - 1; + let reorg_height = self.context.funding_transaction.get_tx_confirmation_height().unwrap_or(0) - 1; // We use the time field to bump the current time we set on channel updates if its // larger. If we don't know that time has moved forward, we can just set it to the last // time we saw and it will be ignored. @@ -5254,7 +5248,7 @@ impl Channel where NS::Target: NodeSigner, L::Target: Logger { - if self.context.funding_tx_confirmation_height == 0 || self.context.funding_tx_confirmation_height + 5 > best_block_height { + if self.context.funding_transaction.get_tx_confirmation_height().is_none() || self.context.funding_transaction.get_tx_confirmation_height().unwrap_or(0) + 5 > best_block_height { return None; } @@ -5365,7 +5359,7 @@ impl Channel where } self.context.announcement_sigs = Some((msg.node_signature, msg.bitcoin_signature)); - if self.context.funding_tx_confirmation_height == 0 || self.context.funding_tx_confirmation_height + 5 > best_block_height { + if self.context.funding_transaction.get_tx_confirmation_height().is_none() || self.context.funding_transaction.get_tx_confirmation_height().unwrap_or(0) + 5 > best_block_height { return Err(ChannelError::Ignore( "Got announcement_signatures prior to the required six confirmations - we may not have received a block yet that our peer has".to_owned())); } @@ -5378,7 +5372,7 @@ impl Channel where pub fn get_signed_channel_announcement( &self, node_signer: &NS, chain_hash: ChainHash, best_block_height: u32, user_config: &UserConfig ) -> Option where NS::Target: NodeSigner { - if self.context.funding_tx_confirmation_height == 0 || self.context.funding_tx_confirmation_height + 5 > best_block_height { + if self.context.funding_transaction.get_tx_confirmation_height().is_none() || self.context.funding_transaction.get_tx_confirmation_height().unwrap_or(0) + 5 > best_block_height { return None; } let announcement = match self.get_channel_announcement(node_signer, chain_hash, user_config) { @@ -6020,8 +6014,6 @@ impl OutboundV1Channel where SP::Target: SignerProvider { closing_fee_limits: None, target_closing_feerate_sats_per_kw: None, - funding_tx_confirmed_in: None, - funding_tx_confirmation_height: 0, short_channel_id: None, channel_creation_height: current_chain_height, @@ -6048,7 +6040,7 @@ impl OutboundV1Channel where SP::Target: SignerProvider { funding_outpoint: None, channel_type_features: channel_type.clone() }, - funding_transaction: None, + funding_transaction: ChannelFundingTransactions::new_empty(), is_batch_funding: None, counterparty_cur_commitment_point: None, @@ -6127,7 +6119,7 @@ impl OutboundV1Channel where SP::Target: SignerProvider { self.context.minimum_depth = Some(COINBASE_MATURITY); } - self.context.funding_transaction = Some(funding_transaction); + self.context.funding_transaction.set_tx(funding_transaction); self.context.is_batch_funding = Some(()).filter(|_| is_batch_funding); let funding_created = self.context.get_funding_created_msg(logger); @@ -6653,8 +6645,6 @@ impl InboundV1Channel where SP::Target: SignerProvider { closing_fee_limits: None, target_closing_feerate_sats_per_kw: None, - funding_tx_confirmed_in: None, - funding_tx_confirmation_height: 0, short_channel_id: None, channel_creation_height: current_chain_height, @@ -6685,7 +6675,7 @@ impl InboundV1Channel where SP::Target: SignerProvider { funding_outpoint: None, channel_type_features: channel_type.clone() }, - funding_transaction: None, + funding_transaction: ChannelFundingTransactions::new_empty(), is_batch_funding: None, counterparty_cur_commitment_point: Some(msg.first_per_commitment_point), @@ -6831,6 +6821,7 @@ impl InboundV1Channel where SP::Target: SignerProvider { let funding_txo = OutPoint { txid: msg.funding_txid, index: msg.funding_output_index }; self.context.channel_transaction_parameters.funding_outpoint = Some(funding_txo); + // self.context.funding_transaction.set_txo(funding_txo); // TODO ? // This is an externally observable change before we finish all our checks. In particular // check_funding_created_signature may fail. self.context.holder_signer.as_mut().provide_channel_parameters(&self.context.channel_transaction_parameters); @@ -7162,8 +7153,6 @@ impl Writeable for Channel where SP::Target: SignerProvider { // consider the stale state on reload. 0u8.write(writer)?; - self.context.funding_tx_confirmed_in.write(writer)?; - self.context.funding_tx_confirmation_height.write(writer)?; self.context.short_channel_id.write(writer)?; self.context.counterparty_dust_limit_satoshis.write(writer)?; @@ -7456,8 +7445,6 @@ impl<'a, 'b, 'c, ES: Deref, SP: Deref> ReadableArgs<(&'a ES, &'b SP, u32, &'c Ch _ => return Err(DecodeError::InvalidValue), } - let funding_tx_confirmed_in = Readable::read(reader)?; - let funding_tx_confirmation_height = Readable::read(reader)?; let short_channel_id = Readable::read(reader)?; let counterparty_dust_limit_satoshis = Readable::read(reader)?; @@ -7495,7 +7482,7 @@ impl<'a, 'b, 'c, ES: Deref, SP: Deref> ReadableArgs<(&'a ES, &'b SP, u32, &'c Ch }; let mut channel_parameters: ChannelTransactionParameters = Readable::read(reader)?; - let funding_transaction: Option = Readable::read(reader)?; + let funding_transaction: ChannelFundingTransactions = Readable::read(reader)?; let counterparty_cur_commitment_point = Readable::read(reader)?; @@ -7725,8 +7712,6 @@ impl<'a, 'b, 'c, ES: Deref, SP: Deref> ReadableArgs<(&'a ES, &'b SP, u32, &'c Ch closing_fee_limits: None, target_closing_feerate_sats_per_kw, - funding_tx_confirmed_in, - funding_tx_confirmation_height, short_channel_id, channel_creation_height: channel_creation_height.unwrap(), diff --git a/lightning/src/ln/channelmanager.rs b/lightning/src/ln/channelmanager.rs index ad787b5f3e6..b6563f3c4a8 100644 --- a/lightning/src/ln/channelmanager.rs +++ b/lightning/src/ln/channelmanager.rs @@ -1739,7 +1739,7 @@ impl ChannelDetails { next_outbound_htlc_minimum_msat: balance.next_outbound_htlc_minimum_msat, user_channel_id: context.get_user_id(), confirmations_required: context.minimum_depth(), - confirmations: Some(context.get_funding_tx_confirmations(best_block_height)), + confirmations: Some(context.get_funding_tx_confirmations_nocheck(best_block_height).unwrap_or(0)), force_close_spend_delay: context.get_counterparty_selected_contest_delay(), is_outbound: context.is_outbound(), is_channel_ready: context.is_usable(), @@ -6074,7 +6074,7 @@ where // This covers non-zero-conf inbound `Channel`s that we are currently monitoring, but those // which have not yet had any confirmations on-chain. if !chan.context.is_outbound() && chan.context.minimum_depth().unwrap_or(1) != 0 && - chan.context.get_funding_tx_confirmations(best_block_height) == 0 + chan.context.funding_transaction.get_tx_confirmations_nocheck(best_block_height).unwrap_or(0) == 0 { num_unfunded_channels += 1; }