@@ -565,6 +565,12 @@ enum OnchainEvent {
565
565
/// output (and generate a SpendableOutput event).
566
566
on_to_local_output_csv : Option < u16 > ,
567
567
} ,
568
+ /// The txid of an alternative funding transaction (due to a splice) that has confirmed but is
569
+ /// not yet locked, invalidating the previous funding transaction as it now spent. Note that we
570
+ /// wait to promote the corresponding `FundingScope` until we see a
571
+ /// [`ChannelMonitorUpdateStep::RenegotiatedFundingLocked`] or if the alternative funding
572
+ /// transaction is irrevocably confirmed.
573
+ AlternativeFundingConfirmation { } ,
568
574
}
569
575
570
576
impl Writeable for OnchainEventEntry {
@@ -609,6 +615,7 @@ impl_writeable_tlv_based_enum_upgradable!(OnchainEvent,
609
615
( 1 , MaturingOutput ) => {
610
616
( 0 , descriptor, required) ,
611
617
} ,
618
+ ( 2 , AlternativeFundingConfirmation ) => { } ,
612
619
( 3 , FundingSpendConfirmation ) => {
613
620
( 0 , on_local_output_csv, option) ,
614
621
( 1 , commitment_tx_to_counterparty_output, option) ,
@@ -618,7 +625,6 @@ impl_writeable_tlv_based_enum_upgradable!(OnchainEvent,
618
625
( 2 , preimage, option) ,
619
626
( 4 , on_to_local_output_csv, option) ,
620
627
} ,
621
-
622
628
) ;
623
629
624
630
#[ derive( Clone , Debug , PartialEq , Eq ) ]
@@ -4871,6 +4877,49 @@ impl<Signer: EcdsaChannelSigner> ChannelMonitorImpl<Signer> {
4871
4877
}
4872
4878
}
4873
4879
4880
+ // A splice transaction has confirmed. We can't promote the splice's scope until we see
4881
+ // the corresponding monitor update for it, but we track the txid so we know which
4882
+ // holder commitment transaction we may need to broadcast.
4883
+ if let Some ( alternative_funding) = self . pending_funding . iter ( )
4884
+ . find ( |funding| funding. funding_txid ( ) == txid)
4885
+ {
4886
+ debug_assert ! ( self . funding_spend_confirmed. is_none( ) ) ;
4887
+ debug_assert ! (
4888
+ !self . onchain_events_awaiting_threshold_conf. iter( )
4889
+ . any( |e| matches!( e. event, OnchainEvent :: FundingSpendConfirmation { .. } ) )
4890
+ ) ;
4891
+ debug_assert_eq ! (
4892
+ self . funding. funding_outpoint( ) . into_bitcoin_outpoint( ) ,
4893
+ tx. input[ 0 ] . previous_output
4894
+ ) ;
4895
+
4896
+ let ( desc, msg) = if alternative_funding. channel_parameters . splice_parent_funding_txid . is_some ( ) {
4897
+ ( "Splice" , "splice_locked" )
4898
+ } else {
4899
+ ( "RBF" , "channel_ready" )
4900
+ } ;
4901
+ let action = if self . no_further_updates_allowed ( ) {
4902
+ if self . holder_tx_signed {
4903
+ ", broadcasting post-splice holder commitment transaction" . to_string ( )
4904
+ } else {
4905
+ "" . to_string ( )
4906
+ }
4907
+ } else {
4908
+ format ! ( ", waiting for `{}` exchange" , msg)
4909
+ } ;
4910
+ log_info ! ( logger, "{desc} for channel {} confirmed with txid {txid}{action}" , self . channel_id( ) ) ;
4911
+
4912
+ self . onchain_events_awaiting_threshold_conf . push ( OnchainEventEntry {
4913
+ txid,
4914
+ transaction : Some ( ( * tx) . clone ( ) ) ,
4915
+ height,
4916
+ block_hash : Some ( block_hash) ,
4917
+ event : OnchainEvent :: AlternativeFundingConfirmation { } ,
4918
+ } ) ;
4919
+
4920
+ continue ' tx_iter;
4921
+ }
4922
+
4874
4923
if tx. input . len ( ) == 1 {
4875
4924
// Assuming our keys were not leaked (in which case we're screwed no matter what),
4876
4925
// commitment transactions and HTLC transactions will all only ever have one input
@@ -5002,7 +5051,7 @@ impl<Signer: EcdsaChannelSigner> ChannelMonitorImpl<Signer> {
5002
5051
let unmatured_htlcs: Vec < _ > = self . onchain_events_awaiting_threshold_conf
5003
5052
. iter ( )
5004
5053
. filter_map ( |entry| match & entry. event {
5005
- OnchainEvent :: HTLCUpdate { source, .. } => Some ( source) ,
5054
+ OnchainEvent :: HTLCUpdate { source, .. } => Some ( source. clone ( ) ) ,
5006
5055
_ => None ,
5007
5056
} )
5008
5057
. collect ( ) ;
@@ -5017,7 +5066,7 @@ impl<Signer: EcdsaChannelSigner> ChannelMonitorImpl<Signer> {
5017
5066
#[ cfg( debug_assertions) ]
5018
5067
{
5019
5068
debug_assert ! (
5020
- !unmatured_htlcs. contains( && source) ,
5069
+ !unmatured_htlcs. contains( & source) ,
5021
5070
"An unmature HTLC transaction conflicts with a maturing one; failed to \
5022
5071
call either transaction_unconfirmed for the conflicting transaction \
5023
5072
or block_disconnected for a block containing it.") ;
@@ -5064,6 +5113,21 @@ impl<Signer: EcdsaChannelSigner> ChannelMonitorImpl<Signer> {
5064
5113
self . funding_spend_confirmed = Some ( entry. txid ) ;
5065
5114
self . confirmed_commitment_tx_counterparty_output = commitment_tx_to_counterparty_output;
5066
5115
} ,
5116
+ OnchainEvent :: AlternativeFundingConfirmation { } => {
5117
+ // An alternative funding transaction has irrevocably confirmed. Locate the
5118
+ // corresponding scope and promote it if the monitor is no longer allowing
5119
+ // updates. Otherwise, we expect it to be promoted via
5120
+ // [`ChannelMonitorUpdateStep::RenegotiatedFundingLocked`].
5121
+ if self . no_further_updates_allowed ( ) {
5122
+ let funding_txid = entry. transaction
5123
+ . expect ( "Transactions are always present for AlternativeFundingConfirmation entries" )
5124
+ . compute_txid ( ) ;
5125
+ debug_assert_ne ! ( self . funding. funding_txid( ) , funding_txid) ;
5126
+ if let Err ( _) = self . promote_funding ( funding_txid) {
5127
+ log_error ! ( logger, "Missing scope for alternative funding confirmation with txid {}" , entry. txid) ;
5128
+ }
5129
+ }
5130
+ } ,
5067
5131
}
5068
5132
}
5069
5133
0 commit comments