@@ -686,6 +686,43 @@ impl UnfundedChannelContext {
686686 }
687687}
688688
689+ /// Info about a transaction and its confirmation status, used mainly for funding transactions.
690+ pub(super) struct TransactionConfirmation {
691+ /// The transaction, or None.
692+ transaction: Option<Transaction>,
693+ /// The hash of the block in which the transaction was included, or None.
694+ confirmed_in: Option<BlockHash>,
695+ /// The height of the block in which the transaction was included, or 0.
696+ confirmation_height: u32,
697+ }
698+
699+ impl TransactionConfirmation {
700+ /// Construct with empty values
701+ fn default() -> Self {
702+ Self {
703+ transaction: None,
704+ confirmed_in: None,
705+ confirmation_height: 0,
706+ }
707+ }
708+
709+ /// Get the confirmation depth: height relative to the given current height.
710+ /// Also returns a flag indicating the special case when the confirmation is in the 'future'.
711+ /// If there is no confirmation height (it was not confirmed, or confirmed and reorged): (0, false)
712+ /// If the confirmation height is in the 'future' (e.g. due to a reorg): (0, true)
713+ /// Otherwise the result is height - confirmation_height + 1, a number always larger than 0.
714+ fn confirmation_depth(&self, current_height: u32) -> (u32, bool) {
715+ if self.confirmation_height == 0 {
716+ (0, false)
717+ } else {
718+ match current_height.checked_sub(self.confirmation_height) {
719+ None => (0, true),
720+ Some(d) => (d + 1, false),
721+ }
722+ }
723+ }
724+ }
725+
689726/// Contains everything about the channel including state, and various flags.
690727pub(super) struct ChannelContext<SP: Deref> where SP::Target: SignerProvider {
691728 config: LegacyChannelConfig,
@@ -829,9 +866,6 @@ pub(super) struct ChannelContext<SP: Deref> where SP::Target: SignerProvider {
829866 /// milliseconds, so any accidental force-closes here should be exceedingly rare.
830867 expecting_peer_commitment_signed: bool,
831868
832- /// The hash of the block in which the funding transaction was included.
833- funding_tx_confirmed_in: Option<BlockHash>,
834- funding_tx_confirmation_height: u32,
835869 short_channel_id: Option<u64>,
836870 /// Either the height at which this channel was created or the height at which it was last
837871 /// serialized if it was serialized by versions prior to 0.0.103.
@@ -875,7 +909,8 @@ pub(super) struct ChannelContext<SP: Deref> where SP::Target: SignerProvider {
875909 counterparty_forwarding_info: Option<CounterpartyForwardingInfo>,
876910
877911 pub(crate) channel_transaction_parameters: ChannelTransactionParameters,
878- funding_transaction: Option<Transaction>,
912+ /// Info about the funding transaction and its confirmation status
913+ funding_tx_confirmation: TransactionConfirmation,
879914 is_batch_funding: Option<()>,
880915
881916 counterparty_cur_commitment_point: Option<PublicKey>,
@@ -1113,17 +1148,12 @@ impl<SP: Deref> ChannelContext<SP> where SP::Target: SignerProvider {
11131148
11141149 /// Returns the block hash in which our funding transaction was confirmed.
11151150 pub fn get_funding_tx_confirmed_in(&self) -> Option<BlockHash> {
1116- self.funding_tx_confirmed_in
1151+ self.funding_tx_confirmation.confirmed_in
11171152 }
11181153
11191154 /// Returns the current number of confirmations on the funding transaction.
11201155 pub fn get_funding_tx_confirmations(&self, height: u32) -> u32 {
1121- if self.funding_tx_confirmation_height == 0 {
1122- // We either haven't seen any confirmation yet, or observed a reorg.
1123- return 0;
1124- }
1125-
1126- height.checked_sub(self.funding_tx_confirmation_height).map_or(0, |c| c + 1)
1156+ self.funding_tx_confirmation.confirmation_depth(height).0
11271157 }
11281158
11291159 fn get_holder_selected_contest_delay(&self) -> u16 {
@@ -2048,7 +2078,7 @@ impl<SP: Deref> ChannelContext<SP> where SP::Target: SignerProvider {
20482078 /// Returns the transaction if there is a pending funding transaction that is yet to be
20492079 /// broadcast.
20502080 pub fn unbroadcasted_funding(&self) -> Option<Transaction> {
2051- self.if_unbroadcasted_funding(|| self.funding_transaction .clone())
2081+ self.if_unbroadcasted_funding(|| self.funding_tx_confirmation.transaction .clone())
20522082 }
20532083
20542084 /// Returns the transaction ID if there is a pending funding transaction that is yet to be
@@ -3896,7 +3926,7 @@ impl<SP: Deref> Channel<SP> where
38963926 // first received the funding_signed.
38973927 let mut funding_broadcastable =
38983928 if self.context.is_outbound() && self.context.channel_state & !STATE_FLAGS >= ChannelState::FundingSent as u32 && self.context.channel_state & ChannelState::WaitingForBatch as u32 == 0 {
3899- self.context.funding_transaction .take()
3929+ self.context.funding_tx_confirmation.transaction .take()
39003930 } else { None };
39013931 // That said, if the funding transaction is already confirmed (ie we're active with a
39023932 // minimum_depth over 0) don't bother re-broadcasting the confirmed funding tx.
@@ -4885,7 +4915,7 @@ impl<SP: Deref> Channel<SP> where
48854915 // Because deciding we're awaiting initial broadcast spuriously could result in
48864916 // funds-loss (as we don't have a monitor, but have the funding transaction confirmed),
48874917 // we hard-assert here, even in production builds.
4888- if self.context.is_outbound() { assert!(self.context.funding_transaction .is_some()); }
4918+ if self.context.is_outbound() { assert!(self.context.funding_tx_confirmation.transaction .is_some()); }
48894919 assert!(self.context.monitor_pending_channel_ready);
48904920 assert_eq!(self.context.latest_monitor_update_id, 0);
48914921 return true;
@@ -4931,16 +4961,16 @@ impl<SP: Deref> Channel<SP> where
49314961 // Called:
49324962 // * always when a new block/transactions are confirmed with the new height
49334963 // * when funding is signed with a height of 0
4934- if self.context.funding_tx_confirmation_height == 0 && self.context.minimum_depth != Some(0) {
4964+ if self.context.funding_tx_confirmation.confirmation_height == 0 && self.context.minimum_depth != Some(0) {
49354965 return None;
49364966 }
49374967
4938- let funding_tx_confirmations = height as i64 - self.context.funding_tx_confirmation_height as i64 + 1 ;
4939- if funding_tx_confirmations <= 0 {
4940- self.context.funding_tx_confirmation_height = 0;
4968+ let ( funding_tx_confirmations, in_future) = self.context.funding_tx_confirmation.confirmation_depth(height) ;
4969+ if in_future {
4970+ self.context.funding_tx_confirmation.confirmation_height = 0;
49414971 }
49424972
4943- if funding_tx_confirmations < self.context.minimum_depth.unwrap_or(0) as i64 {
4973+ if funding_tx_confirmations < self.context.minimum_depth.unwrap_or(0) {
49444974 return None;
49454975 }
49464976
@@ -4964,7 +4994,7 @@ impl<SP: Deref> Channel<SP> where
49644994 // We got a reorg but not enough to trigger a force close, just ignore.
49654995 false
49664996 } else {
4967- if self.context.funding_tx_confirmation_height != 0 && self.context.channel_state & !STATE_FLAGS < ChannelState::ChannelReady as u32 {
4997+ if self.context.funding_tx_confirmation.confirmation_height != 0 && self.context.channel_state & !STATE_FLAGS < ChannelState::ChannelReady as u32 {
49684998 // We should never see a funding transaction on-chain until we've received
49694999 // funding_signed (if we're an outbound channel), or seen funding_generated (if we're
49705000 // an inbound channel - before that we have no known funding TXID). The fuzzer,
@@ -5012,7 +5042,7 @@ impl<SP: Deref> Channel<SP> where
50125042 for &(index_in_block, tx) in txdata.iter() {
50135043 // Check if the transaction is the expected funding transaction, and if it is,
50145044 // check that it pays the right amount to the right script.
5015- if self.context.funding_tx_confirmation_height == 0 {
5045+ if self.context.funding_tx_confirmation.confirmation_height == 0 {
50165046 if tx.txid() == funding_txo.txid {
50175047 let txo_idx = funding_txo.index as usize;
50185048 if txo_idx >= tx.output.len() || tx.output[txo_idx].script_pubkey != self.context.get_funding_redeemscript().to_v0_p2wsh() ||
@@ -5042,8 +5072,8 @@ impl<SP: Deref> Channel<SP> where
50425072 }
50435073 }
50445074 }
5045- self.context.funding_tx_confirmation_height = height;
5046- self.context.funding_tx_confirmed_in = Some(*block_hash);
5075+ self.context.funding_tx_confirmation.confirmation_height = height;
5076+ self.context.funding_tx_confirmation.confirmed_in = Some(*block_hash);
50475077 self.context.short_channel_id = match scid_from_parts(height as u64, index_in_block as u64, txo_idx as u64) {
50485078 Ok(scid) => Some(scid),
50495079 Err(_) => panic!("Block was bogus - either height was > 16 million, had > 16 million transactions, or had > 65k outputs"),
@@ -5137,13 +5167,10 @@ impl<SP: Deref> Channel<SP> where
51375167 let non_shutdown_state = self.context.channel_state & (!MULTI_STATE_FLAGS);
51385168 if non_shutdown_state & !STATE_FLAGS >= ChannelState::ChannelReady as u32 ||
51395169 (non_shutdown_state & ChannelState::OurChannelReady as u32) == ChannelState::OurChannelReady as u32 {
5140- let mut funding_tx_confirmations = height as i64 - self.context.funding_tx_confirmation_height as i64 + 1;
5141- if self.context.funding_tx_confirmation_height == 0 {
5142- // Note that check_get_channel_ready may reset funding_tx_confirmation_height to
5143- // zero if it has been reorged out, however in either case, our state flags
5144- // indicate we've already sent a channel_ready
5145- funding_tx_confirmations = 0;
5146- }
5170+ let (funding_tx_confirmations, _) = self.context.funding_tx_confirmation.confirmation_depth(height);
5171+ // Note that check_get_channel_ready may reset funding_tx_confirmation.confirmation_height to
5172+ // zero if it has been reorged out, however in either case, our state flags
5173+ // indicate we've already sent a channel_ready
51475174
51485175 // If we've sent channel_ready (or have both sent and received channel_ready), and
51495176 // the funding transaction has become unconfirmed,
@@ -5154,15 +5181,15 @@ impl<SP: Deref> Channel<SP> where
51545181 // 0-conf channel, but not doing so may lead to the
51555182 // `ChannelManager::short_to_chan_info` map being inconsistent, so we currently have
51565183 // to.
5157- if funding_tx_confirmations == 0 && self.context.funding_tx_confirmed_in .is_some() {
5184+ if funding_tx_confirmations == 0 && self.context.funding_tx_confirmation.confirmed_in .is_some() {
51585185 let err_reason = format!("Funding transaction was un-confirmed. Locked at {} confs, now have {} confs.",
51595186 self.context.minimum_depth.unwrap(), funding_tx_confirmations);
51605187 return Err(ClosureReason::ProcessingError { err: err_reason });
51615188 }
5162- } else if !self.context.is_outbound() && self.context.funding_tx_confirmed_in .is_none() &&
5189+ } else if !self.context.is_outbound() && self.context.funding_tx_confirmation.confirmed_in .is_none() &&
51635190 height >= self.context.channel_creation_height + FUNDING_CONF_DEADLINE_BLOCKS {
51645191 log_info!(logger, "Closing channel {} due to funding timeout", &self.context.channel_id);
5165- // If funding_tx_confirmed_in is unset, the channel must not be active
5192+ // If funding_tx_confirmation.confirmed_in is unset, the channel must not be active
51665193 assert!(non_shutdown_state & !STATE_FLAGS <= ChannelState::ChannelReady as u32);
51675194 assert_eq!(non_shutdown_state & ChannelState::OurChannelReady as u32, 0);
51685195 return Err(ClosureReason::FundingTimedOut);
@@ -5178,10 +5205,10 @@ impl<SP: Deref> Channel<SP> where
51785205 /// force-close the channel, but may also indicate a harmless reorganization of a block or two
51795206 /// before the channel has reached channel_ready and we can just wait for more blocks.
51805207 pub fn funding_transaction_unconfirmed<L: Deref>(&mut self, logger: &L) -> Result<(), ClosureReason> where L::Target: Logger {
5181- if self.context.funding_tx_confirmation_height != 0 {
5208+ if self.context.funding_tx_confirmation.confirmation_height > 0 {
51825209 // We handle the funding disconnection by calling best_block_updated with a height one
51835210 // below where our funding was connected, implying a reorg back to conf_height - 1.
5184- let reorg_height = self.context.funding_tx_confirmation_height - 1;
5211+ let reorg_height = self.context.funding_tx_confirmation.confirmation_height - 1;
51855212 // We use the time field to bump the current time we set on channel updates if its
51865213 // larger. If we don't know that time has moved forward, we can just set it to the last
51875214 // time we saw and it will be ignored.
@@ -5254,7 +5281,7 @@ impl<SP: Deref> Channel<SP> where
52545281 NS::Target: NodeSigner,
52555282 L::Target: Logger
52565283 {
5257- if self.context.funding_tx_confirmation_height == 0 || self.context.funding_tx_confirmation_height + 5 > best_block_height {
5284+ if self.context.funding_tx_confirmation.confirmation_height == 0 || self.context.funding_tx_confirmation.confirmation_height + 5 > best_block_height {
52585285 return None;
52595286 }
52605287
@@ -5365,7 +5392,7 @@ impl<SP: Deref> Channel<SP> where
53655392 }
53665393
53675394 self.context.announcement_sigs = Some((msg.node_signature, msg.bitcoin_signature));
5368- if self.context.funding_tx_confirmation_height == 0 || self.context.funding_tx_confirmation_height + 5 > best_block_height {
5395+ if self.context.funding_tx_confirmation.confirmation_height == 0 || self.context.funding_tx_confirmation.confirmation_height + 5 > best_block_height {
53695396 return Err(ChannelError::Ignore(
53705397 "Got announcement_signatures prior to the required six confirmations - we may not have received a block yet that our peer has".to_owned()));
53715398 }
@@ -5378,7 +5405,7 @@ impl<SP: Deref> Channel<SP> where
53785405 pub fn get_signed_channel_announcement<NS: Deref>(
53795406 &self, node_signer: &NS, chain_hash: ChainHash, best_block_height: u32, user_config: &UserConfig
53805407 ) -> Option<msgs::ChannelAnnouncement> where NS::Target: NodeSigner {
5381- if self.context.funding_tx_confirmation_height == 0 || self.context.funding_tx_confirmation_height + 5 > best_block_height {
5408+ if self.context.funding_tx_confirmation.confirmation_height == 0 || self.context.funding_tx_confirmation.confirmation_height + 5 > best_block_height {
53825409 return None;
53835410 }
53845411 let announcement = match self.get_channel_announcement(node_signer, chain_hash, user_config) {
@@ -6020,8 +6047,6 @@ impl<SP: Deref> OutboundV1Channel<SP> where SP::Target: SignerProvider {
60206047 closing_fee_limits: None,
60216048 target_closing_feerate_sats_per_kw: None,
60226049
6023- funding_tx_confirmed_in: None,
6024- funding_tx_confirmation_height: 0,
60256050 short_channel_id: None,
60266051 channel_creation_height: current_chain_height,
60276052
@@ -6048,7 +6073,7 @@ impl<SP: Deref> OutboundV1Channel<SP> where SP::Target: SignerProvider {
60486073 funding_outpoint: None,
60496074 channel_type_features: channel_type.clone()
60506075 },
6051- funding_transaction: None ,
6076+ funding_tx_confirmation: TransactionConfirmation::default() ,
60526077 is_batch_funding: None,
60536078
60546079 counterparty_cur_commitment_point: None,
@@ -6127,7 +6152,7 @@ impl<SP: Deref> OutboundV1Channel<SP> where SP::Target: SignerProvider {
61276152 self.context.minimum_depth = Some(COINBASE_MATURITY);
61286153 }
61296154
6130- self.context.funding_transaction = Some(funding_transaction);
6155+ self.context.funding_tx_confirmation.transaction = Some(funding_transaction);
61316156 self.context.is_batch_funding = Some(()).filter(|_| is_batch_funding);
61326157
61336158 let funding_created = self.context.get_funding_created_msg(logger);
@@ -6653,8 +6678,6 @@ impl<SP: Deref> InboundV1Channel<SP> where SP::Target: SignerProvider {
66536678 closing_fee_limits: None,
66546679 target_closing_feerate_sats_per_kw: None,
66556680
6656- funding_tx_confirmed_in: None,
6657- funding_tx_confirmation_height: 0,
66586681 short_channel_id: None,
66596682 channel_creation_height: current_chain_height,
66606683
@@ -6685,7 +6708,7 @@ impl<SP: Deref> InboundV1Channel<SP> where SP::Target: SignerProvider {
66856708 funding_outpoint: None,
66866709 channel_type_features: channel_type.clone()
66876710 },
6688- funding_transaction: None ,
6711+ funding_tx_confirmation: TransactionConfirmation::default() ,
66896712 is_batch_funding: None,
66906713
66916714 counterparty_cur_commitment_point: Some(msg.first_per_commitment_point),
@@ -7162,8 +7185,8 @@ impl<SP: Deref> Writeable for Channel<SP> where SP::Target: SignerProvider {
71627185 // consider the stale state on reload.
71637186 0u8.write(writer)?;
71647187
7165- self.context.funding_tx_confirmed_in .write(writer)?;
7166- self.context.funding_tx_confirmation_height .write(writer)?;
7188+ self.context.funding_tx_confirmation.confirmed_in .write(writer)?;
7189+ self.context.funding_tx_confirmation.confirmation_height .write(writer)?;
71677190 self.context.short_channel_id.write(writer)?;
71687191
71697192 self.context.counterparty_dust_limit_satoshis.write(writer)?;
@@ -7191,7 +7214,7 @@ impl<SP: Deref> Writeable for Channel<SP> where SP::Target: SignerProvider {
71917214 }
71927215
71937216 self.context.channel_transaction_parameters.write(writer)?;
7194- self.context.funding_transaction .write(writer)?;
7217+ self.context.funding_tx_confirmation.transaction .write(writer)?;
71957218
71967219 self.context.counterparty_cur_commitment_point.write(writer)?;
71977220 self.context.counterparty_prev_commitment_point.write(writer)?;
@@ -7725,8 +7748,6 @@ impl<'a, 'b, 'c, ES: Deref, SP: Deref> ReadableArgs<(&'a ES, &'b SP, u32, &'c Ch
77257748 closing_fee_limits: None,
77267749 target_closing_feerate_sats_per_kw,
77277750
7728- funding_tx_confirmed_in,
7729- funding_tx_confirmation_height,
77307751 short_channel_id,
77317752 channel_creation_height: channel_creation_height.unwrap(),
77327753
@@ -7744,7 +7765,11 @@ impl<'a, 'b, 'c, ES: Deref, SP: Deref> ReadableArgs<(&'a ES, &'b SP, u32, &'c Ch
77447765 counterparty_forwarding_info,
77457766
77467767 channel_transaction_parameters: channel_parameters,
7747- funding_transaction,
7768+ funding_tx_confirmation: TransactionConfirmation {
7769+ transaction: funding_transaction,
7770+ confirmed_in: funding_tx_confirmed_in,
7771+ confirmation_height: funding_tx_confirmation_height,
7772+ },
77487773 is_batch_funding,
77497774
77507775 counterparty_cur_commitment_point,
@@ -7799,7 +7824,7 @@ mod tests {
77997824 use crate::ln::PaymentHash;
78007825 use crate::ln::channelmanager::{self, HTLCSource, PaymentId};
78017826 use crate::ln::channel::InitFeatures;
7802- use crate::ln::channel::{ChannelState, InboundHTLCOutput, OutboundV1Channel, InboundV1Channel, OutboundHTLCOutput, InboundHTLCState, OutboundHTLCState, HTLCCandidate, HTLCInitiator, commit_tx_fee_msat};
7827+ use crate::ln::channel::{ChannelState, InboundHTLCOutput, OutboundV1Channel, InboundV1Channel, OutboundHTLCOutput, InboundHTLCState, OutboundHTLCState, HTLCCandidate, HTLCInitiator, TransactionConfirmation, commit_tx_fee_msat};
78037828 use crate::ln::channel::{MAX_FUNDING_SATOSHIS_NO_WUMBO, TOTAL_BITCOIN_SUPPLY_SATOSHIS, MIN_THEIR_CHAN_RESERVE_SATOSHIS};
78047829 use crate::ln::features::ChannelTypeFeatures;
78057830 use crate::ln::msgs::{ChannelUpdate, DecodeError, UnsignedChannelUpdate, MAX_VALUE_MSAT};
@@ -7841,6 +7866,26 @@ mod tests {
78417866 "MAX_FUNDING_SATOSHIS_NO_WUMBO is greater than all satoshis in existence");
78427867 }
78437868
7869+ #[test]
7870+ fn test_transaction_confirmation_depth() {
7871+ {
7872+ let tx_conf = TransactionConfirmation { transaction: None, confirmed_in: None, confirmation_height: 0 };
7873+ assert_eq!(tx_conf.confirmation_depth(42), (0, false));
7874+ }
7875+ {
7876+ let tx_conf = TransactionConfirmation { transaction: None, confirmed_in: None, confirmation_height: 100005 };
7877+ assert_eq!(tx_conf.confirmation_depth(100008), (4, false));
7878+ }
7879+ {
7880+ let tx_conf = TransactionConfirmation { transaction: None, confirmed_in: None, confirmation_height: 100005 };
7881+ assert_eq!(tx_conf.confirmation_depth(100005), (1, false));
7882+ }
7883+ {
7884+ // confirmation_height is larger than current, 'in the future'
7885+ let tx_conf = TransactionConfirmation { transaction: None, confirmed_in: None, confirmation_height: 100005 };
7886+ assert_eq!(tx_conf.confirmation_depth(100000), (0, true));
7887+ }
7888+ }
78447889 struct Keys {
78457890 signer: InMemorySigner,
78467891 }
0 commit comments