@@ -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) ,
@@ -1301,6 +1314,11 @@ pub(crate) struct ChannelMonitorImpl<Signer: EcdsaChannelSigner> {
13011314 // commitment transactions, their ordering with respect to each other must remain the same.
13021315 current_holder_htlc_data : CommitmentHTLCData ,
13031316 prev_holder_htlc_data : Option < CommitmentHTLCData > ,
1317+
1318+ // If a funding transaction has been renegotiated for the channel and it requires zero
1319+ // confirmations to be considered locked, we wait for `ANTI_REORG_DELAY` confirmations until we
1320+ // no longer track alternative funding candidates.
1321+ wait_for_0conf_funding_reorg_safety : bool ,
13041322}
13051323
13061324// Macro helper to access holder commitment HTLC data (including both non-dust and dust) while
@@ -1558,6 +1576,8 @@ impl<Signer: EcdsaChannelSigner> Writeable for ChannelMonitorImpl<Signer> {
15581576 _ => self . pending_monitor_events . clone ( ) ,
15591577 } ;
15601578
1579+ let wait_for_0conf_funding_reorg_safety = self . wait_for_0conf_funding_reorg_safety . then ( || ( ) ) ;
1580+
15611581 write_tlv_fields ! ( writer, {
15621582 ( 1 , self . funding_spend_confirmed, option) ,
15631583 ( 3 , self . htlcs_resolved_on_chain, required_vec) ,
@@ -1576,6 +1596,7 @@ impl<Signer: EcdsaChannelSigner> Writeable for ChannelMonitorImpl<Signer> {
15761596 ( 29 , self . initial_counterparty_commitment_tx, option) ,
15771597 ( 31 , self . funding. channel_parameters, required) ,
15781598 ( 32 , self . pending_funding, optional_vec) ,
1599+ ( 34 , wait_for_0conf_funding_reorg_safety, option) ,
15791600 } ) ;
15801601
15811602 Ok ( ( ) )
@@ -1801,6 +1822,8 @@ impl<Signer: EcdsaChannelSigner> ChannelMonitor<Signer> {
18011822 // There are never any HTLCs in the initial commitment transaction
18021823 current_holder_htlc_data : CommitmentHTLCData :: new ( ) ,
18031824 prev_holder_htlc_data : None ,
1825+
1826+ wait_for_0conf_funding_reorg_safety : false ,
18041827 } )
18051828 }
18061829
@@ -3837,23 +3860,29 @@ impl<Signer: EcdsaChannelSigner> ChannelMonitorImpl<Signer> {
38373860 Ok ( ( ) )
38383861 }
38393862
3840- fn promote_funding ( & mut self , new_funding_txid : Txid ) -> Result < ( ) , ( ) > {
3863+ fn promote_funding (
3864+ & mut self , new_funding_txid : Txid , from_monitor_update : bool ,
3865+ ) -> Result < ( ) , ( ) > {
38413866 let new_funding = self
38423867 . pending_funding
38433868 . iter_mut ( )
3844- . map ( |pending_funding| & mut pending_funding. 0 )
3845- . find ( |funding| funding. funding_txid ( ) == new_funding_txid) ;
3869+ . find ( |pending_funding| pending_funding. 0 . funding_txid ( ) == new_funding_txid) ;
38463870 if new_funding. is_none ( ) {
38473871 return Err ( ( ) ) ;
38483872 }
3849- let mut new_funding = new_funding. unwrap ( ) ;
3873+ let ( new_funding, confirmation_depth ) = new_funding. unwrap ( ) ;
38503874
3851- mem:: swap ( & mut self . funding , & mut new_funding) ;
3875+ mem:: swap ( & mut self . funding , new_funding) ;
38523876 self . onchain_tx_handler . update_after_renegotiated_funding_locked (
38533877 self . funding . current_holder_commitment_tx . clone ( ) ,
38543878 self . funding . prev_holder_commitment_tx . clone ( ) ,
38553879 ) ;
38563880
3881+ if from_monitor_update && * confirmation_depth == 0 {
3882+ self . wait_for_0conf_funding_reorg_safety = true ;
3883+ return Ok ( ( ) ) ;
3884+ }
3885+
38573886 // The swap above places the previous `FundingScope` into `pending_funding`.
38583887 for ( funding, _) in self . pending_funding . drain ( ..) {
38593888 self . outputs_to_watch . remove ( & funding. funding_txid ( ) ) ;
@@ -3984,7 +4013,7 @@ impl<Signer: EcdsaChannelSigner> ChannelMonitorImpl<Signer> {
39844013 } ,
39854014 ChannelMonitorUpdateStep :: RenegotiatedFundingLocked { funding_txid } => {
39864015 log_trace ! ( logger, "Updating ChannelMonitor with locked renegotiated funding txid {}" , funding_txid) ;
3987- if let Err ( _) = self . promote_funding ( * funding_txid) {
4016+ if let Err ( _) = self . promote_funding ( * funding_txid, true ) {
39884017 log_error ! ( logger, "Unknown funding with txid {} became locked" , funding_txid) ;
39894018 ret = Err ( ( ) ) ;
39904019 }
@@ -4942,6 +4971,20 @@ impl<Signer: EcdsaChannelSigner> ChannelMonitorImpl<Signer> {
49424971 }
49434972 }
49444973
4974+ // A zero-conf renegotiated funding transaction has confirmed. We should have already
4975+ // applied the corresponding `RenegotiatedFundingLocked` monitor update for it, but
4976+ // we're still tracking the alternative funding transactions until we're reorg safe.
4977+ if self . wait_for_0conf_funding_reorg_safety && self . funding . funding_txid ( ) == txid {
4978+ debug_assert ! ( self . funding_spend_confirmed. is_none( ) ) ;
4979+ self . onchain_events_awaiting_threshold_conf . push ( OnchainEventEntry {
4980+ txid,
4981+ transaction : Some ( ( * tx) . clone ( ) ) ,
4982+ height,
4983+ block_hash : Some ( block_hash) ,
4984+ event : OnchainEvent :: ZeroConfFundingReorgSafety { } ,
4985+ } ) ;
4986+ }
4987+
49454988 // A splice transaction has confirmed. We can't promote the splice's scope until we see
49464989 // the corresponding monitor update for it, but we track the txid so we know which
49474990 // holder commitment transaction we may need to broadcast.
@@ -5214,19 +5257,35 @@ impl<Signer: EcdsaChannelSigner> ChannelMonitorImpl<Signer> {
52145257 } ,
52155258 OnchainEvent :: AlternativeFundingConfirmation { .. } => {
52165259 // An alternative funding transaction has irrevocably confirmed. Locate the
5217- // corresponding scope and promote it if the monitor is no longer allowing
5218- // updates. Otherwise, we expect it to be promoted via
5219- // [`ChannelMonitorUpdateStep::RenegotiatedFundingLocked`].
5220- if self . no_further_updates_allowed ( ) {
5260+ // corresponding scope and promote it. If we're still allowing monitor updates,
5261+ // we expect it to be promoted via
5262+ // [`ChannelMonitorUpdateStep::RenegotiatedFundingLocked`] instead. However, in
5263+ // the zero conf funding case, while we already promoted the scope, we're still
5264+ // tracking the alternative funding candidates until we're reorg safe.
5265+ if self . no_further_updates_allowed ( ) || self . wait_for_0conf_funding_reorg_safety {
52215266 let funding_txid = entry. transaction
52225267 . expect ( "Transactions are always present for AlternativeFundingConfirmation entries" )
52235268 . compute_txid ( ) ;
52245269 debug_assert_ne ! ( self . funding. funding_txid( ) , funding_txid) ;
5225- if let Err ( _) = self . promote_funding ( funding_txid) {
5270+ if let Err ( _) = self . promote_funding ( funding_txid, false ) {
52265271 log_error ! ( logger, "Missing scope for alternative funding confirmation with txid {}" , entry. txid) ;
52275272 }
52285273 }
52295274 } ,
5275+ OnchainEvent :: ZeroConfFundingReorgSafety { } => {
5276+ if self . wait_for_0conf_funding_reorg_safety {
5277+ debug_assert_eq ! ( self . funding. funding_txid( ) , entry. txid) ;
5278+ self
5279+ . pending_funding
5280+ . drain ( ..)
5281+ . for_each ( |( funding, _) | {
5282+ self . outputs_to_watch . remove ( & funding. funding_txid ( ) ) ;
5283+ } ) ;
5284+ self . wait_for_0conf_funding_reorg_safety = false ;
5285+ } else {
5286+ debug_assert ! ( false , "These events can only be generated when wait_for_0conf_funding_reorg_safety is set" ) ;
5287+ }
5288+ } ,
52305289 }
52315290 }
52325291
@@ -6075,6 +6134,7 @@ impl<'a, 'b, ES: EntropySource, SP: SignerProvider> ReadableArgs<(&'a ES, &'b SP
60756134 let mut first_negotiated_funding_txo = RequiredWrapper ( None ) ;
60766135 let mut channel_parameters = None ;
60776136 let mut pending_funding = None ;
6137+ let mut wait_for_0conf_funding_reorg_safety: Option < ( ) > = None ;
60786138 read_tlv_fields ! ( reader, {
60796139 ( 1 , funding_spend_confirmed, option) ,
60806140 ( 3 , htlcs_resolved_on_chain, optional_vec) ,
@@ -6093,6 +6153,7 @@ impl<'a, 'b, ES: EntropySource, SP: SignerProvider> ReadableArgs<(&'a ES, &'b SP
60936153 ( 29 , initial_counterparty_commitment_tx, option) ,
60946154 ( 31 , channel_parameters, ( option: ReadableArgs , None ) ) ,
60956155 ( 32 , pending_funding, optional_vec) ,
6156+ ( 34 , wait_for_0conf_funding_reorg_safety, option) ,
60966157 } ) ;
60976158 if let Some ( payment_preimages_with_info) = payment_preimages_with_info {
60986159 if payment_preimages_with_info. len ( ) != payment_preimages. len ( ) {
@@ -6262,6 +6323,8 @@ impl<'a, 'b, ES: EntropySource, SP: SignerProvider> ReadableArgs<(&'a ES, &'b SP
62626323
62636324 current_holder_htlc_data,
62646325 prev_holder_htlc_data,
6326+
6327+ wait_for_0conf_funding_reorg_safety : wait_for_0conf_funding_reorg_safety. is_some ( ) ,
62656328 } ) ) )
62666329 }
62676330}
0 commit comments