@@ -1861,6 +1861,30 @@ struct PendingSplice {
1861
1861
received_funding_txid: Option<Txid>,
1862
1862
}
1863
1863
1864
+ /// Wrapper around a [`Transaction`] useful for caching the result of [`Transaction::compute_txid`].
1865
+ struct ConfirmedTransaction<'a> {
1866
+ tx: &'a Transaction,
1867
+ txid: Option<Txid>,
1868
+ }
1869
+
1870
+ impl<'a> ConfirmedTransaction<'a> {
1871
+ /// Returns the underlying [`Transaction`].
1872
+ pub fn tx(&self) -> &'a Transaction {
1873
+ self.tx
1874
+ }
1875
+
1876
+ /// Returns the [`Txid`], computing and caching it if necessary.
1877
+ pub fn txid(&mut self) -> Txid {
1878
+ *self.txid.get_or_insert_with(|| self.tx.compute_txid())
1879
+ }
1880
+ }
1881
+
1882
+ impl<'a> From<&'a Transaction> for ConfirmedTransaction<'a> {
1883
+ fn from(tx: &'a Transaction) -> Self {
1884
+ ConfirmedTransaction { tx, txid: None }
1885
+ }
1886
+ }
1887
+
1864
1888
/// Contains everything about the channel including state, and various flags.
1865
1889
pub(super) struct ChannelContext<SP: Deref> where SP::Target: SignerProvider {
1866
1890
config: LegacyChannelConfig,
@@ -4929,83 +4953,83 @@ impl<SP: Deref> ChannelContext<SP> where SP::Target: SignerProvider {
4929
4953
return true;
4930
4954
}
4931
4955
4932
- fn check_for_funding_tx<'a, L: Deref>(
4956
+ fn check_for_funding_tx<L: Deref>(
4933
4957
&mut self, funding: &mut FundingScope, block_hash: &BlockHash, height: u32,
4934
- txdata: &'a TransactionData , logger: &L,
4935
- ) -> Result<Option<&'a Transaction> , ClosureReason>
4958
+ index_in_block: usize, tx: &mut ConfirmedTransaction , logger: &L,
4959
+ ) -> Result<bool , ClosureReason>
4936
4960
where
4937
4961
L::Target: Logger
4938
4962
{
4939
4963
let funding_txo = match funding.get_funding_txo() {
4940
4964
Some(funding_txo) => funding_txo,
4941
4965
None => {
4942
4966
debug_assert!(false);
4943
- return Ok(None );
4967
+ return Ok(false );
4944
4968
},
4945
4969
};
4946
4970
4947
- let mut confirmed_funding_tx = None ;
4948
- for &(index_in_block, tx) in txdata.iter() {
4949
- // Check if the transaction is the expected funding transaction, and if it is,
4950
- // check that it pays the right amount to the right script.
4951
- if funding.funding_tx_confirmation_height == 0 {
4952
- if tx.compute_txid () == funding_txo.txid {
4953
- let txo_idx = funding_txo.index as usize ;
4954
- if txo_idx >= tx.output.len() || tx.output[txo_idx].script_pubkey != funding.get_funding_redeemscript().to_p2wsh() ||
4955
- tx.output[txo_idx].value.to_sat() != funding.get_value_satoshis() {
4956
- if funding.is_outbound () {
4957
- // If we generated the funding transaction and it doesn't match what it
4958
- // should, the client is really broken and we should just panic and
4959
- // tell them off. That said, because hash collisions happen with high
4960
- // probability in fuzzing mode, if we're fuzzing we just close the
4961
- // channel and move on.
4962
- #[cfg(not(fuzzing))]
4963
- panic!("Client called ChannelManager::funding_transaction_generated with bogus transaction!");
4964
- }
4965
- self.update_time_counter += 1;
4966
- let err_reason = "funding tx had wrong script/value or output index" ;
4967
- return Err(ClosureReason::ProcessingError { err: err_reason.to_owned() }) ;
4968
- } else {
4969
- if funding.is_outbound() {
4970
- if !tx.is_coinbase () {
4971
- for input in tx.input.iter () {
4972
- if input.witness.is_empty () {
4973
- // We generated a malleable funding transaction, implying we've
4974
- // just exposed ourselves to funds loss to our counterparty.
4975
- #[cfg(not(fuzzing))]
4976
- panic!("Client called ChannelManager::funding_transaction_generated with bogus transaction!");
4977
- }
4971
+ let mut is_confirmed_funding_tx = false ;
4972
+
4973
+ // Check if the transaction is the expected funding transaction, and if it is,
4974
+ // check that it pays the right amount to the right script.
4975
+ if funding.funding_tx_confirmation_height == 0 {
4976
+ if tx.txid () == funding_txo.txid {
4977
+ let tx = tx.tx() ;
4978
+ let txo_idx = funding_txo.index as usize;
4979
+ if txo_idx >= tx.output.len() || tx.output [txo_idx].script_pubkey != funding.get_funding_redeemscript().to_p2wsh() ||
4980
+ tx.output[txo_idx].value.to_sat() != funding.get_value_satoshis () {
4981
+ if funding.is_outbound() {
4982
+ // If we generated the funding transaction and it doesn't match what it
4983
+ // should, the client is really broken and we should just panic and
4984
+ // tell them off. That said, because hash collisions happen with high
4985
+ // probability in fuzzing mode, if we're fuzzing we just close the
4986
+ // channel and move on.
4987
+ #[cfg(not(fuzzing))]
4988
+ panic!("Client called ChannelManager::funding_transaction_generated with bogus transaction!");
4989
+ }
4990
+ self.update_time_counter += 1 ;
4991
+ let err_reason = "funding tx had wrong script/value or output index" ;
4992
+ return Err(ClosureReason::ProcessingError { err: err_reason.to_owned() });
4993
+ } else {
4994
+ if funding.is_outbound () {
4995
+ if ! tx.is_coinbase () {
4996
+ for input in tx.input.iter () {
4997
+ if input.witness.is_empty() {
4998
+ // We generated a malleable funding transaction, implying we've
4999
+ // just exposed ourselves to funds loss to our counterparty.
5000
+ #[cfg(not(fuzzing))]
5001
+ panic!("Client called ChannelManager::funding_transaction_generated with bogus transaction!");
4978
5002
}
4979
5003
}
4980
5004
}
5005
+ }
4981
5006
4982
- // The acceptor of v1-established channels doesn't have the funding
4983
- // transaction until it is seen on chain. Set it so that minimum_depth
4984
- // checks can tell if the coinbase transaction was used.
4985
- if funding.funding_transaction.is_none() {
4986
- funding.funding_transaction = Some(tx.clone());
4987
- }
4988
-
4989
- funding.funding_tx_confirmation_height = height;
4990
- funding.funding_tx_confirmed_in = Some(*block_hash);
4991
- funding.short_channel_id = match scid_from_parts(height as u64, index_in_block as u64, txo_idx as u64) {
4992
- Ok(scid) => Some(scid),
4993
- Err(_) => panic!("Block was bogus - either height was > 16 million, had > 16 million transactions, or had > 65k outputs"),
4994
- };
5007
+ // The acceptor of v1-established channels doesn't have the funding
5008
+ // transaction until it is seen on chain. Set it so that minimum_depth
5009
+ // checks can tell if the coinbase transaction was used.
5010
+ if funding.funding_transaction.is_none() {
5011
+ funding.funding_transaction = Some(tx.clone());
4995
5012
}
4996
5013
4997
- confirmed_funding_tx = Some(tx);
5014
+ funding.funding_tx_confirmation_height = height;
5015
+ funding.funding_tx_confirmed_in = Some(*block_hash);
5016
+ funding.short_channel_id = match scid_from_parts(height as u64, index_in_block as u64, txo_idx as u64) {
5017
+ Ok(scid) => Some(scid),
5018
+ Err(_) => panic!("Block was bogus - either height was > 16 million, had > 16 million transactions, or had > 65k outputs"),
5019
+ };
4998
5020
}
5021
+
5022
+ is_confirmed_funding_tx = true;
4999
5023
}
5000
- for inp in tx.input.iter() {
5001
- if inp.previous_output == funding_txo.into_bitcoin_outpoint () {
5002
- log_info!(logger, "Detected channel-closing tx {} spending {}:{}, closing channel {}", tx.compute_txid(), inp.previous_output.txid, inp.previous_output.vout, &self.channel_id());
5003
- return Err(ClosureReason::CommitmentTxConfirmed );
5004
- }
5024
+ }
5025
+ for inp in tx.tx().input.iter () {
5026
+ if inp.previous_output == funding_txo.into_bitcoin_outpoint() {
5027
+ log_info!(logger, "Detected channel-closing tx {} spending {}:{}, closing channel {}", tx.txid(), inp.previous_output.txid, inp.previous_output.vout, &self.channel_id() );
5028
+ return Err(ClosureReason::CommitmentTxConfirmed);
5005
5029
}
5006
5030
}
5007
5031
5008
- Ok(confirmed_funding_tx )
5032
+ Ok(is_confirmed_funding_tx )
5009
5033
}
5010
5034
}
5011
5035
@@ -8327,59 +8351,63 @@ impl<SP: Deref> FundedChannel<SP> where
8327
8351
NS::Target: NodeSigner,
8328
8352
L::Target: Logger
8329
8353
{
8330
- // If we allow 1-conf funding, we may need to check for channel_ready or splice_locked here
8331
- // and send it immediately instead of waiting for a best_block_updated call (which may have
8332
- // already happened for this block).
8333
- let confirmed_funding_tx = self.context.check_for_funding_tx(
8334
- &mut self.funding, block_hash, height, txdata, logger,
8335
- )?;
8354
+ for &(index_in_block, tx) in txdata.iter() {
8355
+ let mut confirmed_tx = ConfirmedTransaction::from(tx);
8336
8356
8337
- if let Some(funding_tx) = confirmed_funding_tx {
8338
- if let Some(channel_ready) = self.check_get_channel_ready(height, logger) {
8339
- log_info!(logger, "Sending a channel_ready to our peer for channel {}", &self.context.channel_id);
8340
- let announcement_sigs = self.get_announcement_sigs(node_signer, chain_hash, user_config, height, logger);
8341
- return Ok((Some(FundingConfirmedMessage::Establishment(channel_ready)), announcement_sigs));
8342
- }
8343
- }
8357
+ // If we allow 1-conf funding, we may need to check for channel_ready or splice_locked here
8358
+ // and send it immediately instead of waiting for a best_block_updated call (which may have
8359
+ // already happened for this block).
8360
+ let is_confirmed_funding_tx = self.context.check_for_funding_tx(
8361
+ &mut self.funding, block_hash, height, index_in_block, &mut confirmed_tx, logger,
8362
+ )?;
8344
8363
8345
- #[cfg(splicing)]
8346
- let mut confirmed_funding = None;
8347
- #[cfg(splicing)]
8348
- for funding in self.pending_funding.iter_mut() {
8349
- if self.context.check_for_funding_tx(funding, block_hash, height, txdata, logger)?.is_some() {
8350
- if confirmed_funding.is_some() {
8351
- let err_reason = "splice tx of another pending funding already confirmed";
8352
- return Err(ClosureReason::ProcessingError { err: err_reason.to_owned() });
8364
+ if is_confirmed_funding_tx {
8365
+ if let Some(channel_ready) = self.check_get_channel_ready(height, logger) {
8366
+ log_info!(logger, "Sending a channel_ready to our peer for channel {}", &self.context.channel_id);
8367
+ let announcement_sigs = self.get_announcement_sigs(node_signer, chain_hash, user_config, height, logger);
8368
+ return Ok((Some(FundingConfirmedMessage::Establishment(channel_ready)), announcement_sigs));
8353
8369
}
8370
+ }
8371
+
8372
+ #[cfg(splicing)]
8373
+ let mut confirmed_funding = None;
8374
+ #[cfg(splicing)]
8375
+ for funding in self.pending_funding.iter_mut() {
8376
+ if self.context.check_for_funding_tx(funding, block_hash, height, index_in_block, &mut confirmed_tx, logger)? {
8377
+ if confirmed_funding.is_some() {
8378
+ let err_reason = "splice tx of another pending funding already confirmed";
8379
+ return Err(ClosureReason::ProcessingError { err: err_reason.to_owned() });
8380
+ }
8354
8381
8355
- confirmed_funding = Some(funding);
8382
+ confirmed_funding = Some(funding);
8383
+ }
8356
8384
}
8357
- }
8358
8385
8359
- #[cfg(splicing)]
8360
- if let Some(funding) = confirmed_funding {
8361
- let pending_splice = match self.pending_splice.as_mut() {
8362
- Some(pending_splice) => pending_splice,
8363
- None => {
8364
- // TODO: Move pending_funding into pending_splice?
8365
- debug_assert!(false);
8366
- // TODO: Error instead?
8367
- return Ok((None, None));
8368
- },
8369
- };
8386
+ #[cfg(splicing)]
8387
+ if let Some(funding) = confirmed_funding {
8388
+ let pending_splice = match self.pending_splice.as_mut() {
8389
+ Some(pending_splice) => pending_splice,
8390
+ None => {
8391
+ // TODO: Move pending_funding into pending_splice?
8392
+ debug_assert!(false);
8393
+ // TODO: Error instead?
8394
+ return Ok((None, None));
8395
+ },
8396
+ };
8370
8397
8371
- if let Some(splice_locked) = self.context.check_get_splice_locked(pending_splice, funding, height, logger) {
8372
- log_info!(logger, "Sending a splice_locked to our peer for channel {}", &self.context.channel_id);
8398
+ if let Some(splice_locked) = self.context.check_get_splice_locked(pending_splice, funding, height, logger) {
8399
+ log_info!(logger, "Sending a splice_locked to our peer for channel {}", &self.context.channel_id);
8373
8400
8374
- pending_splice.sent_funding_txid = Some(splice_locked.splice_txid);
8375
- if pending_splice.sent_funding_txid == pending_splice.received_funding_txid {
8376
- promote_splice_funding!(self, funding);
8401
+ pending_splice.sent_funding_txid = Some(splice_locked.splice_txid);
8402
+ if pending_splice.sent_funding_txid == pending_splice.received_funding_txid {
8403
+ promote_splice_funding!(self, funding);
8377
8404
8378
- let announcement_sigs = self.get_announcement_sigs(node_signer, chain_hash, user_config, height, logger);
8379
- return Ok((Some(FundingConfirmedMessage::Splice(splice_locked)), announcement_sigs));
8380
- }
8405
+ let announcement_sigs = self.get_announcement_sigs(node_signer, chain_hash, user_config, height, logger);
8406
+ return Ok((Some(FundingConfirmedMessage::Splice(splice_locked)), announcement_sigs));
8407
+ }
8381
8408
8382
- return Ok((Some(FundingConfirmedMessage::Splice(splice_locked)), None));
8409
+ return Ok((Some(FundingConfirmedMessage::Splice(splice_locked)), None));
8410
+ }
8383
8411
}
8384
8412
}
8385
8413
0 commit comments