@@ -1106,6 +1106,10 @@ impl FundingScope {
11061106 fn is_splice ( & self ) -> bool {
11071107 self . channel_parameters . splice_parent_funding_txid . is_some ( )
11081108 }
1109+
1110+ fn channel_type_features ( & self ) -> & ChannelTypeFeatures {
1111+ & self . channel_parameters . channel_type_features
1112+ }
11091113}
11101114
11111115impl_writeable_tlv_based ! ( FundingScope , {
@@ -3610,7 +3614,7 @@ impl<Signer: EcdsaChannelSigner> ChannelMonitorImpl<Signer> {
36103614 // Assume that the broadcasted commitment transaction confirmed in the current best
36113615 // block. Even if not, its a reasonable metric for the bump criteria on the HTLC
36123616 // transactions.
3613- let ( claim_reqs, _) = self . get_broadcasted_holder_claims ( holder_commitment_tx, self . best_block . height ) ;
3617+ let ( claim_reqs, _) = self . get_broadcasted_holder_claims ( & self . funding , holder_commitment_tx, self . best_block . height ) ;
36143618 let conf_target = self . closure_conf_target ( ) ;
36153619 self . onchain_tx_handler . update_claims_view_from_requests (
36163620 claim_reqs, self . best_block . height , self . best_block . height , broadcaster,
@@ -3621,25 +3625,37 @@ impl<Signer: EcdsaChannelSigner> ChannelMonitorImpl<Signer> {
36213625 }
36223626
36233627 #[ rustfmt:: skip]
3624- fn generate_claimable_outpoints_and_watch_outputs ( & mut self , reason : ClosureReason ) -> ( Vec < PackageTemplate > , Vec < TransactionOutputs > ) {
3625- let holder_commitment_tx = & self . funding . current_holder_commitment_tx ;
3628+ fn generate_claimable_outpoints_and_watch_outputs (
3629+ & mut self , generate_monitor_event_with_reason : Option < ClosureReason > ,
3630+ ) -> ( Vec < PackageTemplate > , Vec < TransactionOutputs > ) {
3631+ let funding = self . alternative_funding_confirmed
3632+ . map ( |( alternative_funding_txid, _) | {
3633+ self . pending_funding
3634+ . iter ( )
3635+ . find ( |funding| funding. funding_txid ( ) == alternative_funding_txid)
3636+ . expect ( "FundingScope for confirmed alternative funding must exist" )
3637+ } )
3638+ . unwrap_or ( & self . funding ) ;
3639+ let holder_commitment_tx = & funding. current_holder_commitment_tx ;
36263640 let funding_outp = HolderFundingOutput :: build (
36273641 holder_commitment_tx. clone ( ) ,
3628- self . funding . channel_parameters . clone ( ) ,
3642+ funding. channel_parameters . clone ( ) ,
36293643 ) ;
3630- let funding_outpoint = self . get_funding_txo ( ) ;
3644+ let funding_outpoint = funding . funding_outpoint ( ) ;
36313645 let commitment_package = PackageTemplate :: build_package (
36323646 funding_outpoint. txid . clone ( ) , funding_outpoint. index as u32 ,
36333647 PackageSolvingData :: HolderFundingOutput ( funding_outp) ,
36343648 self . best_block . height ,
36353649 ) ;
36363650 let mut claimable_outpoints = vec ! [ commitment_package] ;
3637- let event = MonitorEvent :: HolderForceClosedWithInfo {
3638- reason,
3639- outpoint : funding_outpoint,
3640- channel_id : self . channel_id ,
3641- } ;
3642- self . pending_monitor_events . push ( event) ;
3651+ if let Some ( reason) = generate_monitor_event_with_reason {
3652+ let event = MonitorEvent :: HolderForceClosedWithInfo {
3653+ reason,
3654+ outpoint : funding_outpoint,
3655+ channel_id : self . channel_id ,
3656+ } ;
3657+ self . pending_monitor_events . push ( event) ;
3658+ }
36433659
36443660 // Although we aren't signing the transaction directly here, the transaction will be signed
36453661 // in the claim that is queued to OnchainTxHandler. We set holder_tx_signed here to reject
@@ -3649,12 +3665,12 @@ impl<Signer: EcdsaChannelSigner> ChannelMonitorImpl<Signer> {
36493665 // We can't broadcast our HTLC transactions while the commitment transaction is
36503666 // unconfirmed. We'll delay doing so until we detect the confirmed commitment in
36513667 // `transactions_confirmed`.
3652- if !self . channel_type_features ( ) . supports_anchors_zero_fee_htlc_tx ( ) {
3668+ if !funding . channel_type_features ( ) . supports_anchors_zero_fee_htlc_tx ( ) {
36533669 // Because we're broadcasting a commitment transaction, we should construct the package
36543670 // assuming it gets confirmed in the next block. Sadly, we have code which considers
36553671 // "not yet confirmed" things as discardable, so we cannot do that here.
36563672 let ( mut new_outpoints, _) = self . get_broadcasted_holder_claims (
3657- holder_commitment_tx, self . best_block . height ,
3673+ & funding , holder_commitment_tx, self . best_block . height ,
36583674 ) ;
36593675 let new_outputs = self . get_broadcasted_holder_watch_outputs ( holder_commitment_tx) ;
36603676 if !new_outputs. is_empty ( ) {
@@ -3678,7 +3694,7 @@ impl<Signer: EcdsaChannelSigner> ChannelMonitorImpl<Signer> {
36783694 broadcasted_latest_txn : Some ( true ) ,
36793695 message : "ChannelMonitor-initiated commitment transaction broadcast" . to_owned ( ) ,
36803696 } ;
3681- let ( claimable_outpoints, _) = self . generate_claimable_outpoints_and_watch_outputs ( reason) ;
3697+ let ( claimable_outpoints, _) = self . generate_claimable_outpoints_and_watch_outputs ( Some ( reason) ) ;
36823698 let conf_target = self . closure_conf_target ( ) ;
36833699 self . onchain_tx_handler . update_claims_view_from_requests (
36843700 claimable_outpoints, self . best_block . height , self . best_block . height , broadcaster,
@@ -4524,7 +4540,7 @@ impl<Signer: EcdsaChannelSigner> ChannelMonitorImpl<Signer> {
45244540
45254541 #[ rustfmt:: skip]
45264542 fn get_broadcasted_holder_htlc_descriptors (
4527- & self , holder_tx : & HolderCommitmentTransaction ,
4543+ & self , funding : & FundingScope , holder_tx : & HolderCommitmentTransaction ,
45284544 ) -> Vec < HTLCDescriptor > {
45294545 let tx = holder_tx. trust ( ) ;
45304546 let mut htlcs = Vec :: with_capacity ( holder_tx. nondust_htlcs ( ) . len ( ) ) ;
@@ -4542,11 +4558,10 @@ impl<Signer: EcdsaChannelSigner> ChannelMonitorImpl<Signer> {
45424558 } ;
45434559
45444560 htlcs. push ( HTLCDescriptor {
4545- // TODO(splicing): Consider alternative funding scopes.
45464561 channel_derivation_parameters : ChannelDerivationParameters {
4547- value_satoshis : self . funding . channel_parameters . channel_value_satoshis ,
4562+ value_satoshis : funding. channel_parameters . channel_value_satoshis ,
45484563 keys_id : self . channel_keys_id ,
4549- transaction_parameters : self . funding . channel_parameters . clone ( ) ,
4564+ transaction_parameters : funding. channel_parameters . clone ( ) ,
45504565 } ,
45514566 commitment_txid : tx. txid ( ) ,
45524567 per_commitment_number : tx. commitment_number ( ) ,
@@ -4566,7 +4581,7 @@ impl<Signer: EcdsaChannelSigner> ChannelMonitorImpl<Signer> {
45664581 // script so we can detect whether a holder transaction has been seen on-chain.
45674582 #[ rustfmt:: skip]
45684583 fn get_broadcasted_holder_claims (
4569- & self , holder_tx : & HolderCommitmentTransaction , conf_height : u32 ,
4584+ & self , funding : & FundingScope , holder_tx : & HolderCommitmentTransaction , conf_height : u32 ,
45704585 ) -> ( Vec < PackageTemplate > , Option < ( ScriptBuf , PublicKey , RevocationKey ) > ) {
45714586 let tx = holder_tx. trust ( ) ;
45724587 let keys = tx. keys ( ) ;
@@ -4577,7 +4592,7 @@ impl<Signer: EcdsaChannelSigner> ChannelMonitorImpl<Signer> {
45774592 redeem_script. to_p2wsh ( ) , holder_tx. per_commitment_point ( ) , keys. revocation_key . clone ( ) ,
45784593 ) ) ;
45794594
4580- let claim_requests = self . get_broadcasted_holder_htlc_descriptors ( holder_tx) . into_iter ( )
4595+ let claim_requests = self . get_broadcasted_holder_htlc_descriptors ( funding , holder_tx) . into_iter ( )
45814596 . map ( |htlc_descriptor| {
45824597 let counterparty_spendable_height = if htlc_descriptor. htlc . offered {
45834598 conf_height
@@ -4644,7 +4659,8 @@ impl<Signer: EcdsaChannelSigner> ChannelMonitorImpl<Signer> {
46444659 is_holder_tx = true ;
46454660 log_info ! ( logger, "Got broadcast of latest holder commitment tx {}, searching for available HTLCs to claim" , commitment_txid) ;
46464661 let holder_commitment_tx = & self . funding . current_holder_commitment_tx ;
4647- let res = self . get_broadcasted_holder_claims ( holder_commitment_tx, height) ;
4662+ let res =
4663+ self . get_broadcasted_holder_claims ( & self . funding , holder_commitment_tx, height) ;
46484664 let mut to_watch = self . get_broadcasted_holder_watch_outputs ( holder_commitment_tx) ;
46494665 append_onchain_update ! ( res, to_watch) ;
46504666 fail_unbroadcast_htlcs ! (
@@ -4661,7 +4677,8 @@ impl<Signer: EcdsaChannelSigner> ChannelMonitorImpl<Signer> {
46614677 if holder_commitment_tx. trust ( ) . txid ( ) == commitment_txid {
46624678 is_holder_tx = true ;
46634679 log_info ! ( logger, "Got broadcast of previous holder commitment tx {}, searching for available HTLCs to claim" , commitment_txid) ;
4664- let res = self . get_broadcasted_holder_claims ( holder_commitment_tx, height) ;
4680+ let res =
4681+ self . get_broadcasted_holder_claims ( & self . funding , holder_commitment_tx, height) ;
46654682 let mut to_watch = self . get_broadcasted_holder_watch_outputs ( holder_commitment_tx) ;
46664683 append_onchain_update ! ( res, to_watch) ;
46674684 fail_unbroadcast_htlcs ! (
@@ -4697,45 +4714,63 @@ impl<Signer: EcdsaChannelSigner> ChannelMonitorImpl<Signer> {
46974714 }
46984715 // If we have generated claims for counterparty_commitment_txid earlier, we can rely on always
46994716 // having claim related htlcs for counterparty_commitment_txid in counterparty_claimable_outpoints.
4700- for ( htlc, _) in self . funding . counterparty_claimable_outpoints . get ( counterparty_commitment_txid) . unwrap_or ( & vec ! [ ] ) {
4701- log_trace ! ( logger, "Canceling claims for previously confirmed counterparty commitment {}" ,
4702- counterparty_commitment_txid) ;
4703- let mut outpoint = BitcoinOutPoint { txid : * counterparty_commitment_txid, vout : 0 } ;
4704- if let Some ( vout) = htlc. transaction_output_index {
4705- outpoint. vout = vout;
4706- self . onchain_tx_handler . abandon_claim ( & outpoint) ;
4717+ for funding in core:: iter:: once ( & self . funding ) . chain ( self . pending_funding . iter ( ) ) {
4718+ let mut found_claim = false ;
4719+ for ( htlc, _) in funding. counterparty_claimable_outpoints . get ( counterparty_commitment_txid) . unwrap_or ( & vec ! [ ] ) {
4720+ let mut outpoint = BitcoinOutPoint { txid : * counterparty_commitment_txid, vout : 0 } ;
4721+ if let Some ( vout) = htlc. transaction_output_index {
4722+ outpoint. vout = vout;
4723+ if self . onchain_tx_handler . abandon_claim ( & outpoint) {
4724+ found_claim = true ;
4725+ }
4726+ }
4727+ }
4728+ if found_claim {
4729+ log_trace ! ( logger, "Canceled claims for previously confirmed counterparty commitment with txid {counterparty_commitment_txid}" ) ;
47074730 }
47084731 }
47094732 }
47104733 // Cancel any pending claims for any holder commitments in case they had previously
47114734 // confirmed or been signed (in which case we will start attempting to claim without
47124735 // waiting for confirmation).
4713- if self . funding . current_holder_commitment_tx . trust ( ) . txid ( ) != * confirmed_commitment_txid {
4714- let txid = self . funding . current_holder_commitment_tx . trust ( ) . txid ( ) ;
4715- log_trace ! ( logger, "Canceling claims for previously broadcast holder commitment {}" , txid) ;
4716- let mut outpoint = BitcoinOutPoint { txid, vout : 0 } ;
4717- for htlc in self . funding . current_holder_commitment_tx . nondust_htlcs ( ) {
4718- if let Some ( vout) = htlc. transaction_output_index {
4719- outpoint. vout = vout;
4720- self . onchain_tx_handler . abandon_claim ( & outpoint) ;
4721- } else {
4722- debug_assert ! ( false , "Expected transaction output index for non-dust HTLC" ) ;
4723- }
4724- }
4725- }
4726- if let Some ( prev_holder_commitment_tx) = & self . funding . prev_holder_commitment_tx {
4727- let txid = prev_holder_commitment_tx. trust ( ) . txid ( ) ;
4728- if txid != * confirmed_commitment_txid {
4729- log_trace ! ( logger, "Canceling claims for previously broadcast holder commitment {}" , txid) ;
4736+ for funding in core:: iter:: once ( & self . funding ) . chain ( self . pending_funding . iter ( ) ) {
4737+ if funding. current_holder_commitment_tx . trust ( ) . txid ( ) != * confirmed_commitment_txid {
4738+ let mut found_claim = false ;
4739+ let txid = funding. current_holder_commitment_tx . trust ( ) . txid ( ) ;
47304740 let mut outpoint = BitcoinOutPoint { txid, vout : 0 } ;
4731- for htlc in prev_holder_commitment_tx . nondust_htlcs ( ) {
4741+ for htlc in funding . current_holder_commitment_tx . nondust_htlcs ( ) {
47324742 if let Some ( vout) = htlc. transaction_output_index {
47334743 outpoint. vout = vout;
4734- self . onchain_tx_handler . abandon_claim ( & outpoint) ;
4744+ if self . onchain_tx_handler . abandon_claim ( & outpoint) {
4745+ found_claim = true ;
4746+ }
47354747 } else {
47364748 debug_assert ! ( false , "Expected transaction output index for non-dust HTLC" ) ;
47374749 }
47384750 }
4751+ if found_claim {
4752+ log_trace ! ( logger, "Canceled claims for previously broadcast holder commitment with txid {txid}" ) ;
4753+ }
4754+ }
4755+ if let Some ( prev_holder_commitment_tx) = & funding. prev_holder_commitment_tx {
4756+ let txid = prev_holder_commitment_tx. trust ( ) . txid ( ) ;
4757+ if txid != * confirmed_commitment_txid {
4758+ let mut found_claim = false ;
4759+ let mut outpoint = BitcoinOutPoint { txid, vout : 0 } ;
4760+ for htlc in prev_holder_commitment_tx. nondust_htlcs ( ) {
4761+ if let Some ( vout) = htlc. transaction_output_index {
4762+ outpoint. vout = vout;
4763+ if self . onchain_tx_handler . abandon_claim ( & outpoint) {
4764+ found_claim = true ;
4765+ }
4766+ } else {
4767+ debug_assert ! ( false , "Expected transaction output index for non-dust HTLC" ) ;
4768+ }
4769+ }
4770+ if found_claim {
4771+ log_trace ! ( logger, "Canceled claims for previously broadcast holder commitment with txid {txid}" ) ;
4772+ }
4773+ }
47394774 }
47404775 }
47414776 }
@@ -4762,7 +4797,7 @@ impl<Signer: EcdsaChannelSigner> ChannelMonitorImpl<Signer> {
47624797 return holder_transactions;
47634798 }
47644799
4765- self . get_broadcasted_holder_htlc_descriptors ( & self . funding . current_holder_commitment_tx )
4800+ self . get_broadcasted_holder_htlc_descriptors ( & self . funding , & self . funding . current_holder_commitment_tx )
47664801 . into_iter ( )
47674802 . for_each ( |htlc_descriptor| {
47684803 let txid = self . funding . current_holder_commitment_tx . trust ( ) . txid ( ) ;
@@ -4858,6 +4893,7 @@ impl<Signer: EcdsaChannelSigner> ChannelMonitorImpl<Signer> {
48584893
48594894 let mut watch_outputs = Vec :: new ( ) ;
48604895 let mut claimable_outpoints = Vec :: new ( ) ;
4896+ let mut should_broadcast_commitment = false ;
48614897 ' tx_iter: for tx in & txn_matched {
48624898 let txid = tx. compute_txid ( ) ;
48634899 log_trace ! ( logger, "Transaction {} confirmed in block {}" , txid , block_hash) ;
@@ -4938,6 +4974,26 @@ impl<Signer: EcdsaChannelSigner> ChannelMonitorImpl<Signer> {
49384974 } ) ;
49394975 }
49404976
4977+ if self . holder_tx_signed {
4978+ // Cancel any previous claims that are no longer valid as they stemmed from a
4979+ // different funding transaction.
4980+ let alternative_holder_commitment_txid =
4981+ alternative_funding. current_holder_commitment_tx . trust ( ) . txid ( ) ;
4982+ self . cancel_prev_commitment_claims ( & logger, & alternative_holder_commitment_txid) ;
4983+
4984+ // Queue claims for the alternative holder commitment since it is the only one
4985+ // that can currently confirm so far (until we see a reorg of its funding
4986+ // transaction).
4987+ //
4988+ // It's possible we process a holder/counterparty commitment within this same
4989+ // block that would invalidate the one we're intending to broadcast. If we were
4990+ // to broadcast our holder commitment now, we wouldn't be able to cancel it via
4991+ // our usual `cancel_prev_commitment_claims` path once we see a confirmed
4992+ // commitment since the claim would still be pending in `claimable_outpoints`
4993+ // (i.e., it wouldn't have been registered with the `OnchainTxHandler` yet).
4994+ should_broadcast_commitment = true ;
4995+ }
4996+
49414997 continue ' tx_iter;
49424998 }
49434999
@@ -4975,6 +5031,10 @@ impl<Signer: EcdsaChannelSigner> ChannelMonitorImpl<Signer> {
49755031
49765032 claimable_outpoints. append ( & mut new_outpoints) ;
49775033 }
5034+
5035+ // We've just seen a commitment confirm, which conflicts with the holder
5036+ // commitment we intend to broadcast
5037+ should_broadcast_commitment = false ;
49785038 }
49795039 self . onchain_events_awaiting_threshold_conf . push ( OnchainEventEntry {
49805040 txid,
@@ -5023,6 +5083,13 @@ impl<Signer: EcdsaChannelSigner> ChannelMonitorImpl<Signer> {
50235083 self . best_block = BestBlock :: new ( block_hash, height) ;
50245084 }
50255085
5086+ if should_broadcast_commitment {
5087+ let ( mut claimables, mut outputs) =
5088+ self . generate_claimable_outpoints_and_watch_outputs ( None ) ;
5089+ claimable_outpoints. append ( & mut claimables) ;
5090+ watch_outputs. append ( & mut outputs) ;
5091+ }
5092+
50265093 self . block_confirmed ( height, block_hash, txn_matched, watch_outputs, claimable_outpoints, & broadcaster, & fee_estimator, logger)
50275094 }
50285095
@@ -5056,7 +5123,7 @@ impl<Signer: EcdsaChannelSigner> ChannelMonitorImpl<Signer> {
50565123
50575124 let should_broadcast = self . should_broadcast_holder_commitment_txn ( logger) ;
50585125 if should_broadcast {
5059- let ( mut new_outpoints, mut new_outputs) = self . generate_claimable_outpoints_and_watch_outputs ( ClosureReason :: HTLCsTimedOut ) ;
5126+ let ( mut new_outpoints, mut new_outputs) = self . generate_claimable_outpoints_and_watch_outputs ( Some ( ClosureReason :: HTLCsTimedOut ) ) ;
50605127 claimable_outpoints. append ( & mut new_outpoints) ;
50615128 watch_outputs. append ( & mut new_outputs) ;
50625129 }
@@ -5259,6 +5326,14 @@ impl<Signer: EcdsaChannelSigner> ChannelMonitorImpl<Signer> {
52595326 if let Some ( ( _, conf_height) ) = self . alternative_funding_confirmed . as_ref ( ) {
52605327 if * conf_height == height {
52615328 self . alternative_funding_confirmed . take ( ) ;
5329+ if self . holder_tx_signed {
5330+ // Cancel any previous claims that are no longer valid as they stemmed from a
5331+ // different funding transaction. We'll wait until we see a funding transaction
5332+ // confirm again before attempting to broadcast the new valid holder commitment.
5333+ let new_holder_commitment_txid =
5334+ self . funding . current_holder_commitment_tx . trust ( ) . txid ( ) ;
5335+ self . cancel_prev_commitment_claims ( & logger, & new_holder_commitment_txid) ;
5336+ }
52625337 }
52635338 }
52645339
@@ -5305,6 +5380,14 @@ impl<Signer: EcdsaChannelSigner> ChannelMonitorImpl<Signer> {
53055380 if let Some ( ( alternative_funding_txid, _) ) = self . alternative_funding_confirmed . as_ref ( ) {
53065381 if alternative_funding_txid == txid {
53075382 self . alternative_funding_confirmed . take ( ) ;
5383+ if self . holder_tx_signed {
5384+ // Cancel any previous claims that are no longer valid as they stemmed from a
5385+ // different funding transaction. We'll wait until we see a funding transaction
5386+ // confirm again before attempting to broadcast the new valid holder commitment.
5387+ let new_holder_commitment_txid =
5388+ self . funding . current_holder_commitment_tx . trust ( ) . txid ( ) ;
5389+ self . cancel_prev_commitment_claims ( & logger, & new_holder_commitment_txid) ;
5390+ }
53085391 }
53095392 }
53105393
0 commit comments