@@ -777,6 +777,24 @@ pub enum BalanceSource {
777
777
Htlc ,
778
778
}
779
779
780
+ /// The claimable balance of a holder commitment transaction that has yet to be broadcast.
781
+ #[ derive( Clone , Debug , PartialEq , Eq ) ]
782
+ #[ cfg_attr( test, derive( PartialOrd , Ord ) ) ]
783
+ pub struct HolderCommitmentTransactionBalance {
784
+ /// The amount available to claim, in satoshis, excluding the on-chain fees which will be
785
+ /// required to do so.
786
+ pub amount_satoshis : u64 ,
787
+ /// The transaction fee we pay for the closing commitment transaction. This amount is not
788
+ /// included in the [`HolderCommitmentTransaction::amount_satoshis`] value.
789
+ /// This amount includes the sum of dust HTLCs on the commitment transaction, any elided anchors,
790
+ /// as well as the sum of msat amounts rounded down from non-dust HTLCs.
791
+ ///
792
+ /// Note that if this channel is inbound (and thus our counterparty pays the commitment
793
+ /// transaction fee) this value will be zero. For [`ChannelMonitor`]s created prior to LDK
794
+ /// 0.0.124, the channel is always treated as outbound (and thus this value is never zero).
795
+ pub transaction_fee_satoshis : u64 ,
796
+ }
797
+
780
798
/// Details about the balance(s) available for spending once the channel appears on chain.
781
799
///
782
800
/// See [`ChannelMonitor::get_claimable_balances`] for more details on when these will or will not
@@ -785,21 +803,21 @@ pub enum BalanceSource {
785
803
#[ cfg_attr( test, derive( PartialOrd , Ord ) ) ]
786
804
pub enum Balance {
787
805
/// The channel is not yet closed (or the commitment or closing transaction has not yet
788
- /// appeared in a block). The given balance is claimable (less on-chain fees) if the channel is
789
- /// force-closed now.
806
+ /// appeared in a block).
790
807
ClaimableOnChannelClose {
791
- /// The amount available to claim, in satoshis, excluding the on-chain fees which will be
792
- /// required to do so.
793
- amount_satoshis : u64 ,
794
- /// The transaction fee we pay for the closing commitment transaction. This amount is not
795
- /// included in the [`Balance::ClaimableOnChannelClose::amount_satoshis`] value.
796
- /// This amount includes the sum of dust HTLCs on the commitment transaction, any elided anchors,
797
- /// as well as the sum of msat amounts rounded down from non-dust HTLCs.
808
+ /// A list of balance candidates based on the latest set of valid holder commitment
809
+ /// transactions that can hit the chain. Typically, a channel only has one valid holder
810
+ /// commitment transaction that spends the current funding output. As soon as a channel is
811
+ /// spliced, an alternative holder commitment transaction exists spending the new funding
812
+ /// output. More alternative holder commitment transactions can exist as the splice remains
813
+ /// pending and RBF attempts are made.
798
814
///
799
- /// Note that if this channel is inbound (and thus our counterparty pays the commitment
800
- /// transaction fee) this value will be zero. For [`ChannelMonitor`]s created prior to LDK
801
- /// 0.0.124, the channel is always treated as outbound (and thus this value is never zero).
802
- transaction_fee_satoshis : u64 ,
815
+ /// The candidates are sorted by the order in which the holder commitment transactions were
816
+ /// negotiated. When only one candidate exists, the channel does not have a splice pending.
817
+ /// When multiple candidates exist, the last one reflects the balance of the
818
+ /// latest splice/RBF attempt, while the first reflects the balance prior to the splice
819
+ /// occurring.
820
+ balance_candidates : Vec < HolderCommitmentTransactionBalance > ,
803
821
/// The amount of millisatoshis which has been burned to fees from HTLCs which are outbound
804
822
/// from us and are related to a payment which was sent by us. This is the sum of the
805
823
/// millisatoshis part of all HTLCs which are otherwise represented by
@@ -821,7 +839,7 @@ pub enum Balance {
821
839
/// to us and for which we know the preimage. This is the sum of the millisatoshis part of
822
840
/// all HTLCs which would be represented by [`Balance::ContentiousClaimable`] on channel
823
841
/// close, but whose current value is included in
824
- /// [`Balance::ClaimableOnChannelClose ::amount_satoshis`], as well as any dust HTLCs which
842
+ /// [`HolderCommitmentTransactionBalance ::amount_satoshis`], as well as any dust HTLCs which
825
843
/// would otherwise be represented the same.
826
844
///
827
845
/// This amount (rounded up to a whole satoshi value) will not be included in the counterparty's
@@ -928,7 +946,11 @@ impl Balance {
928
946
#[ rustfmt:: skip]
929
947
pub fn claimable_amount_satoshis ( & self ) -> u64 {
930
948
match self {
931
- Balance :: ClaimableOnChannelClose { amount_satoshis, .. } |
949
+ Balance :: ClaimableOnChannelClose { balance_candidates, .. } => {
950
+ // FIXME: Should we report the balance for the currently confirmed splice
951
+ // transaction before it has been locked?
952
+ balance_candidates. last ( ) . map ( |balance| balance. amount_satoshis ) . unwrap_or ( 0 )
953
+ } ,
932
954
Balance :: ClaimableAwaitingConfirmations { amount_satoshis, .. } |
933
955
Balance :: ContentiousClaimable { amount_satoshis, .. } |
934
956
Balance :: CounterpartyRevokedOutputClaimable { amount_satoshis, .. }
@@ -2671,7 +2693,8 @@ impl<Signer: EcdsaChannelSigner> ChannelMonitorImpl<Signer> {
2671
2693
debug_assert ! ( htlc_input_idx_opt. is_some( ) ) ;
2672
2694
BitcoinOutPoint :: new ( * txid, htlc_input_idx_opt. unwrap_or ( 0 ) )
2673
2695
} else {
2674
- debug_assert ! ( !self . channel_type_features( ) . supports_anchors_zero_fee_htlc_tx( ) ) ;
2696
+ let funding = get_confirmed_funding_scope ! ( self ) ;
2697
+ debug_assert ! ( !funding. channel_type_features( ) . supports_anchors_zero_fee_htlc_tx( ) ) ;
2675
2698
BitcoinOutPoint :: new ( * txid, 0 )
2676
2699
}
2677
2700
} else {
@@ -2833,8 +2856,9 @@ impl<Signer: EcdsaChannelSigner> ChannelMonitor<Signer> {
2833
2856
}
2834
2857
2835
2858
if let Some ( txid) = confirmed_txid {
2859
+ let funding_spent = get_confirmed_funding_scope ! ( us) ;
2836
2860
let mut found_commitment_tx = false ;
2837
- if let Some ( counterparty_tx_htlcs) = us . funding . counterparty_claimable_outpoints . get ( & txid) {
2861
+ if let Some ( counterparty_tx_htlcs) = funding_spent . counterparty_claimable_outpoints . get ( & txid) {
2838
2862
// First look for the to_remote output back to us.
2839
2863
if let Some ( conf_thresh) = pending_commitment_tx_conf_thresh {
2840
2864
if let Some ( value) = us. onchain_events_awaiting_threshold_conf . iter ( ) . find_map ( |event| {
@@ -2855,7 +2879,7 @@ impl<Signer: EcdsaChannelSigner> ChannelMonitor<Signer> {
2855
2879
// confirmation with the same height or have never met our dust amount.
2856
2880
}
2857
2881
}
2858
- if Some ( txid) == us . funding . current_counterparty_commitment_txid || Some ( txid) == us . funding . prev_counterparty_commitment_txid {
2882
+ if Some ( txid) == funding_spent . current_counterparty_commitment_txid || Some ( txid) == funding_spent . prev_counterparty_commitment_txid {
2859
2883
walk_htlcs ! ( false , false , counterparty_tx_htlcs. iter( ) . map( |( a, b) | ( a, b. as_ref( ) . map( |b| & * * b) ) ) ) ;
2860
2884
} else {
2861
2885
walk_htlcs ! ( false , true , counterparty_tx_htlcs. iter( ) . map( |( a, b) | ( a, b. as_ref( ) . map( |b| & * * b) ) ) ) ;
@@ -2898,17 +2922,17 @@ impl<Signer: EcdsaChannelSigner> ChannelMonitor<Signer> {
2898
2922
}
2899
2923
}
2900
2924
found_commitment_tx = true ;
2901
- } else if txid == us . funding . current_holder_commitment_tx . trust ( ) . txid ( ) {
2925
+ } else if txid == funding_spent . current_holder_commitment_tx . trust ( ) . txid ( ) {
2902
2926
walk_htlcs ! ( true , false , holder_commitment_htlcs!( us, CURRENT_WITH_SOURCES ) ) ;
2903
2927
if let Some ( conf_thresh) = pending_commitment_tx_conf_thresh {
2904
2928
res. push ( Balance :: ClaimableAwaitingConfirmations {
2905
- amount_satoshis : us . funding . current_holder_commitment_tx . to_broadcaster_value_sat ( ) ,
2929
+ amount_satoshis : funding_spent . current_holder_commitment_tx . to_broadcaster_value_sat ( ) ,
2906
2930
confirmation_height : conf_thresh,
2907
2931
source : BalanceSource :: HolderForceClosed ,
2908
2932
} ) ;
2909
2933
}
2910
2934
found_commitment_tx = true ;
2911
- } else if let Some ( prev_holder_commitment_tx) = & us . funding . prev_holder_commitment_tx {
2935
+ } else if let Some ( prev_holder_commitment_tx) = & funding_spent . prev_holder_commitment_tx {
2912
2936
if txid == prev_holder_commitment_tx. trust ( ) . txid ( ) {
2913
2937
walk_htlcs ! ( true , false , holder_commitment_htlcs!( us, PREV_WITH_SOURCES ) . unwrap( ) ) ;
2914
2938
if let Some ( conf_thresh) = pending_commitment_tx_conf_thresh {
@@ -2927,7 +2951,7 @@ impl<Signer: EcdsaChannelSigner> ChannelMonitor<Signer> {
2927
2951
// neither us nor our counterparty misbehaved. At worst we've under-estimated
2928
2952
// the amount we can claim as we'll punish a misbehaving counterparty.
2929
2953
res. push ( Balance :: ClaimableAwaitingConfirmations {
2930
- amount_satoshis : us . funding . current_holder_commitment_tx . to_broadcaster_value_sat ( ) ,
2954
+ amount_satoshis : funding_spent . current_holder_commitment_tx . to_broadcaster_value_sat ( ) ,
2931
2955
confirmation_height : conf_thresh,
2932
2956
source : BalanceSource :: CoopClose ,
2933
2957
} ) ;
@@ -2939,6 +2963,8 @@ impl<Signer: EcdsaChannelSigner> ChannelMonitor<Signer> {
2939
2963
let mut outbound_forwarded_htlc_rounded_msat = 0 ;
2940
2964
let mut inbound_claiming_htlc_rounded_msat = 0 ;
2941
2965
let mut inbound_htlc_rounded_msat = 0 ;
2966
+ // We share the same set of HTLCs across all scopes, so we don't need to check the other
2967
+ // scopes as it'd be redundant.
2942
2968
for ( htlc, source) in holder_commitment_htlcs ! ( us, CURRENT_WITH_SOURCES ) {
2943
2969
let rounded_value_msat = if htlc. transaction_output_index . is_none ( ) {
2944
2970
htlc. amount_msat
@@ -2980,16 +3006,27 @@ impl<Signer: EcdsaChannelSigner> ChannelMonitor<Signer> {
2980
3006
}
2981
3007
}
2982
3008
}
2983
- let to_self_value_sat = us. funding . current_holder_commitment_tx . to_broadcaster_value_sat ( ) ;
3009
+ let balance_candidates = core:: iter:: once ( & us. funding )
3010
+ . chain ( us. pending_funding . iter ( ) )
3011
+ . map ( |funding| {
3012
+ let to_self_value_sat = funding. current_holder_commitment_tx . to_broadcaster_value_sat ( ) ;
3013
+ // In addition to `commit_tx_fee_sat`, this can also include dust HTLCs, any
3014
+ // elided anchors, and the total msat amount rounded down from non-dust HTLCs.
3015
+ let transaction_fee_satoshis = if us. holder_pays_commitment_tx_fee . unwrap_or ( true ) {
3016
+ let transaction = & funding. current_holder_commitment_tx . trust ( ) . built_transaction ( ) . transaction ;
3017
+ let output_value_sat: u64 = transaction. output . iter ( ) . map ( |txout| txout. value . to_sat ( ) ) . sum ( ) ;
3018
+ funding. channel_parameters . channel_value_satoshis - output_value_sat
3019
+ } else {
3020
+ 0
3021
+ } ;
3022
+ HolderCommitmentTransactionBalance {
3023
+ amount_satoshis : to_self_value_sat + claimable_inbound_htlc_value_sat,
3024
+ transaction_fee_satoshis,
3025
+ }
3026
+ } )
3027
+ . collect ( ) ;
2984
3028
res. push ( Balance :: ClaimableOnChannelClose {
2985
- amount_satoshis : to_self_value_sat + claimable_inbound_htlc_value_sat,
2986
- // In addition to `commit_tx_fee_sat`, this can also include dust HTLCs, any elided anchors,
2987
- // and the total msat amount rounded down from non-dust HTLCs
2988
- transaction_fee_satoshis : if us. holder_pays_commitment_tx_fee . unwrap_or ( true ) {
2989
- let transaction = & us. funding . current_holder_commitment_tx . trust ( ) . built_transaction ( ) . transaction ;
2990
- let output_value_sat: u64 = transaction. output . iter ( ) . map ( |txout| txout. value . to_sat ( ) ) . sum ( ) ;
2991
- us. funding . channel_parameters . channel_value_satoshis - output_value_sat
2992
- } else { 0 } ,
3029
+ balance_candidates,
2993
3030
outbound_payment_htlc_rounded_msat,
2994
3031
outbound_forwarded_htlc_rounded_msat,
2995
3032
inbound_claiming_htlc_rounded_msat,
0 commit comments