@@ -534,7 +534,9 @@ enum OnchainEvent {
534
534
} ,
535
535
/// An output waiting on [`ANTI_REORG_DELAY`] confirmations before we hand the user the
536
536
/// [`SpendableOutputDescriptor`].
537
- MaturingOutput { descriptor : SpendableOutputDescriptor } ,
537
+ MaturingOutput {
538
+ descriptor : SpendableOutputDescriptor ,
539
+ } ,
538
540
/// A spend of the funding output, either a commitment transaction or a cooperative closing
539
541
/// transaction.
540
542
FundingSpendConfirmation {
@@ -578,6 +580,16 @@ enum OnchainEvent {
578
580
// considered locked.
579
581
confirmation_depth : u32 ,
580
582
} ,
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 { } ,
581
593
}
582
594
583
595
impl Writeable for OnchainEventEntry {
@@ -629,6 +641,7 @@ impl_writeable_tlv_based_enum_upgradable!(OnchainEvent,
629
641
( 0 , on_local_output_csv, option) ,
630
642
( 1 , commitment_tx_to_counterparty_output, option) ,
631
643
} ,
644
+ ( 4 , ZeroConfFundingReorgSafety ) => { } ,
632
645
( 5 , HTLCSpendConfirmation ) => {
633
646
( 0 , commitment_tx_output_idx, required) ,
634
647
( 2 , preimage, option) ,
@@ -1299,6 +1312,11 @@ pub(crate) struct ChannelMonitorImpl<Signer: EcdsaChannelSigner> {
1299
1312
// commitment transactions, their ordering with respect to each other must remain the same.
1300
1313
current_holder_htlc_data : CommitmentHTLCData ,
1301
1314
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 ,
1302
1320
}
1303
1321
1304
1322
// 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> {
1556
1574
_ => self . pending_monitor_events . clone ( ) ,
1557
1575
} ;
1558
1576
1577
+ let wait_for_0conf_funding_reorg_safety = self . wait_for_0conf_funding_reorg_safety . then ( || ( ) ) ;
1578
+
1559
1579
write_tlv_fields ! ( writer, {
1560
1580
( 1 , self . funding_spend_confirmed, option) ,
1561
1581
( 3 , self . htlcs_resolved_on_chain, required_vec) ,
@@ -1574,6 +1594,7 @@ impl<Signer: EcdsaChannelSigner> Writeable for ChannelMonitorImpl<Signer> {
1574
1594
( 29 , self . initial_counterparty_commitment_tx, option) ,
1575
1595
( 31 , self . funding. channel_parameters, required) ,
1576
1596
( 32 , self . pending_funding, optional_vec) ,
1597
+ ( 34 , wait_for_0conf_funding_reorg_safety, option) ,
1577
1598
} ) ;
1578
1599
1579
1600
Ok ( ( ) )
@@ -1799,6 +1820,8 @@ impl<Signer: EcdsaChannelSigner> ChannelMonitor<Signer> {
1799
1820
// There are never any HTLCs in the initial commitment transaction
1800
1821
current_holder_htlc_data : CommitmentHTLCData :: new ( ) ,
1801
1822
prev_holder_htlc_data : None ,
1823
+
1824
+ wait_for_0conf_funding_reorg_safety : false ,
1802
1825
} )
1803
1826
}
1804
1827
@@ -3835,23 +3858,29 @@ impl<Signer: EcdsaChannelSigner> ChannelMonitorImpl<Signer> {
3835
3858
Ok ( ( ) )
3836
3859
}
3837
3860
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 < ( ) , ( ) > {
3839
3864
let new_funding = self
3840
3865
. pending_funding
3841
3866
. 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) ;
3844
3868
if new_funding. is_none ( ) {
3845
3869
return Err ( ( ) ) ;
3846
3870
}
3847
- let mut new_funding = new_funding. unwrap ( ) ;
3871
+ let ( new_funding, confirmation_depth ) = new_funding. unwrap ( ) ;
3848
3872
3849
- mem:: swap ( & mut self . funding , & mut new_funding) ;
3873
+ mem:: swap ( & mut self . funding , new_funding) ;
3850
3874
self . onchain_tx_handler . update_after_renegotiated_funding_locked (
3851
3875
self . funding . current_holder_commitment_tx . clone ( ) ,
3852
3876
self . funding . prev_holder_commitment_tx . clone ( ) ,
3853
3877
) ;
3854
3878
3879
+ if from_monitor_update && * confirmation_depth == 0 {
3880
+ self . wait_for_0conf_funding_reorg_safety = true ;
3881
+ return Ok ( ( ) ) ;
3882
+ }
3883
+
3855
3884
// The swap above places the previous `FundingScope` into `pending_funding`.
3856
3885
for ( funding, _) in self . pending_funding . drain ( ..) {
3857
3886
self . outputs_to_watch . remove ( & funding. funding_txid ( ) ) ;
@@ -3982,7 +4011,7 @@ impl<Signer: EcdsaChannelSigner> ChannelMonitorImpl<Signer> {
3982
4011
} ,
3983
4012
ChannelMonitorUpdateStep :: RenegotiatedFundingLocked { funding_txid } => {
3984
4013
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 ) {
3986
4015
log_error ! ( logger, "Unknown funding with txid {} became locked" , funding_txid) ;
3987
4016
ret = Err ( ( ) ) ;
3988
4017
}
@@ -4940,6 +4969,20 @@ impl<Signer: EcdsaChannelSigner> ChannelMonitorImpl<Signer> {
4940
4969
}
4941
4970
}
4942
4971
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
+
4943
4986
// A splice transaction has confirmed. We can't promote the splice's scope until we see
4944
4987
// the corresponding monitor update for it, but we track the txid so we know which
4945
4988
// holder commitment transaction we may need to broadcast.
@@ -5212,19 +5255,35 @@ impl<Signer: EcdsaChannelSigner> ChannelMonitorImpl<Signer> {
5212
5255
} ,
5213
5256
OnchainEvent :: AlternativeFundingConfirmation { .. } => {
5214
5257
// 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 {
5219
5264
let funding_txid = entry. transaction
5220
5265
. expect ( "Transactions are always present for AlternativeFundingConfirmation entries" )
5221
5266
. compute_txid ( ) ;
5222
5267
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 ) {
5224
5269
log_error ! ( logger, "Missing scope for alternative funding confirmation with txid {}" , entry. txid) ;
5225
5270
}
5226
5271
}
5227
5272
} ,
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
+ } ,
5228
5287
}
5229
5288
}
5230
5289
@@ -6073,6 +6132,7 @@ impl<'a, 'b, ES: EntropySource, SP: SignerProvider> ReadableArgs<(&'a ES, &'b SP
6073
6132
let mut first_negotiated_funding_txo = RequiredWrapper ( None ) ;
6074
6133
let mut channel_parameters = None ;
6075
6134
let mut pending_funding = None ;
6135
+ let mut wait_for_0conf_funding_reorg_safety: Option < ( ) > = None ;
6076
6136
read_tlv_fields ! ( reader, {
6077
6137
( 1 , funding_spend_confirmed, option) ,
6078
6138
( 3 , htlcs_resolved_on_chain, optional_vec) ,
@@ -6091,6 +6151,7 @@ impl<'a, 'b, ES: EntropySource, SP: SignerProvider> ReadableArgs<(&'a ES, &'b SP
6091
6151
( 29 , initial_counterparty_commitment_tx, option) ,
6092
6152
( 31 , channel_parameters, ( option: ReadableArgs , None ) ) ,
6093
6153
( 32 , pending_funding, optional_vec) ,
6154
+ ( 34 , wait_for_0conf_funding_reorg_safety, option) ,
6094
6155
} ) ;
6095
6156
if let Some ( payment_preimages_with_info) = payment_preimages_with_info {
6096
6157
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
6260
6321
6261
6322
current_holder_htlc_data,
6262
6323
prev_holder_htlc_data,
6324
+
6325
+ wait_for_0conf_funding_reorg_safety : wait_for_0conf_funding_reorg_safety. is_some ( ) ,
6263
6326
} ) ) )
6264
6327
}
6265
6328
}
0 commit comments