@@ -534,7 +534,9 @@ enum OnchainEvent {
534534 } ,
535535 /// An output waiting on [`ANTI_REORG_DELAY`] confirmations before we hand the user the
536536 /// [`SpendableOutputDescriptor`].
537- MaturingOutput { descriptor : SpendableOutputDescriptor } ,
537+ MaturingOutput {
538+ descriptor : SpendableOutputDescriptor ,
539+ } ,
538540 /// A spend of the funding output, either a commitment transaction or a cooperative closing
539541 /// transaction.
540542 FundingSpendConfirmation {
@@ -578,6 +580,16 @@ enum OnchainEvent {
578580 // considered locked.
579581 confirmation_depth : u32 ,
580582 } ,
583+ // We've negotiated and locked (via a `RenegotiatedFundingLocked` monitor update) a zero conf
584+ // funding transcation. If confirmations were required, we'd remove all alternative funding
585+ // transactions and their associated holder commitment transactions, as we can assume they can
586+ // no longer confirm. However, with zero conf funding transactions, we cannot guarantee this.
587+ // Ultimately an alternative funding transaction could actually end up on chain, and we must
588+ // still be able to claim our funds from it.
589+ //
590+ // This event will only be generated when a `RenegotiatedFundingLocked` monitor update is
591+ // applied for a zero conf funding transaction.
592+ ZeroConfFundingReorgSafety { } ,
581593}
582594
583595impl Writeable for OnchainEventEntry {
@@ -629,6 +641,7 @@ impl_writeable_tlv_based_enum_upgradable!(OnchainEvent,
629641 ( 0 , on_local_output_csv, option) ,
630642 ( 1 , commitment_tx_to_counterparty_output, option) ,
631643 } ,
644+ ( 4 , ZeroConfFundingReorgSafety ) => { } ,
632645 ( 5 , HTLCSpendConfirmation ) => {
633646 ( 0 , commitment_tx_output_idx, required) ,
634647 ( 2 , preimage, option) ,
@@ -1299,6 +1312,11 @@ pub(crate) struct ChannelMonitorImpl<Signer: EcdsaChannelSigner> {
12991312 // commitment transactions, their ordering with respect to each other must remain the same.
13001313 current_holder_htlc_data : CommitmentHTLCData ,
13011314 prev_holder_htlc_data : Option < CommitmentHTLCData > ,
1315+
1316+ // If a funding transaction has been renegotiated for the channel and it requires zero
1317+ // confirmations to be considered locked, we wait for `ANTI_REORG_DELAY` confirmations until we
1318+ // no longer track alternative funding candidates.
1319+ wait_for_0conf_funding_reorg_safety : bool ,
13021320}
13031321
13041322// Macro helper to access holder commitment HTLC data (including both non-dust and dust) while
@@ -1556,6 +1574,8 @@ impl<Signer: EcdsaChannelSigner> Writeable for ChannelMonitorImpl<Signer> {
15561574 _ => self . pending_monitor_events . clone ( ) ,
15571575 } ;
15581576
1577+ let wait_for_0conf_funding_reorg_safety = self . wait_for_0conf_funding_reorg_safety . then ( || ( ) ) ;
1578+
15591579 write_tlv_fields ! ( writer, {
15601580 ( 1 , self . funding_spend_confirmed, option) ,
15611581 ( 3 , self . htlcs_resolved_on_chain, required_vec) ,
@@ -1574,6 +1594,7 @@ impl<Signer: EcdsaChannelSigner> Writeable for ChannelMonitorImpl<Signer> {
15741594 ( 29 , self . initial_counterparty_commitment_tx, option) ,
15751595 ( 31 , self . funding. channel_parameters, required) ,
15761596 ( 32 , self . pending_funding, optional_vec) ,
1597+ ( 34 , wait_for_0conf_funding_reorg_safety, option) ,
15771598 } ) ;
15781599
15791600 Ok ( ( ) )
@@ -1799,6 +1820,8 @@ impl<Signer: EcdsaChannelSigner> ChannelMonitor<Signer> {
17991820 // There are never any HTLCs in the initial commitment transaction
18001821 current_holder_htlc_data : CommitmentHTLCData :: new ( ) ,
18011822 prev_holder_htlc_data : None ,
1823+
1824+ wait_for_0conf_funding_reorg_safety : false ,
18021825 } )
18031826 }
18041827
@@ -3835,23 +3858,29 @@ impl<Signer: EcdsaChannelSigner> ChannelMonitorImpl<Signer> {
38353858 Ok ( ( ) )
38363859 }
38373860
3838- fn promote_funding ( & mut self , new_funding_txid : Txid ) -> Result < ( ) , ( ) > {
3861+ fn promote_funding (
3862+ & mut self , new_funding_txid : Txid , from_monitor_update : bool ,
3863+ ) -> Result < ( ) , ( ) > {
38393864 let new_funding = self
38403865 . pending_funding
38413866 . iter_mut ( )
3842- . map ( |pending_funding| & mut pending_funding. 0 )
3843- . find ( |funding| funding. funding_txid ( ) == new_funding_txid) ;
3867+ . find ( |pending_funding| pending_funding. 0 . funding_txid ( ) == new_funding_txid) ;
38443868 if new_funding. is_none ( ) {
38453869 return Err ( ( ) ) ;
38463870 }
3847- let mut new_funding = new_funding. unwrap ( ) ;
3871+ let ( new_funding, confirmation_depth ) = new_funding. unwrap ( ) ;
38483872
3849- mem:: swap ( & mut self . funding , & mut new_funding) ;
3873+ mem:: swap ( & mut self . funding , new_funding) ;
38503874 self . onchain_tx_handler . update_after_renegotiated_funding_locked (
38513875 self . funding . current_holder_commitment_tx . clone ( ) ,
38523876 self . funding . prev_holder_commitment_tx . clone ( ) ,
38533877 ) ;
38543878
3879+ if from_monitor_update && * confirmation_depth == 0 {
3880+ self . wait_for_0conf_funding_reorg_safety = true ;
3881+ return Ok ( ( ) ) ;
3882+ }
3883+
38553884 // The swap above places the previous `FundingScope` into `pending_funding`.
38563885 for ( funding, _) in self . pending_funding . drain ( ..) {
38573886 self . outputs_to_watch . remove ( & funding. funding_txid ( ) ) ;
@@ -3982,7 +4011,7 @@ impl<Signer: EcdsaChannelSigner> ChannelMonitorImpl<Signer> {
39824011 } ,
39834012 ChannelMonitorUpdateStep :: RenegotiatedFundingLocked { funding_txid } => {
39844013 log_trace ! ( logger, "Updating ChannelMonitor with locked renegotiated funding txid {}" , funding_txid) ;
3985- if let Err ( _) = self . promote_funding ( * funding_txid) {
4014+ if let Err ( _) = self . promote_funding ( * funding_txid, true ) {
39864015 log_error ! ( logger, "Unknown funding with txid {} became locked" , funding_txid) ;
39874016 ret = Err ( ( ) ) ;
39884017 }
@@ -4940,6 +4969,20 @@ impl<Signer: EcdsaChannelSigner> ChannelMonitorImpl<Signer> {
49404969 }
49414970 }
49424971
4972+ // A zero-conf renegotiated funding transaction has confirmed. We should have already
4973+ // applied the corresponding `RenegotiatedFundingLocked` monitor update for it, but
4974+ // we're still tracking the alternative funding transactions until we're reorg safe.
4975+ if self . wait_for_0conf_funding_reorg_safety && self . funding . funding_txid ( ) == txid {
4976+ debug_assert ! ( self . funding_spend_confirmed. is_none( ) ) ;
4977+ self . onchain_events_awaiting_threshold_conf . push ( OnchainEventEntry {
4978+ txid,
4979+ transaction : Some ( ( * tx) . clone ( ) ) ,
4980+ height,
4981+ block_hash : Some ( block_hash) ,
4982+ event : OnchainEvent :: ZeroConfFundingReorgSafety { } ,
4983+ } ) ;
4984+ }
4985+
49434986 // A splice transaction has confirmed. We can't promote the splice's scope until we see
49444987 // the corresponding monitor update for it, but we track the txid so we know which
49454988 // holder commitment transaction we may need to broadcast.
@@ -5212,19 +5255,35 @@ impl<Signer: EcdsaChannelSigner> ChannelMonitorImpl<Signer> {
52125255 } ,
52135256 OnchainEvent :: AlternativeFundingConfirmation { .. } => {
52145257 // An alternative funding transaction has irrevocably confirmed. Locate the
5215- // corresponding scope and promote it if the monitor is no longer allowing
5216- // updates. Otherwise, we expect it to be promoted via
5217- // [`ChannelMonitorUpdateStep::RenegotiatedFundingLocked`].
5218- if self . no_further_updates_allowed ( ) {
5258+ // corresponding scope and promote it. If we're still allowing monitor updates,
5259+ // we expect it to be promoted via
5260+ // [`ChannelMonitorUpdateStep::RenegotiatedFundingLocked`] instead. However, in
5261+ // the zero conf funding case, while we already promoted the scope, we're still
5262+ // tracking the alternative funding candidates until we're reorg safe.
5263+ if self . no_further_updates_allowed ( ) || self . wait_for_0conf_funding_reorg_safety {
52195264 let funding_txid = entry. transaction
52205265 . expect ( "Transactions are always present for AlternativeFundingConfirmation entries" )
52215266 . compute_txid ( ) ;
52225267 debug_assert_ne ! ( self . funding. funding_txid( ) , funding_txid) ;
5223- if let Err ( _) = self . promote_funding ( funding_txid) {
5268+ if let Err ( _) = self . promote_funding ( funding_txid, false ) {
52245269 log_error ! ( logger, "Missing scope for alternative funding confirmation with txid {}" , entry. txid) ;
52255270 }
52265271 }
52275272 } ,
5273+ OnchainEvent :: ZeroConfFundingReorgSafety { } => {
5274+ if self . wait_for_0conf_funding_reorg_safety {
5275+ debug_assert_eq ! ( self . funding. funding_txid( ) , entry. txid) ;
5276+ self
5277+ . pending_funding
5278+ . drain ( ..)
5279+ . for_each ( |( funding, _) | {
5280+ self . outputs_to_watch . remove ( & funding. funding_txid ( ) ) ;
5281+ } ) ;
5282+ self . wait_for_0conf_funding_reorg_safety = false ;
5283+ } else {
5284+ debug_assert ! ( false , "These events can only be generated when wait_for_0conf_funding_reorg_safety is set" ) ;
5285+ }
5286+ } ,
52285287 }
52295288 }
52305289
@@ -6073,6 +6132,7 @@ impl<'a, 'b, ES: EntropySource, SP: SignerProvider> ReadableArgs<(&'a ES, &'b SP
60736132 let mut first_negotiated_funding_txo = RequiredWrapper ( None ) ;
60746133 let mut channel_parameters = None ;
60756134 let mut pending_funding = None ;
6135+ let mut wait_for_0conf_funding_reorg_safety: Option < ( ) > = None ;
60766136 read_tlv_fields ! ( reader, {
60776137 ( 1 , funding_spend_confirmed, option) ,
60786138 ( 3 , htlcs_resolved_on_chain, optional_vec) ,
@@ -6091,6 +6151,7 @@ impl<'a, 'b, ES: EntropySource, SP: SignerProvider> ReadableArgs<(&'a ES, &'b SP
60916151 ( 29 , initial_counterparty_commitment_tx, option) ,
60926152 ( 31 , channel_parameters, ( option: ReadableArgs , None ) ) ,
60936153 ( 32 , pending_funding, optional_vec) ,
6154+ ( 34 , wait_for_0conf_funding_reorg_safety, option) ,
60946155 } ) ;
60956156 if let Some ( payment_preimages_with_info) = payment_preimages_with_info {
60966157 if payment_preimages_with_info. len ( ) != payment_preimages. len ( ) {
@@ -6260,6 +6321,8 @@ impl<'a, 'b, ES: EntropySource, SP: SignerProvider> ReadableArgs<(&'a ES, &'b SP
62606321
62616322 current_holder_htlc_data,
62626323 prev_holder_htlc_data,
6324+
6325+ wait_for_0conf_funding_reorg_safety : wait_for_0conf_funding_reorg_safety. is_some ( ) ,
62636326 } ) ) )
62646327 }
62656328}
0 commit comments