@@ -531,7 +531,9 @@ enum OnchainEvent {
531531 } ,
532532 /// An output waiting on [`ANTI_REORG_DELAY`] confirmations before we hand the user the
533533 /// [`SpendableOutputDescriptor`].
534- MaturingOutput { descriptor : SpendableOutputDescriptor } ,
534+ MaturingOutput {
535+ descriptor : SpendableOutputDescriptor ,
536+ } ,
535537 /// A spend of the funding output, either a commitment transaction or a cooperative closing
536538 /// transaction.
537539 FundingSpendConfirmation {
@@ -572,6 +574,17 @@ enum OnchainEvent {
572574 /// once [`ChannelMonitor::no_further_updates_allowed`] returns true. We promote the
573575 /// `FundingScope` once the funding transaction is irrevocably confirmed.
574576 AlternativeFundingConfirmation { } ,
577+ // We've negotiated and locked (via a [`ChannelMonitorUpdateStep::RenegotiatedFundingLocked`]) a
578+ // zero conf funding transcation. If confirmations were required, we'd remove all alternative
579+ // funding transactions and their associated holder commitment transactions, as we assume they
580+ // can no longer confirm. However, with zero conf funding transactions, we cannot guarantee
581+ // this. Ultimately an alternative funding transaction could actually end up on chain, and we
582+ // must still be able to claim our funds from it.
583+ //
584+ // This event will only be generated when a
585+ // [`ChannelMonitorUpdateStep::RenegotiatedFundingLocked`] is applied for a zero conf funding
586+ // transaction.
587+ ZeroConfFundingReorgSafety { } ,
575588}
576589
577590impl Writeable for OnchainEventEntry {
@@ -621,6 +634,7 @@ impl_writeable_tlv_based_enum_upgradable!(OnchainEvent,
621634 ( 0 , on_local_output_csv, option) ,
622635 ( 1 , commitment_tx_to_counterparty_output, option) ,
623636 } ,
637+ ( 4 , ZeroConfFundingReorgSafety ) => { } ,
624638 ( 5 , HTLCSpendConfirmation ) => {
625639 ( 0 , commitment_tx_output_idx, required) ,
626640 ( 2 , preimage, option) ,
@@ -684,6 +698,7 @@ pub(crate) enum ChannelMonitorUpdateStep {
684698 channel_parameters : ChannelTransactionParameters ,
685699 holder_commitment_tx : HolderCommitmentTransaction ,
686700 counterparty_commitment_tx : CommitmentTransaction ,
701+ confirmation_depth : u32 ,
687702 } ,
688703 RenegotiatedFundingLocked {
689704 funding_txid : Txid ,
@@ -751,6 +766,7 @@ impl_writeable_tlv_based_enum_upgradable!(ChannelMonitorUpdateStep,
751766 ( 1 , channel_parameters, ( required: ReadableArgs , None ) ) ,
752767 ( 3 , holder_commitment_tx, required) ,
753768 ( 5 , counterparty_commitment_tx, required) ,
769+ ( 7 , confirmation_depth, required) ,
754770 } ,
755771 ( 12 , RenegotiatedFundingLocked ) => {
756772 ( 1 , funding_txid, required) ,
@@ -1293,6 +1309,11 @@ pub(crate) struct ChannelMonitorImpl<Signer: EcdsaChannelSigner> {
12931309 prev_holder_htlc_data : Option < CommitmentHTLCData > ,
12941310
12951311 alternative_funding_confirmed : Option < ( Txid , u32 ) > ,
1312+
1313+ // If a funding transaction has been renegotiated for the channel and it requires zero
1314+ // confirmations to be considered locked, we wait for `ANTI_REORG_DELAY` confirmations until we
1315+ // no longer track alternative funding candidates.
1316+ wait_for_0conf_funding_reorg_safety : bool ,
12961317}
12971318
12981319// Macro helper to access holder commitment HTLC data (including both non-dust and dust) while
@@ -1550,6 +1571,8 @@ impl<Signer: EcdsaChannelSigner> Writeable for ChannelMonitorImpl<Signer> {
15501571 _ => self . pending_monitor_events . clone ( ) ,
15511572 } ;
15521573
1574+ let wait_for_0conf_funding_reorg_safety = self . wait_for_0conf_funding_reorg_safety . then ( || ( ) ) ;
1575+
15531576 write_tlv_fields ! ( writer, {
15541577 ( 1 , self . funding_spend_confirmed, option) ,
15551578 ( 3 , self . htlcs_resolved_on_chain, required_vec) ,
@@ -1569,6 +1592,7 @@ impl<Signer: EcdsaChannelSigner> Writeable for ChannelMonitorImpl<Signer> {
15691592 ( 31 , self . funding. channel_parameters, required) ,
15701593 ( 32 , self . pending_funding, optional_vec) ,
15711594 ( 34 , self . alternative_funding_confirmed, option) ,
1595+ ( 36 , wait_for_0conf_funding_reorg_safety, option) ,
15721596 } ) ;
15731597
15741598 Ok ( ( ) )
@@ -1796,6 +1820,7 @@ impl<Signer: EcdsaChannelSigner> ChannelMonitor<Signer> {
17961820 prev_holder_htlc_data : None ,
17971821
17981822 alternative_funding_confirmed : None ,
1823+ wait_for_0conf_funding_reorg_safety : false ,
17991824 } )
18001825 }
18011826
@@ -3417,6 +3442,7 @@ impl<Signer: EcdsaChannelSigner> ChannelMonitorImpl<Signer> {
34173442 self . update_holder_commitment_data ( vec ! [ holder_commitment_tx] , htlc_data, claimed_htlcs)
34183443 }
34193444
3445+ // TODO(splicing): Consider `wait_for_0conf_funding_reorg_safety`.
34203446 fn verify_matching_commitment_transactions <
34213447 ' a ,
34223448 I : ExactSizeIterator < Item = & ' a CommitmentTransaction > ,
@@ -3704,7 +3730,7 @@ impl<Signer: EcdsaChannelSigner> ChannelMonitorImpl<Signer> {
37043730 & mut self , logger : & WithChannelMonitor < L > ,
37053731 channel_parameters : & ChannelTransactionParameters ,
37063732 alternative_holder_commitment_tx : & HolderCommitmentTransaction ,
3707- alternative_counterparty_commitment_tx : & CommitmentTransaction ,
3733+ alternative_counterparty_commitment_tx : & CommitmentTransaction , confirmation_depth : u32 ,
37083734 ) -> Result < ( ) , ( ) >
37093735 where
37103736 L :: Target : Logger ,
@@ -3793,14 +3819,16 @@ impl<Signer: EcdsaChannelSigner> ChannelMonitorImpl<Signer> {
37933819 if let Some ( parent_funding_txid) = channel_parameters. splice_parent_funding_txid . as_ref ( ) {
37943820 // Only one splice can be negotiated at a time after we've exchanged `channel_ready`
37953821 // (implying our funding is confirmed) that spends our currently locked funding.
3796- if !self . pending_funding . is_empty ( ) {
3822+ if !self . pending_funding . is_empty ( ) && ! self . wait_for_0conf_funding_reorg_safety {
37973823 log_error ! (
37983824 logger,
37993825 "Negotiated splice while channel is pending channel_ready/splice_locked"
38003826 ) ;
38013827 return Err ( ( ) ) ;
38023828 }
3803- if * parent_funding_txid != self . funding . funding_txid ( ) {
3829+ if * parent_funding_txid != self . funding . funding_txid ( )
3830+ || alternative_funding_outpoint. txid != self . funding . funding_txid ( )
3831+ {
38043832 log_error ! (
38053833 logger,
38063834 "Negotiated splice that does not spend currently locked funding transaction"
@@ -3820,6 +3848,11 @@ impl<Signer: EcdsaChannelSigner> ChannelMonitorImpl<Signer> {
38203848 ) ;
38213849 self . pending_funding . push ( alternative_funding) ;
38223850
3851+ // FIXME: Wait for anything below `ANTI_REORG_DELAY`, not just zero conf?
3852+ if !self . wait_for_0conf_funding_reorg_safety {
3853+ self . wait_for_0conf_funding_reorg_safety = confirmation_depth == 0 ;
3854+ }
3855+
38233856 Ok ( ( ) )
38243857 }
38253858
@@ -3831,20 +3864,28 @@ impl<Signer: EcdsaChannelSigner> ChannelMonitorImpl<Signer> {
38313864 if new_funding. is_none ( ) {
38323865 return Err ( ( ) ) ;
38333866 }
3834- let mut new_funding = new_funding. unwrap ( ) ;
3867+ let new_funding = new_funding. unwrap ( ) ;
38353868
3836- mem:: swap ( & mut self . funding , & mut new_funding) ;
3869+ mem:: swap ( & mut self . funding , new_funding) ;
38373870 self . onchain_tx_handler . update_after_renegotiated_funding_locked (
38383871 self . funding . current_holder_commitment_tx . clone ( ) ,
38393872 self . funding . prev_holder_commitment_tx . clone ( ) ,
38403873 ) ;
38413874
3875+ if self . wait_for_0conf_funding_reorg_safety {
3876+ return Ok ( ( ) ) ;
3877+ }
3878+
38423879 // The swap above places the previous `FundingScope` into `pending_funding`.
38433880 for funding in self . pending_funding . drain ( ..) {
38443881 self . outputs_to_watch . remove ( & funding. funding_txid ( ) ) ;
38453882 }
38463883 self . alternative_funding_confirmed . take ( ) ;
38473884
3885+ // Make sure we're no longer waiting for zero conf funding reorg safety if a non-zero conf
3886+ // splice is negotiated and locked after a zero conf one.
3887+ self . wait_for_0conf_funding_reorg_safety = false ;
3888+
38483889 Ok ( ( ) )
38493890 }
38503891
@@ -3957,11 +3998,13 @@ impl<Signer: EcdsaChannelSigner> ChannelMonitorImpl<Signer> {
39573998 } ,
39583999 ChannelMonitorUpdateStep :: RenegotiatedFunding {
39594000 channel_parameters, holder_commitment_tx, counterparty_commitment_tx,
4001+ confirmation_depth,
39604002 } => {
39614003 log_trace ! ( logger, "Updating ChannelMonitor with alternative holder and counterparty commitment transactions for funding txid {}" ,
39624004 channel_parameters. funding_outpoint. unwrap( ) . txid) ;
39634005 if let Err ( _) = self . renegotiated_funding (
39644006 logger, channel_parameters, holder_commitment_tx, counterparty_commitment_tx,
4007+ * confirmation_depth,
39654008 ) {
39664009 ret = Err ( ( ) ) ;
39674010 }
@@ -4922,20 +4965,33 @@ impl<Signer: EcdsaChannelSigner> ChannelMonitorImpl<Signer> {
49224965 }
49234966 }
49244967
4925- // A splice/dual-funded RBF transaction has confirmed. We can't promote the
4926- // `FundingScope` scope until we see the
4968+ // A splice/dual-funded RBF transaction has confirmed. If it's not zero conf, we can't
4969+ // promote the `FundingScope` scope until we see the
49274970 // [`ChannelMonitorUpdateStep::RenegotiatedFundingLocked`] for it, but we track the txid
49284971 // so we know which holder commitment transaction we may need to broadcast.
4929- if let Some ( alternative_funding) = self . pending_funding . iter ( )
4972+ if let Some ( ( confirmed_funding, is_funding_locked) ) = self
4973+ . pending_funding
4974+ . iter ( )
49304975 . find ( |funding| funding. funding_txid ( ) == txid)
4976+ . map ( |funding| ( funding, false ) )
4977+ . or_else ( || {
4978+ ( self . funding . funding_txid ( ) == txid) . then ( || & self . funding )
4979+ . filter ( |_| self . wait_for_0conf_funding_reorg_safety )
4980+ . map ( |funding| ( funding, true ) )
4981+ } )
49314982 {
4983+ debug_assert ! ( self . alternative_funding_confirmed. is_none( ) ) ;
4984+ debug_assert ! (
4985+ !self . onchain_events_awaiting_threshold_conf. iter( )
4986+ . any( |e| matches!( e. event, OnchainEvent :: AlternativeFundingConfirmation { } ) )
4987+ ) ;
49324988 debug_assert ! ( self . funding_spend_confirmed. is_none( ) ) ;
49334989 debug_assert ! (
49344990 !self . onchain_events_awaiting_threshold_conf. iter( )
49354991 . any( |e| matches!( e. event, OnchainEvent :: FundingSpendConfirmation { .. } ) )
49364992 ) ;
49374993
4938- let ( desc, msg) = if alternative_funding . channel_parameters . splice_parent_funding_txid . is_some ( ) {
4994+ let ( desc, msg) = if confirmed_funding . is_splice ( ) {
49394995 debug_assert ! ( tx. input. iter( ) . any( |input| {
49404996 let funding_outpoint = self . funding. funding_outpoint( ) . into_bitcoin_outpoint( ) ;
49414997 input. previous_output == funding_outpoint
@@ -4944,43 +5000,77 @@ impl<Signer: EcdsaChannelSigner> ChannelMonitorImpl<Signer> {
49445000 } else {
49455001 ( "RBF" , "channel_ready" )
49465002 } ;
4947- let action = if self . no_further_updates_allowed ( ) {
4948- if self . holder_tx_signed {
4949- ", broadcasting post-splice holder commitment transaction" . to_string ( )
4950- } else {
4951- "" . to_string ( )
4952- }
4953- } else {
5003+ let action = if self . holder_tx_signed {
5004+ ", broadcasting post-splice holder commitment transaction" . to_string ( )
5005+ } else if !self . no_further_updates_allowed ( ) && !is_funding_locked {
49545006 format ! ( ", waiting for `{msg}` exchange" )
5007+ } else {
5008+ "" . to_string ( )
49555009 } ;
49565010 log_info ! ( logger, "{desc} for channel {} confirmed with txid {txid}{action}" , self . channel_id( ) ) ;
49575011
4958- self . alternative_funding_confirmed = Some ( ( txid, height) ) ;
5012+ if is_funding_locked {
5013+ // We can only have already processed the
5014+ // [`ChannelMonitorUpdateStep::RenegotiatedFundingLocked`] if we're zero conf,
5015+ // but we still track the alternative funding transactions until we're no longer
5016+ // under reorg risk.
5017+ debug_assert ! ( self . wait_for_0conf_funding_reorg_safety) ;
49595018
4960- if self . no_further_updates_allowed ( ) {
4961- // We can no longer rely on
4962- // [`ChannelMonitorUpdateStep::RenegotiatedFundingLocked`] to promote the
4963- // scope, do so when the funding is no longer under reorg risk.
4964- self . onchain_events_awaiting_threshold_conf . push ( OnchainEventEntry {
5019+ let event_entry = OnchainEventEntry {
49655020 txid,
49665021 transaction : Some ( ( * tx) . clone ( ) ) ,
49675022 height,
49685023 block_hash : Some ( block_hash) ,
4969- event : OnchainEvent :: AlternativeFundingConfirmation { } ,
4970- } ) ;
5024+ event : OnchainEvent :: ZeroConfFundingReorgSafety { } ,
5025+ } ;
5026+
5027+ if let Some ( event) = self . onchain_events_awaiting_threshold_conf
5028+ . iter_mut ( )
5029+ . find ( |e| matches ! ( e. event, OnchainEvent :: ZeroConfFundingReorgSafety { } ) )
5030+ {
5031+ // Since channels may chain multiple zero conf splices, we only want to track
5032+ // one event overall.
5033+ * event = event_entry;
5034+ } else {
5035+ self . onchain_events_awaiting_threshold_conf . push ( event_entry) ;
5036+ }
5037+ } else {
5038+ debug_assert ! (
5039+ !self . onchain_events_awaiting_threshold_conf. iter( )
5040+ . any( |e| matches!( e. event, OnchainEvent :: ZeroConfFundingReorgSafety { } ) )
5041+ ) ;
5042+
5043+ self . alternative_funding_confirmed = Some ( ( txid, height) ) ;
5044+
5045+ if self . no_further_updates_allowed ( ) {
5046+ // We can no longer rely on
5047+ // [`ChannelMonitorUpdateStep::RenegotiatedFundingLocked`] to promote the
5048+ // scope, do so when the funding is no longer under reorg risk.
5049+ self . onchain_events_awaiting_threshold_conf . push ( OnchainEventEntry {
5050+ txid,
5051+ transaction : Some ( ( * tx) . clone ( ) ) ,
5052+ height,
5053+ block_hash : Some ( block_hash) ,
5054+ event : OnchainEvent :: AlternativeFundingConfirmation { } ,
5055+ } ) ;
5056+ }
49715057 }
49725058
4973- if self . holder_tx_signed {
5059+ // If we've previously broadcast a holder commitment, queue claims for the
5060+ // alternative holder commitment now that it is the only one that can confirm (until
5061+ // we see a reorg of its funding transaction). We also choose to broadcast if our
5062+ // intended funding transaction was locked with zero confirmations, but another
5063+ // funding transaction has now confirmed, since commitment updates were only made to
5064+ // the locked funding.
5065+ if self . holder_tx_signed ||
5066+ ( self . wait_for_0conf_funding_reorg_safety && !is_funding_locked)
5067+ {
49745068 // Cancel any previous claims that are no longer valid as they stemmed from a
49755069 // different funding transaction.
49765070 let alternative_holder_commitment_txid =
4977- alternative_funding . current_holder_commitment_tx . trust ( ) . txid ( ) ;
5071+ confirmed_funding . current_holder_commitment_tx . trust ( ) . txid ( ) ;
49785072 self . cancel_prev_commitment_claims ( & logger, & alternative_holder_commitment_txid) ;
49795073
4980- // Queue claims for the alternative holder commitment since it is the only one
4981- // that can currently confirm so far (until we see a reorg of its funding
4982- // transaction).
4983- //
49845074 // It's possible we process a counterparty commitment within this same block
49855075 // that would invalidate our holder commitment. If we were to broadcast our
49865076 // holder commitment now, we wouldn't be able to cancel it via our usual
@@ -5207,6 +5297,21 @@ impl<Signer: EcdsaChannelSigner> ChannelMonitorImpl<Signer> {
52075297 log_error ! ( logger, "Missing scope for alternative funding confirmation with txid {}" , entry. txid) ;
52085298 }
52095299 } ,
5300+ OnchainEvent :: ZeroConfFundingReorgSafety { } => {
5301+ if self . wait_for_0conf_funding_reorg_safety {
5302+ debug_assert_eq ! ( self . funding. funding_txid( ) , entry. txid) ;
5303+ debug_assert ! ( self . alternative_funding_confirmed. is_none( ) ) ;
5304+ self
5305+ . pending_funding
5306+ . drain ( ..)
5307+ . for_each ( |funding| {
5308+ self . outputs_to_watch . remove ( & funding. funding_txid ( ) ) ;
5309+ } ) ;
5310+ self . wait_for_0conf_funding_reorg_safety = false ;
5311+ } else {
5312+ debug_assert ! ( false , "These events can only be generated when wait_for_0conf_funding_reorg_safety is set" ) ;
5313+ }
5314+ } ,
52105315 }
52115316 }
52125317
@@ -6071,6 +6176,7 @@ impl<'a, 'b, ES: EntropySource, SP: SignerProvider> ReadableArgs<(&'a ES, &'b SP
60716176 let mut channel_parameters = None ;
60726177 let mut pending_funding = None ;
60736178 let mut alternative_funding_confirmed = None ;
6179+ let mut wait_for_0conf_funding_reorg_safety: Option < ( ) > = None ;
60746180 read_tlv_fields ! ( reader, {
60756181 ( 1 , funding_spend_confirmed, option) ,
60766182 ( 3 , htlcs_resolved_on_chain, optional_vec) ,
@@ -6090,6 +6196,7 @@ impl<'a, 'b, ES: EntropySource, SP: SignerProvider> ReadableArgs<(&'a ES, &'b SP
60906196 ( 31 , channel_parameters, ( option: ReadableArgs , None ) ) ,
60916197 ( 32 , pending_funding, optional_vec) ,
60926198 ( 34 , alternative_funding_confirmed, option) ,
6199+ ( 36 , wait_for_0conf_funding_reorg_safety, option) ,
60936200 } ) ;
60946201 if let Some ( payment_preimages_with_info) = payment_preimages_with_info {
60956202 if payment_preimages_with_info. len ( ) != payment_preimages. len ( ) {
@@ -6261,6 +6368,7 @@ impl<'a, 'b, ES: EntropySource, SP: SignerProvider> ReadableArgs<(&'a ES, &'b SP
62616368 prev_holder_htlc_data,
62626369
62636370 alternative_funding_confirmed,
6371+ wait_for_0conf_funding_reorg_safety : wait_for_0conf_funding_reorg_safety. is_some ( ) ,
62646372 } ) ) )
62656373 }
62666374}
0 commit comments