@@ -565,6 +565,13 @@ enum OnchainEvent {
565
565
/// output (and generate a SpendableOutput event).
566
566
on_to_local_output_csv : Option < u16 > ,
567
567
} ,
568
+ /// An alternative funding transaction (due to a splice/RBF) has confirmed but can no longer be
569
+ /// locked not as the monitor is no longer allowing updates. Note that we wait to promote the
570
+ /// corresponding `FundingScope` until we see a
571
+ /// [`ChannelMonitorUpdateStep::RenegotiatedFundingLocked`], but this event is only applicable
572
+ /// once [`ChannelMonitor::no_further_updates_allowed`] returns true. We promote the
573
+ /// `FundingScope` once the funding transaction is irrevocably confirmed.
574
+ AlternativeFundingConfirmation { } ,
568
575
}
569
576
570
577
impl Writeable for OnchainEventEntry {
@@ -609,6 +616,7 @@ impl_writeable_tlv_based_enum_upgradable!(OnchainEvent,
609
616
( 1 , MaturingOutput ) => {
610
617
( 0 , descriptor, required) ,
611
618
} ,
619
+ ( 2 , AlternativeFundingConfirmation ) => { } ,
612
620
( 3 , FundingSpendConfirmation ) => {
613
621
( 0 , on_local_output_csv, option) ,
614
622
( 1 , commitment_tx_to_counterparty_output, option) ,
@@ -618,7 +626,6 @@ impl_writeable_tlv_based_enum_upgradable!(OnchainEvent,
618
626
( 2 , preimage, option) ,
619
627
( 4 , on_to_local_output_csv, option) ,
620
628
} ,
621
-
622
629
) ;
623
630
624
631
#[ derive( Clone , Debug , PartialEq , Eq ) ]
@@ -1280,6 +1287,10 @@ pub(crate) struct ChannelMonitorImpl<Signer: EcdsaChannelSigner> {
1280
1287
// commitment transactions, their ordering with respect to each other must remain the same.
1281
1288
current_holder_htlc_data : CommitmentHTLCData ,
1282
1289
prev_holder_htlc_data : Option < CommitmentHTLCData > ,
1290
+
1291
+ // Tracks the txid and confirmation height of a renegotiated funding transaction upon
1292
+ // confirmation. Used to determine which commitment we should broadcast when necessary.
1293
+ alternative_funding_confirmed : Option < ( Txid , u32 ) > ,
1283
1294
}
1284
1295
1285
1296
// Macro helper to access holder commitment HTLC data (including both non-dust and dust) while
@@ -1555,6 +1566,7 @@ impl<Signer: EcdsaChannelSigner> Writeable for ChannelMonitorImpl<Signer> {
1555
1566
( 29 , self . initial_counterparty_commitment_tx, option) ,
1556
1567
( 31 , self . funding. channel_parameters, required) ,
1557
1568
( 32 , self . pending_funding, optional_vec) ,
1569
+ ( 34 , self . alternative_funding_confirmed, option) ,
1558
1570
} ) ;
1559
1571
1560
1572
Ok ( ( ) )
@@ -1780,6 +1792,8 @@ impl<Signer: EcdsaChannelSigner> ChannelMonitor<Signer> {
1780
1792
// There are never any HTLCs in the initial commitment transaction
1781
1793
current_holder_htlc_data : CommitmentHTLCData :: new ( ) ,
1782
1794
prev_holder_htlc_data : None ,
1795
+
1796
+ alternative_funding_confirmed : None ,
1783
1797
} )
1784
1798
}
1785
1799
@@ -3815,6 +3829,9 @@ impl<Signer: EcdsaChannelSigner> ChannelMonitorImpl<Signer> {
3815
3829
for funding in self . pending_funding . drain ( ..) {
3816
3830
self . outputs_to_watch . remove ( & funding. funding_txid ( ) ) ;
3817
3831
}
3832
+ if let Some ( ( alternative_funding_txid, _) ) = self . alternative_funding_confirmed . take ( ) {
3833
+ debug_assert_eq ! ( alternative_funding_txid, new_funding_txid) ;
3834
+ }
3818
3835
3819
3836
Ok ( ( ) )
3820
3837
}
@@ -4873,6 +4890,57 @@ impl<Signer: EcdsaChannelSigner> ChannelMonitorImpl<Signer> {
4873
4890
}
4874
4891
}
4875
4892
4893
+ // A splice/dual-funded RBF transaction has confirmed. We can't promote the
4894
+ // `FundingScope` scope until we see the
4895
+ // [`ChannelMonitorUpdateStep::RenegotiatedFundingLocked`] for it, but we track the txid
4896
+ // so we know which holder commitment transaction we may need to broadcast.
4897
+ if let Some ( alternative_funding) = self . pending_funding . iter ( )
4898
+ . find ( |funding| funding. funding_txid ( ) == txid)
4899
+ {
4900
+ debug_assert ! ( self . funding_spend_confirmed. is_none( ) ) ;
4901
+ debug_assert ! (
4902
+ !self . onchain_events_awaiting_threshold_conf. iter( )
4903
+ . any( |e| matches!( e. event, OnchainEvent :: FundingSpendConfirmation { .. } ) )
4904
+ ) ;
4905
+
4906
+ let ( desc, msg) = if alternative_funding. channel_parameters . splice_parent_funding_txid . is_some ( ) {
4907
+ debug_assert ! ( tx. input. iter( ) . any( |input| {
4908
+ let funding_outpoint = self . funding. funding_outpoint( ) . into_bitcoin_outpoint( ) ;
4909
+ input. previous_output == funding_outpoint
4910
+ } ) ) ;
4911
+ ( "Splice" , "splice_locked" )
4912
+ } else {
4913
+ ( "RBF" , "channel_ready" )
4914
+ } ;
4915
+ let action = if self . no_further_updates_allowed ( ) {
4916
+ if self . holder_tx_signed {
4917
+ ", broadcasting post-splice holder commitment transaction" . to_string ( )
4918
+ } else {
4919
+ "" . to_string ( )
4920
+ }
4921
+ } else {
4922
+ format ! ( ", waiting for `{msg}` exchange" )
4923
+ } ;
4924
+ log_info ! ( logger, "{desc} for channel {} confirmed with txid {txid}{action}" , self . channel_id( ) ) ;
4925
+
4926
+ self . alternative_funding_confirmed = Some ( ( txid, height) ) ;
4927
+
4928
+ if self . no_further_updates_allowed ( ) {
4929
+ // We can no longer rely on
4930
+ // [`ChannelMonitorUpdateStep::RenegotiatedFundingLocked`] to promote the
4931
+ // scope, do so when the funding is no longer under reorg risk.
4932
+ self . onchain_events_awaiting_threshold_conf . push ( OnchainEventEntry {
4933
+ txid,
4934
+ transaction : Some ( ( * tx) . clone ( ) ) ,
4935
+ height,
4936
+ block_hash : Some ( block_hash) ,
4937
+ event : OnchainEvent :: AlternativeFundingConfirmation { } ,
4938
+ } ) ;
4939
+ }
4940
+
4941
+ continue ' tx_iter;
4942
+ }
4943
+
4876
4944
if tx. input . len ( ) == 1 {
4877
4945
// Assuming our keys were not leaked (in which case we're screwed no matter what),
4878
4946
// commitment transactions and HTLC transactions will all only ever have one input
@@ -5004,7 +5072,7 @@ impl<Signer: EcdsaChannelSigner> ChannelMonitorImpl<Signer> {
5004
5072
let unmatured_htlcs: Vec < _ > = self . onchain_events_awaiting_threshold_conf
5005
5073
. iter ( )
5006
5074
. filter_map ( |entry| match & entry. event {
5007
- OnchainEvent :: HTLCUpdate { source, .. } => Some ( source) ,
5075
+ OnchainEvent :: HTLCUpdate { source, .. } => Some ( source. clone ( ) ) ,
5008
5076
_ => None ,
5009
5077
} )
5010
5078
. collect ( ) ;
@@ -5019,7 +5087,7 @@ impl<Signer: EcdsaChannelSigner> ChannelMonitorImpl<Signer> {
5019
5087
#[ cfg( debug_assertions) ]
5020
5088
{
5021
5089
debug_assert ! (
5022
- !unmatured_htlcs. contains( && source) ,
5090
+ !unmatured_htlcs. contains( & source) ,
5023
5091
"An unmature HTLC transaction conflicts with a maturing one; failed to \
5024
5092
call either transaction_unconfirmed for the conflicting transaction \
5025
5093
or block_disconnected for a block containing it.") ;
@@ -5066,6 +5134,15 @@ impl<Signer: EcdsaChannelSigner> ChannelMonitorImpl<Signer> {
5066
5134
self . funding_spend_confirmed = Some ( entry. txid ) ;
5067
5135
self . confirmed_commitment_tx_counterparty_output = commitment_tx_to_counterparty_output;
5068
5136
} ,
5137
+ OnchainEvent :: AlternativeFundingConfirmation { } => {
5138
+ // An alternative funding transaction has irrevocably confirmed and we're no
5139
+ // longer allowing monitor updates, so promote the `FundingScope` now.
5140
+ debug_assert ! ( self . no_further_updates_allowed( ) ) ;
5141
+ debug_assert_ne ! ( self . funding. funding_txid( ) , entry. txid) ;
5142
+ if let Err ( _) = self . promote_funding ( entry. txid ) {
5143
+ log_error ! ( logger, "Missing scope for alternative funding confirmation with txid {}" , entry. txid) ;
5144
+ }
5145
+ } ,
5069
5146
}
5070
5147
}
5071
5148
@@ -5178,6 +5255,13 @@ impl<Signer: EcdsaChannelSigner> ChannelMonitorImpl<Signer> {
5178
5255
//- maturing spendable output has transaction paying us has been disconnected
5179
5256
self . onchain_events_awaiting_threshold_conf . retain ( |ref entry| entry. height < height) ;
5180
5257
5258
+ // TODO: Replace with `take_if` once our MSRV is >= 1.80.
5259
+ if let Some ( ( _, conf_height) ) = self . alternative_funding_confirmed . as_ref ( ) {
5260
+ if * conf_height == height {
5261
+ self . alternative_funding_confirmed . take ( ) ;
5262
+ }
5263
+ }
5264
+
5181
5265
let bounded_fee_estimator = LowerBoundedFeeEstimator :: new ( fee_estimator) ;
5182
5266
let conf_target = self . closure_conf_target ( ) ;
5183
5267
self . onchain_tx_handler . block_disconnected (
@@ -5217,6 +5301,13 @@ impl<Signer: EcdsaChannelSigner> ChannelMonitorImpl<Signer> {
5217
5301
5218
5302
debug_assert ! ( !self . onchain_events_awaiting_threshold_conf. iter( ) . any( |ref entry| entry. txid == * txid) ) ;
5219
5303
5304
+ // TODO: Replace with `take_if` once our MSRV is >= 1.80.
5305
+ if let Some ( ( alternative_funding_txid, _) ) = self . alternative_funding_confirmed . as_ref ( ) {
5306
+ if alternative_funding_txid == txid {
5307
+ self . alternative_funding_confirmed . take ( ) ;
5308
+ }
5309
+ }
5310
+
5220
5311
let conf_target = self . closure_conf_target ( ) ;
5221
5312
self . onchain_tx_handler . transaction_unconfirmed (
5222
5313
txid, broadcaster, conf_target, & self . destination_script , fee_estimator, logger
@@ -5870,6 +5961,7 @@ impl<'a, 'b, ES: EntropySource, SP: SignerProvider> ReadableArgs<(&'a ES, &'b SP
5870
5961
let mut first_negotiated_funding_txo = RequiredWrapper ( None ) ;
5871
5962
let mut channel_parameters = None ;
5872
5963
let mut pending_funding = None ;
5964
+ let mut alternative_funding_confirmed = None ;
5873
5965
read_tlv_fields ! ( reader, {
5874
5966
( 1 , funding_spend_confirmed, option) ,
5875
5967
( 3 , htlcs_resolved_on_chain, optional_vec) ,
@@ -5888,6 +5980,7 @@ impl<'a, 'b, ES: EntropySource, SP: SignerProvider> ReadableArgs<(&'a ES, &'b SP
5888
5980
( 29 , initial_counterparty_commitment_tx, option) ,
5889
5981
( 31 , channel_parameters, ( option: ReadableArgs , None ) ) ,
5890
5982
( 32 , pending_funding, optional_vec) ,
5983
+ ( 34 , alternative_funding_confirmed, option) ,
5891
5984
} ) ;
5892
5985
if let Some ( payment_preimages_with_info) = payment_preimages_with_info {
5893
5986
if payment_preimages_with_info. len ( ) != payment_preimages. len ( ) {
@@ -6057,6 +6150,8 @@ impl<'a, 'b, ES: EntropySource, SP: SignerProvider> ReadableArgs<(&'a ES, &'b SP
6057
6150
6058
6151
current_holder_htlc_data,
6059
6152
prev_holder_htlc_data,
6153
+
6154
+ alternative_funding_confirmed,
6060
6155
} ) ) )
6061
6156
}
6062
6157
}
0 commit comments