@@ -1106,6 +1106,10 @@ impl FundingScope {
1106
1106
fn is_splice ( & self ) -> bool {
1107
1107
self . channel_parameters . splice_parent_funding_txid . is_some ( )
1108
1108
}
1109
+
1110
+ fn channel_type_features ( & self ) -> & ChannelTypeFeatures {
1111
+ & self . channel_parameters . channel_type_features
1112
+ }
1109
1113
}
1110
1114
1111
1115
impl_writeable_tlv_based ! ( FundingScope , {
@@ -3610,7 +3614,7 @@ impl<Signer: EcdsaChannelSigner> ChannelMonitorImpl<Signer> {
3610
3614
// Assume that the broadcasted commitment transaction confirmed in the current best
3611
3615
// block. Even if not, its a reasonable metric for the bump criteria on the HTLC
3612
3616
// 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 ) ;
3614
3618
let conf_target = self . closure_conf_target ( ) ;
3615
3619
self . onchain_tx_handler . update_claims_view_from_requests (
3616
3620
claim_reqs, self . best_block . height , self . best_block . height , broadcaster,
@@ -3621,25 +3625,37 @@ impl<Signer: EcdsaChannelSigner> ChannelMonitorImpl<Signer> {
3621
3625
}
3622
3626
3623
3627
#[ 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 ;
3626
3640
let funding_outp = HolderFundingOutput :: build (
3627
3641
holder_commitment_tx. clone ( ) ,
3628
- self . funding . channel_parameters . clone ( ) ,
3642
+ funding. channel_parameters . clone ( ) ,
3629
3643
) ;
3630
- let funding_outpoint = self . get_funding_txo ( ) ;
3644
+ let funding_outpoint = funding . funding_outpoint ( ) ;
3631
3645
let commitment_package = PackageTemplate :: build_package (
3632
3646
funding_outpoint. txid . clone ( ) , funding_outpoint. index as u32 ,
3633
3647
PackageSolvingData :: HolderFundingOutput ( funding_outp) ,
3634
3648
self . best_block . height ,
3635
3649
) ;
3636
3650
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
+ }
3643
3659
3644
3660
// Although we aren't signing the transaction directly here, the transaction will be signed
3645
3661
// 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> {
3649
3665
// We can't broadcast our HTLC transactions while the commitment transaction is
3650
3666
// unconfirmed. We'll delay doing so until we detect the confirmed commitment in
3651
3667
// `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 ( ) {
3653
3669
// Because we're broadcasting a commitment transaction, we should construct the package
3654
3670
// assuming it gets confirmed in the next block. Sadly, we have code which considers
3655
3671
// "not yet confirmed" things as discardable, so we cannot do that here.
3656
3672
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 ,
3658
3674
) ;
3659
3675
let new_outputs = self . get_broadcasted_holder_watch_outputs ( holder_commitment_tx) ;
3660
3676
if !new_outputs. is_empty ( ) {
@@ -3678,7 +3694,7 @@ impl<Signer: EcdsaChannelSigner> ChannelMonitorImpl<Signer> {
3678
3694
broadcasted_latest_txn : Some ( true ) ,
3679
3695
message : "ChannelMonitor-initiated commitment transaction broadcast" . to_owned ( ) ,
3680
3696
} ;
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) ) ;
3682
3698
let conf_target = self . closure_conf_target ( ) ;
3683
3699
self . onchain_tx_handler . update_claims_view_from_requests (
3684
3700
claimable_outpoints, self . best_block . height , self . best_block . height , broadcaster,
@@ -4524,7 +4540,7 @@ impl<Signer: EcdsaChannelSigner> ChannelMonitorImpl<Signer> {
4524
4540
4525
4541
#[ rustfmt:: skip]
4526
4542
fn get_broadcasted_holder_htlc_descriptors (
4527
- & self , holder_tx : & HolderCommitmentTransaction ,
4543
+ & self , funding : & FundingScope , holder_tx : & HolderCommitmentTransaction ,
4528
4544
) -> Vec < HTLCDescriptor > {
4529
4545
let tx = holder_tx. trust ( ) ;
4530
4546
let mut htlcs = Vec :: with_capacity ( holder_tx. nondust_htlcs ( ) . len ( ) ) ;
@@ -4542,11 +4558,10 @@ impl<Signer: EcdsaChannelSigner> ChannelMonitorImpl<Signer> {
4542
4558
} ;
4543
4559
4544
4560
htlcs. push ( HTLCDescriptor {
4545
- // TODO(splicing): Consider alternative funding scopes.
4546
4561
channel_derivation_parameters : ChannelDerivationParameters {
4547
- value_satoshis : self . funding . channel_parameters . channel_value_satoshis ,
4562
+ value_satoshis : funding. channel_parameters . channel_value_satoshis ,
4548
4563
keys_id : self . channel_keys_id ,
4549
- transaction_parameters : self . funding . channel_parameters . clone ( ) ,
4564
+ transaction_parameters : funding. channel_parameters . clone ( ) ,
4550
4565
} ,
4551
4566
commitment_txid : tx. txid ( ) ,
4552
4567
per_commitment_number : tx. commitment_number ( ) ,
@@ -4566,7 +4581,7 @@ impl<Signer: EcdsaChannelSigner> ChannelMonitorImpl<Signer> {
4566
4581
// script so we can detect whether a holder transaction has been seen on-chain.
4567
4582
#[ rustfmt:: skip]
4568
4583
fn get_broadcasted_holder_claims (
4569
- & self , holder_tx : & HolderCommitmentTransaction , conf_height : u32 ,
4584
+ & self , funding : & FundingScope , holder_tx : & HolderCommitmentTransaction , conf_height : u32 ,
4570
4585
) -> ( Vec < PackageTemplate > , Option < ( ScriptBuf , PublicKey , RevocationKey ) > ) {
4571
4586
let tx = holder_tx. trust ( ) ;
4572
4587
let keys = tx. keys ( ) ;
@@ -4577,7 +4592,7 @@ impl<Signer: EcdsaChannelSigner> ChannelMonitorImpl<Signer> {
4577
4592
redeem_script. to_p2wsh ( ) , holder_tx. per_commitment_point ( ) , keys. revocation_key . clone ( ) ,
4578
4593
) ) ;
4579
4594
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 ( )
4581
4596
. map ( |htlc_descriptor| {
4582
4597
let counterparty_spendable_height = if htlc_descriptor. htlc . offered {
4583
4598
conf_height
@@ -4644,7 +4659,8 @@ impl<Signer: EcdsaChannelSigner> ChannelMonitorImpl<Signer> {
4644
4659
is_holder_tx = true ;
4645
4660
log_info ! ( logger, "Got broadcast of latest holder commitment tx {}, searching for available HTLCs to claim" , commitment_txid) ;
4646
4661
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) ;
4648
4664
let mut to_watch = self . get_broadcasted_holder_watch_outputs ( holder_commitment_tx) ;
4649
4665
append_onchain_update ! ( res, to_watch) ;
4650
4666
fail_unbroadcast_htlcs ! (
@@ -4661,7 +4677,8 @@ impl<Signer: EcdsaChannelSigner> ChannelMonitorImpl<Signer> {
4661
4677
if holder_commitment_tx. trust ( ) . txid ( ) == commitment_txid {
4662
4678
is_holder_tx = true ;
4663
4679
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) ;
4665
4682
let mut to_watch = self . get_broadcasted_holder_watch_outputs ( holder_commitment_tx) ;
4666
4683
append_onchain_update ! ( res, to_watch) ;
4667
4684
fail_unbroadcast_htlcs ! (
@@ -4697,45 +4714,63 @@ impl<Signer: EcdsaChannelSigner> ChannelMonitorImpl<Signer> {
4697
4714
}
4698
4715
// If we have generated claims for counterparty_commitment_txid earlier, we can rely on always
4699
4716
// 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}" ) ;
4707
4730
}
4708
4731
}
4709
4732
}
4710
4733
// Cancel any pending claims for any holder commitments in case they had previously
4711
4734
// confirmed or been signed (in which case we will start attempting to claim without
4712
4735
// 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 ( ) ;
4730
4740
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 ( ) {
4732
4742
if let Some ( vout) = htlc. transaction_output_index {
4733
4743
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
+ }
4735
4747
} else {
4736
4748
debug_assert ! ( false , "Expected transaction output index for non-dust HTLC" ) ;
4737
4749
}
4738
4750
}
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
+ }
4739
4774
}
4740
4775
}
4741
4776
}
@@ -4762,7 +4797,7 @@ impl<Signer: EcdsaChannelSigner> ChannelMonitorImpl<Signer> {
4762
4797
return holder_transactions;
4763
4798
}
4764
4799
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 )
4766
4801
. into_iter ( )
4767
4802
. for_each ( |htlc_descriptor| {
4768
4803
let txid = self . funding . current_holder_commitment_tx . trust ( ) . txid ( ) ;
@@ -4858,6 +4893,7 @@ impl<Signer: EcdsaChannelSigner> ChannelMonitorImpl<Signer> {
4858
4893
4859
4894
let mut watch_outputs = Vec :: new ( ) ;
4860
4895
let mut claimable_outpoints = Vec :: new ( ) ;
4896
+ let mut should_broadcast_commitment = false ;
4861
4897
' tx_iter: for tx in & txn_matched {
4862
4898
let txid = tx. compute_txid ( ) ;
4863
4899
log_trace ! ( logger, "Transaction {} confirmed in block {}" , txid , block_hash) ;
@@ -4938,6 +4974,26 @@ impl<Signer: EcdsaChannelSigner> ChannelMonitorImpl<Signer> {
4938
4974
} ) ;
4939
4975
}
4940
4976
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
+
4941
4997
continue ' tx_iter;
4942
4998
}
4943
4999
@@ -4975,6 +5031,10 @@ impl<Signer: EcdsaChannelSigner> ChannelMonitorImpl<Signer> {
4975
5031
4976
5032
claimable_outpoints. append ( & mut new_outpoints) ;
4977
5033
}
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 ;
4978
5038
}
4979
5039
self . onchain_events_awaiting_threshold_conf . push ( OnchainEventEntry {
4980
5040
txid,
@@ -5023,6 +5083,13 @@ impl<Signer: EcdsaChannelSigner> ChannelMonitorImpl<Signer> {
5023
5083
self . best_block = BestBlock :: new ( block_hash, height) ;
5024
5084
}
5025
5085
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
+
5026
5093
self . block_confirmed ( height, block_hash, txn_matched, watch_outputs, claimable_outpoints, & broadcaster, & fee_estimator, logger)
5027
5094
}
5028
5095
@@ -5056,7 +5123,7 @@ impl<Signer: EcdsaChannelSigner> ChannelMonitorImpl<Signer> {
5056
5123
5057
5124
let should_broadcast = self . should_broadcast_holder_commitment_txn ( logger) ;
5058
5125
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 ) ) ;
5060
5127
claimable_outpoints. append ( & mut new_outpoints) ;
5061
5128
watch_outputs. append ( & mut new_outputs) ;
5062
5129
}
@@ -5259,6 +5326,14 @@ impl<Signer: EcdsaChannelSigner> ChannelMonitorImpl<Signer> {
5259
5326
if let Some ( ( _, conf_height) ) = self . alternative_funding_confirmed . as_ref ( ) {
5260
5327
if * conf_height == height {
5261
5328
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
+ }
5262
5337
}
5263
5338
}
5264
5339
@@ -5305,6 +5380,14 @@ impl<Signer: EcdsaChannelSigner> ChannelMonitorImpl<Signer> {
5305
5380
if let Some ( ( alternative_funding_txid, _) ) = self . alternative_funding_confirmed . as_ref ( ) {
5306
5381
if alternative_funding_txid == txid {
5307
5382
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
+ }
5308
5391
}
5309
5392
}
5310
5393
0 commit comments