@@ -686,6 +686,43 @@ impl UnfundedChannelContext {
686
686
}
687
687
}
688
688
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
+
689
726
/// Contains everything about the channel including state, and various flags.
690
727
pub(super) struct ChannelContext<SP: Deref> where SP::Target: SignerProvider {
691
728
config: LegacyChannelConfig,
@@ -829,9 +866,6 @@ pub(super) struct ChannelContext<SP: Deref> where SP::Target: SignerProvider {
829
866
/// milliseconds, so any accidental force-closes here should be exceedingly rare.
830
867
expecting_peer_commitment_signed: bool,
831
868
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,
835
869
short_channel_id: Option<u64>,
836
870
/// Either the height at which this channel was created or the height at which it was last
837
871
/// 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 {
875
909
counterparty_forwarding_info: Option<CounterpartyForwardingInfo>,
876
910
877
911
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,
879
914
is_batch_funding: Option<()>,
880
915
881
916
counterparty_cur_commitment_point: Option<PublicKey>,
@@ -1113,17 +1148,12 @@ impl<SP: Deref> ChannelContext<SP> where SP::Target: SignerProvider {
1113
1148
1114
1149
/// Returns the block hash in which our funding transaction was confirmed.
1115
1150
pub fn get_funding_tx_confirmed_in(&self) -> Option<BlockHash> {
1116
- self.funding_tx_confirmed_in
1151
+ self.funding_tx_confirmation.confirmed_in
1117
1152
}
1118
1153
1119
1154
/// Returns the current number of confirmations on the funding transaction.
1120
1155
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
1127
1157
}
1128
1158
1129
1159
fn get_holder_selected_contest_delay(&self) -> u16 {
@@ -2048,7 +2078,7 @@ impl<SP: Deref> ChannelContext<SP> where SP::Target: SignerProvider {
2048
2078
/// Returns the transaction if there is a pending funding transaction that is yet to be
2049
2079
/// broadcast.
2050
2080
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())
2052
2082
}
2053
2083
2054
2084
/// 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
3896
3926
// first received the funding_signed.
3897
3927
let mut funding_broadcastable =
3898
3928
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()
3900
3930
} else { None };
3901
3931
// That said, if the funding transaction is already confirmed (ie we're active with a
3902
3932
// minimum_depth over 0) don't bother re-broadcasting the confirmed funding tx.
@@ -4885,7 +4915,7 @@ impl<SP: Deref> Channel<SP> where
4885
4915
// Because deciding we're awaiting initial broadcast spuriously could result in
4886
4916
// funds-loss (as we don't have a monitor, but have the funding transaction confirmed),
4887
4917
// 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()); }
4889
4919
assert!(self.context.monitor_pending_channel_ready);
4890
4920
assert_eq!(self.context.latest_monitor_update_id, 0);
4891
4921
return true;
@@ -4931,16 +4961,16 @@ impl<SP: Deref> Channel<SP> where
4931
4961
// Called:
4932
4962
// * always when a new block/transactions are confirmed with the new height
4933
4963
// * 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) {
4935
4965
return None;
4936
4966
}
4937
4967
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;
4941
4971
}
4942
4972
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) {
4944
4974
return None;
4945
4975
}
4946
4976
@@ -4964,7 +4994,7 @@ impl<SP: Deref> Channel<SP> where
4964
4994
// We got a reorg but not enough to trigger a force close, just ignore.
4965
4995
false
4966
4996
} 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 {
4968
4998
// We should never see a funding transaction on-chain until we've received
4969
4999
// funding_signed (if we're an outbound channel), or seen funding_generated (if we're
4970
5000
// an inbound channel - before that we have no known funding TXID). The fuzzer,
@@ -5012,7 +5042,7 @@ impl<SP: Deref> Channel<SP> where
5012
5042
for &(index_in_block, tx) in txdata.iter() {
5013
5043
// Check if the transaction is the expected funding transaction, and if it is,
5014
5044
// 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 {
5016
5046
if tx.txid() == funding_txo.txid {
5017
5047
let txo_idx = funding_txo.index as usize;
5018
5048
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
5042
5072
}
5043
5073
}
5044
5074
}
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);
5047
5077
self.context.short_channel_id = match scid_from_parts(height as u64, index_in_block as u64, txo_idx as u64) {
5048
5078
Ok(scid) => Some(scid),
5049
5079
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
5137
5167
let non_shutdown_state = self.context.channel_state & (!MULTI_STATE_FLAGS);
5138
5168
if non_shutdown_state & !STATE_FLAGS >= ChannelState::ChannelReady as u32 ||
5139
5169
(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
5147
5174
5148
5175
// If we've sent channel_ready (or have both sent and received channel_ready), and
5149
5176
// the funding transaction has become unconfirmed,
@@ -5154,15 +5181,15 @@ impl<SP: Deref> Channel<SP> where
5154
5181
// 0-conf channel, but not doing so may lead to the
5155
5182
// `ChannelManager::short_to_chan_info` map being inconsistent, so we currently have
5156
5183
// 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() {
5158
5185
let err_reason = format!("Funding transaction was un-confirmed. Locked at {} confs, now have {} confs.",
5159
5186
self.context.minimum_depth.unwrap(), funding_tx_confirmations);
5160
5187
return Err(ClosureReason::ProcessingError { err: err_reason });
5161
5188
}
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() &&
5163
5190
height >= self.context.channel_creation_height + FUNDING_CONF_DEADLINE_BLOCKS {
5164
5191
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
5166
5193
assert!(non_shutdown_state & !STATE_FLAGS <= ChannelState::ChannelReady as u32);
5167
5194
assert_eq!(non_shutdown_state & ChannelState::OurChannelReady as u32, 0);
5168
5195
return Err(ClosureReason::FundingTimedOut);
@@ -5178,10 +5205,10 @@ impl<SP: Deref> Channel<SP> where
5178
5205
/// force-close the channel, but may also indicate a harmless reorganization of a block or two
5179
5206
/// before the channel has reached channel_ready and we can just wait for more blocks.
5180
5207
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 {
5182
5209
// We handle the funding disconnection by calling best_block_updated with a height one
5183
5210
// 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;
5185
5212
// We use the time field to bump the current time we set on channel updates if its
5186
5213
// larger. If we don't know that time has moved forward, we can just set it to the last
5187
5214
// time we saw and it will be ignored.
@@ -5254,7 +5281,7 @@ impl<SP: Deref> Channel<SP> where
5254
5281
NS::Target: NodeSigner,
5255
5282
L::Target: Logger
5256
5283
{
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 {
5258
5285
return None;
5259
5286
}
5260
5287
@@ -5365,7 +5392,7 @@ impl<SP: Deref> Channel<SP> where
5365
5392
}
5366
5393
5367
5394
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 {
5369
5396
return Err(ChannelError::Ignore(
5370
5397
"Got announcement_signatures prior to the required six confirmations - we may not have received a block yet that our peer has".to_owned()));
5371
5398
}
@@ -5378,7 +5405,7 @@ impl<SP: Deref> Channel<SP> where
5378
5405
pub fn get_signed_channel_announcement<NS: Deref>(
5379
5406
&self, node_signer: &NS, chain_hash: ChainHash, best_block_height: u32, user_config: &UserConfig
5380
5407
) -> 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 {
5382
5409
return None;
5383
5410
}
5384
5411
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 {
6020
6047
closing_fee_limits: None,
6021
6048
target_closing_feerate_sats_per_kw: None,
6022
6049
6023
- funding_tx_confirmed_in: None,
6024
- funding_tx_confirmation_height: 0,
6025
6050
short_channel_id: None,
6026
6051
channel_creation_height: current_chain_height,
6027
6052
@@ -6048,7 +6073,7 @@ impl<SP: Deref> OutboundV1Channel<SP> where SP::Target: SignerProvider {
6048
6073
funding_outpoint: None,
6049
6074
channel_type_features: channel_type.clone()
6050
6075
},
6051
- funding_transaction: None ,
6076
+ funding_tx_confirmation: TransactionConfirmation::default() ,
6052
6077
is_batch_funding: None,
6053
6078
6054
6079
counterparty_cur_commitment_point: None,
@@ -6127,7 +6152,7 @@ impl<SP: Deref> OutboundV1Channel<SP> where SP::Target: SignerProvider {
6127
6152
self.context.minimum_depth = Some(COINBASE_MATURITY);
6128
6153
}
6129
6154
6130
- self.context.funding_transaction = Some(funding_transaction);
6155
+ self.context.funding_tx_confirmation.transaction = Some(funding_transaction);
6131
6156
self.context.is_batch_funding = Some(()).filter(|_| is_batch_funding);
6132
6157
6133
6158
let funding_created = self.context.get_funding_created_msg(logger);
@@ -6653,8 +6678,6 @@ impl<SP: Deref> InboundV1Channel<SP> where SP::Target: SignerProvider {
6653
6678
closing_fee_limits: None,
6654
6679
target_closing_feerate_sats_per_kw: None,
6655
6680
6656
- funding_tx_confirmed_in: None,
6657
- funding_tx_confirmation_height: 0,
6658
6681
short_channel_id: None,
6659
6682
channel_creation_height: current_chain_height,
6660
6683
@@ -6685,7 +6708,7 @@ impl<SP: Deref> InboundV1Channel<SP> where SP::Target: SignerProvider {
6685
6708
funding_outpoint: None,
6686
6709
channel_type_features: channel_type.clone()
6687
6710
},
6688
- funding_transaction: None ,
6711
+ funding_tx_confirmation: TransactionConfirmation::default() ,
6689
6712
is_batch_funding: None,
6690
6713
6691
6714
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 {
7162
7185
// consider the stale state on reload.
7163
7186
0u8.write(writer)?;
7164
7187
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)?;
7167
7190
self.context.short_channel_id.write(writer)?;
7168
7191
7169
7192
self.context.counterparty_dust_limit_satoshis.write(writer)?;
@@ -7191,7 +7214,7 @@ impl<SP: Deref> Writeable for Channel<SP> where SP::Target: SignerProvider {
7191
7214
}
7192
7215
7193
7216
self.context.channel_transaction_parameters.write(writer)?;
7194
- self.context.funding_transaction .write(writer)?;
7217
+ self.context.funding_tx_confirmation.transaction .write(writer)?;
7195
7218
7196
7219
self.context.counterparty_cur_commitment_point.write(writer)?;
7197
7220
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
7725
7748
closing_fee_limits: None,
7726
7749
target_closing_feerate_sats_per_kw,
7727
7750
7728
- funding_tx_confirmed_in,
7729
- funding_tx_confirmation_height,
7730
7751
short_channel_id,
7731
7752
channel_creation_height: channel_creation_height.unwrap(),
7732
7753
@@ -7744,7 +7765,11 @@ impl<'a, 'b, 'c, ES: Deref, SP: Deref> ReadableArgs<(&'a ES, &'b SP, u32, &'c Ch
7744
7765
counterparty_forwarding_info,
7745
7766
7746
7767
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
+ },
7748
7773
is_batch_funding,
7749
7774
7750
7775
counterparty_cur_commitment_point,
@@ -7799,7 +7824,7 @@ mod tests {
7799
7824
use crate::ln::PaymentHash;
7800
7825
use crate::ln::channelmanager::{self, HTLCSource, PaymentId};
7801
7826
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};
7803
7828
use crate::ln::channel::{MAX_FUNDING_SATOSHIS_NO_WUMBO, TOTAL_BITCOIN_SUPPLY_SATOSHIS, MIN_THEIR_CHAN_RESERVE_SATOSHIS};
7804
7829
use crate::ln::features::ChannelTypeFeatures;
7805
7830
use crate::ln::msgs::{ChannelUpdate, DecodeError, UnsignedChannelUpdate, MAX_VALUE_MSAT};
@@ -7841,6 +7866,26 @@ mod tests {
7841
7866
"MAX_FUNDING_SATOSHIS_NO_WUMBO is greater than all satoshis in existence");
7842
7867
}
7843
7868
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
+ }
7844
7889
struct Keys {
7845
7890
signer: InMemorySigner,
7846
7891
}
0 commit comments