@@ -531,7 +531,9 @@ enum OnchainEvent {
531
531
} ,
532
532
/// An output waiting on [`ANTI_REORG_DELAY`] confirmations before we hand the user the
533
533
/// [`SpendableOutputDescriptor`].
534
- MaturingOutput { descriptor : SpendableOutputDescriptor } ,
534
+ MaturingOutput {
535
+ descriptor : SpendableOutputDescriptor ,
536
+ } ,
535
537
/// A spend of the funding output, either a commitment transaction or a cooperative closing
536
538
/// transaction.
537
539
FundingSpendConfirmation {
@@ -572,6 +574,17 @@ enum OnchainEvent {
572
574
/// once [`ChannelMonitor::no_further_updates_allowed`] returns true. We promote the
573
575
/// `FundingScope` once the funding transaction is irrevocably confirmed.
574
576
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 { } ,
575
588
}
576
589
577
590
impl Writeable for OnchainEventEntry {
@@ -621,6 +634,7 @@ impl_writeable_tlv_based_enum_upgradable!(OnchainEvent,
621
634
( 0 , on_local_output_csv, option) ,
622
635
( 1 , commitment_tx_to_counterparty_output, option) ,
623
636
} ,
637
+ ( 4 , ZeroConfFundingReorgSafety ) => { } ,
624
638
( 5 , HTLCSpendConfirmation ) => {
625
639
( 0 , commitment_tx_output_idx, required) ,
626
640
( 2 , preimage, option) ,
@@ -684,6 +698,7 @@ pub(crate) enum ChannelMonitorUpdateStep {
684
698
channel_parameters : ChannelTransactionParameters ,
685
699
holder_commitment_tx : HolderCommitmentTransaction ,
686
700
counterparty_commitment_tx : CommitmentTransaction ,
701
+ confirmation_depth : u32 ,
687
702
} ,
688
703
RenegotiatedFundingLocked {
689
704
funding_txid : Txid ,
@@ -751,6 +766,7 @@ impl_writeable_tlv_based_enum_upgradable!(ChannelMonitorUpdateStep,
751
766
( 1 , channel_parameters, ( required: ReadableArgs , None ) ) ,
752
767
( 3 , holder_commitment_tx, required) ,
753
768
( 5 , counterparty_commitment_tx, required) ,
769
+ ( 7 , confirmation_depth, required) ,
754
770
} ,
755
771
( 12 , RenegotiatedFundingLocked ) => {
756
772
( 1 , funding_txid, required) ,
@@ -1293,6 +1309,11 @@ pub(crate) struct ChannelMonitorImpl<Signer: EcdsaChannelSigner> {
1293
1309
prev_holder_htlc_data : Option < CommitmentHTLCData > ,
1294
1310
1295
1311
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 ,
1296
1317
}
1297
1318
1298
1319
// 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> {
1550
1571
_ => self . pending_monitor_events . clone ( ) ,
1551
1572
} ;
1552
1573
1574
+ let wait_for_0conf_funding_reorg_safety = self . wait_for_0conf_funding_reorg_safety . then ( || ( ) ) ;
1575
+
1553
1576
write_tlv_fields ! ( writer, {
1554
1577
( 1 , self . funding_spend_confirmed, option) ,
1555
1578
( 3 , self . htlcs_resolved_on_chain, required_vec) ,
@@ -1569,6 +1592,7 @@ impl<Signer: EcdsaChannelSigner> Writeable for ChannelMonitorImpl<Signer> {
1569
1592
( 31 , self . funding. channel_parameters, required) ,
1570
1593
( 32 , self . pending_funding, optional_vec) ,
1571
1594
( 34 , self . alternative_funding_confirmed, option) ,
1595
+ ( 36 , wait_for_0conf_funding_reorg_safety, option) ,
1572
1596
} ) ;
1573
1597
1574
1598
Ok ( ( ) )
@@ -1796,6 +1820,7 @@ impl<Signer: EcdsaChannelSigner> ChannelMonitor<Signer> {
1796
1820
prev_holder_htlc_data : None ,
1797
1821
1798
1822
alternative_funding_confirmed : None ,
1823
+ wait_for_0conf_funding_reorg_safety : false ,
1799
1824
} )
1800
1825
}
1801
1826
@@ -3417,6 +3442,7 @@ impl<Signer: EcdsaChannelSigner> ChannelMonitorImpl<Signer> {
3417
3442
self . update_holder_commitment_data ( vec ! [ holder_commitment_tx] , htlc_data, claimed_htlcs)
3418
3443
}
3419
3444
3445
+ // TODO(splicing): Consider `wait_for_0conf_funding_reorg_safety`.
3420
3446
fn verify_matching_commitment_transactions <
3421
3447
' a ,
3422
3448
I : ExactSizeIterator < Item = & ' a CommitmentTransaction > ,
@@ -3704,7 +3730,7 @@ impl<Signer: EcdsaChannelSigner> ChannelMonitorImpl<Signer> {
3704
3730
& mut self , logger : & WithChannelMonitor < L > ,
3705
3731
channel_parameters : & ChannelTransactionParameters ,
3706
3732
alternative_holder_commitment_tx : & HolderCommitmentTransaction ,
3707
- alternative_counterparty_commitment_tx : & CommitmentTransaction ,
3733
+ alternative_counterparty_commitment_tx : & CommitmentTransaction , confirmation_depth : u32 ,
3708
3734
) -> Result < ( ) , ( ) >
3709
3735
where
3710
3736
L :: Target : Logger ,
@@ -3793,14 +3819,16 @@ impl<Signer: EcdsaChannelSigner> ChannelMonitorImpl<Signer> {
3793
3819
if let Some ( parent_funding_txid) = channel_parameters. splice_parent_funding_txid . as_ref ( ) {
3794
3820
// Only one splice can be negotiated at a time after we've exchanged `channel_ready`
3795
3821
// (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 {
3797
3823
log_error ! (
3798
3824
logger,
3799
3825
"Negotiated splice while channel is pending channel_ready/splice_locked"
3800
3826
) ;
3801
3827
return Err ( ( ) ) ;
3802
3828
}
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
+ {
3804
3832
log_error ! (
3805
3833
logger,
3806
3834
"Negotiated splice that does not spend currently locked funding transaction"
@@ -3820,6 +3848,11 @@ impl<Signer: EcdsaChannelSigner> ChannelMonitorImpl<Signer> {
3820
3848
) ;
3821
3849
self . pending_funding . push ( alternative_funding) ;
3822
3850
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
+
3823
3856
Ok ( ( ) )
3824
3857
}
3825
3858
@@ -3831,20 +3864,28 @@ impl<Signer: EcdsaChannelSigner> ChannelMonitorImpl<Signer> {
3831
3864
if new_funding. is_none ( ) {
3832
3865
return Err ( ( ) ) ;
3833
3866
}
3834
- let mut new_funding = new_funding. unwrap ( ) ;
3867
+ let new_funding = new_funding. unwrap ( ) ;
3835
3868
3836
- mem:: swap ( & mut self . funding , & mut new_funding) ;
3869
+ mem:: swap ( & mut self . funding , new_funding) ;
3837
3870
self . onchain_tx_handler . update_after_renegotiated_funding_locked (
3838
3871
self . funding . current_holder_commitment_tx . clone ( ) ,
3839
3872
self . funding . prev_holder_commitment_tx . clone ( ) ,
3840
3873
) ;
3841
3874
3875
+ if self . wait_for_0conf_funding_reorg_safety {
3876
+ return Ok ( ( ) ) ;
3877
+ }
3878
+
3842
3879
// The swap above places the previous `FundingScope` into `pending_funding`.
3843
3880
for funding in self . pending_funding . drain ( ..) {
3844
3881
self . outputs_to_watch . remove ( & funding. funding_txid ( ) ) ;
3845
3882
}
3846
3883
self . alternative_funding_confirmed . take ( ) ;
3847
3884
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
+
3848
3889
Ok ( ( ) )
3849
3890
}
3850
3891
@@ -3957,11 +3998,13 @@ impl<Signer: EcdsaChannelSigner> ChannelMonitorImpl<Signer> {
3957
3998
} ,
3958
3999
ChannelMonitorUpdateStep :: RenegotiatedFunding {
3959
4000
channel_parameters, holder_commitment_tx, counterparty_commitment_tx,
4001
+ confirmation_depth,
3960
4002
} => {
3961
4003
log_trace ! ( logger, "Updating ChannelMonitor with alternative holder and counterparty commitment transactions for funding txid {}" ,
3962
4004
channel_parameters. funding_outpoint. unwrap( ) . txid) ;
3963
4005
if let Err ( _) = self . renegotiated_funding (
3964
4006
logger, channel_parameters, holder_commitment_tx, counterparty_commitment_tx,
4007
+ * confirmation_depth,
3965
4008
) {
3966
4009
ret = Err ( ( ) ) ;
3967
4010
}
@@ -4922,20 +4965,33 @@ impl<Signer: EcdsaChannelSigner> ChannelMonitorImpl<Signer> {
4922
4965
}
4923
4966
}
4924
4967
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
4927
4970
// [`ChannelMonitorUpdateStep::RenegotiatedFundingLocked`] for it, but we track the txid
4928
4971
// 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 ( )
4930
4975
. 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
+ } )
4931
4982
{
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
+ ) ;
4932
4988
debug_assert ! ( self . funding_spend_confirmed. is_none( ) ) ;
4933
4989
debug_assert ! (
4934
4990
!self . onchain_events_awaiting_threshold_conf. iter( )
4935
4991
. any( |e| matches!( e. event, OnchainEvent :: FundingSpendConfirmation { .. } ) )
4936
4992
) ;
4937
4993
4938
- let ( desc, msg) = if alternative_funding . channel_parameters . splice_parent_funding_txid . is_some ( ) {
4994
+ let ( desc, msg) = if confirmed_funding . is_splice ( ) {
4939
4995
debug_assert ! ( tx. input. iter( ) . any( |input| {
4940
4996
let funding_outpoint = self . funding. funding_outpoint( ) . into_bitcoin_outpoint( ) ;
4941
4997
input. previous_output == funding_outpoint
@@ -4944,43 +5000,77 @@ impl<Signer: EcdsaChannelSigner> ChannelMonitorImpl<Signer> {
4944
5000
} else {
4945
5001
( "RBF" , "channel_ready" )
4946
5002
} ;
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 {
4954
5006
format ! ( ", waiting for `{msg}` exchange" )
5007
+ } else {
5008
+ "" . to_string ( )
4955
5009
} ;
4956
5010
log_info ! ( logger, "{desc} for channel {} confirmed with txid {txid}{action}" , self . channel_id( ) ) ;
4957
5011
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) ;
4959
5018
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 {
4965
5020
txid,
4966
5021
transaction : Some ( ( * tx) . clone ( ) ) ,
4967
5022
height,
4968
5023
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
+ }
4971
5057
}
4972
5058
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
+ {
4974
5068
// Cancel any previous claims that are no longer valid as they stemmed from a
4975
5069
// different funding transaction.
4976
5070
let alternative_holder_commitment_txid =
4977
- alternative_funding . current_holder_commitment_tx . trust ( ) . txid ( ) ;
5071
+ confirmed_funding . current_holder_commitment_tx . trust ( ) . txid ( ) ;
4978
5072
self . cancel_prev_commitment_claims ( & logger, & alternative_holder_commitment_txid) ;
4979
5073
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
- //
4984
5074
// It's possible we process a counterparty commitment within this same block
4985
5075
// that would invalidate our holder commitment. If we were to broadcast our
4986
5076
// holder commitment now, we wouldn't be able to cancel it via our usual
@@ -5207,6 +5297,21 @@ impl<Signer: EcdsaChannelSigner> ChannelMonitorImpl<Signer> {
5207
5297
log_error ! ( logger, "Missing scope for alternative funding confirmation with txid {}" , entry. txid) ;
5208
5298
}
5209
5299
} ,
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
+ } ,
5210
5315
}
5211
5316
}
5212
5317
@@ -6071,6 +6176,7 @@ impl<'a, 'b, ES: EntropySource, SP: SignerProvider> ReadableArgs<(&'a ES, &'b SP
6071
6176
let mut channel_parameters = None ;
6072
6177
let mut pending_funding = None ;
6073
6178
let mut alternative_funding_confirmed = None ;
6179
+ let mut wait_for_0conf_funding_reorg_safety: Option < ( ) > = None ;
6074
6180
read_tlv_fields ! ( reader, {
6075
6181
( 1 , funding_spend_confirmed, option) ,
6076
6182
( 3 , htlcs_resolved_on_chain, optional_vec) ,
@@ -6090,6 +6196,7 @@ impl<'a, 'b, ES: EntropySource, SP: SignerProvider> ReadableArgs<(&'a ES, &'b SP
6090
6196
( 31 , channel_parameters, ( option: ReadableArgs , None ) ) ,
6091
6197
( 32 , pending_funding, optional_vec) ,
6092
6198
( 34 , alternative_funding_confirmed, option) ,
6199
+ ( 36 , wait_for_0conf_funding_reorg_safety, option) ,
6093
6200
} ) ;
6094
6201
if let Some ( payment_preimages_with_info) = payment_preimages_with_info {
6095
6202
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
6261
6368
prev_holder_htlc_data,
6262
6369
6263
6370
alternative_funding_confirmed,
6371
+ wait_for_0conf_funding_reorg_safety : wait_for_0conf_funding_reorg_safety. is_some ( ) ,
6264
6372
} ) ) )
6265
6373
}
6266
6374
}
0 commit comments