@@ -777,6 +777,24 @@ pub enum BalanceSource {
777777 Htlc ,
778778}
779779
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 [`HolderCommitmentTransactionBalance::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+
780798/// Details about the balance(s) available for spending once the channel appears on chain.
781799///
782800/// See [`ChannelMonitor::get_claimable_balances`] for more details on when these will or will not
@@ -785,21 +803,26 @@ pub enum BalanceSource {
785803#[ cfg_attr( test, derive( PartialOrd , Ord ) ) ]
786804pub enum Balance {
787805 /// 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).
790807 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.
798814 ///
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 > ,
821+ /// The index within [`Balance::ClaimableOnChannelClose::balance_candidates`] for the
822+ /// balance according to the current onchain state of the channel. This can be helpful when
823+ /// wanting to determine the claimable amount when the holder commitment transaction for the
824+ /// current funding transaction is broadcast and/or confirms.
825+ confirmed_balance_candidate_index : usize ,
803826 /// The amount of millisatoshis which has been burned to fees from HTLCs which are outbound
804827 /// from us and are related to a payment which was sent by us. This is the sum of the
805828 /// millisatoshis part of all HTLCs which are otherwise represented by
@@ -821,7 +844,7 @@ pub enum Balance {
821844 /// to us and for which we know the preimage. This is the sum of the millisatoshis part of
822845 /// all HTLCs which would be represented by [`Balance::ContentiousClaimable`] on channel
823846 /// close, but whose current value is included in
824- /// [`Balance::ClaimableOnChannelClose ::amount_satoshis`], as well as any dust HTLCs which
847+ /// [`HolderCommitmentTransactionBalance ::amount_satoshis`], as well as any dust HTLCs which
825848 /// would otherwise be represented the same.
826849 ///
827850 /// This amount (rounded up to a whole satoshi value) will not be included in the counterparty's
@@ -915,6 +938,13 @@ pub enum Balance {
915938impl Balance {
916939 /// The amount claimable, in satoshis.
917940 ///
941+ /// When the channel has yet to close, this returns the balance we expect to claim from the
942+ /// channel. This may change throughout the lifetime of the channel due to payments, but also
943+ /// due to splicing. If there's a pending splice, this will return the balance we expect to have
944+ /// assuming the latest negotiated splice confirms. However, if one of the negotiated splice
945+ /// transactions has already confirmed but is not yet locked, this reports the corresponding
946+ /// balance for said splice transaction instead.
947+ ///
918948 /// For outbound payments, this excludes the balance from the possible HTLC timeout.
919949 ///
920950 /// For forwarded payments, this includes the balance from the possible HTLC timeout as
@@ -928,7 +958,15 @@ impl Balance {
928958 #[ rustfmt:: skip]
929959 pub fn claimable_amount_satoshis ( & self ) -> u64 {
930960 match self {
931- Balance :: ClaimableOnChannelClose { amount_satoshis, .. } |
961+ Balance :: ClaimableOnChannelClose {
962+ balance_candidates, confirmed_balance_candidate_index, ..
963+ } => {
964+ if * confirmed_balance_candidate_index != 0 {
965+ balance_candidates[ * confirmed_balance_candidate_index] . amount_satoshis
966+ } else {
967+ balance_candidates. last ( ) . map ( |balance| balance. amount_satoshis ) . unwrap_or ( 0 )
968+ }
969+ } ,
932970 Balance :: ClaimableAwaitingConfirmations { amount_satoshis, .. } |
933971 Balance :: ContentiousClaimable { amount_satoshis, .. } |
934972 Balance :: CounterpartyRevokedOutputClaimable { amount_satoshis, .. }
@@ -2675,7 +2713,8 @@ impl<Signer: EcdsaChannelSigner> ChannelMonitorImpl<Signer> {
26752713 debug_assert ! ( htlc_input_idx_opt. is_some( ) ) ;
26762714 BitcoinOutPoint :: new ( * txid, htlc_input_idx_opt. unwrap_or ( 0 ) )
26772715 } else {
2678- debug_assert ! ( !self . channel_type_features( ) . supports_anchors_zero_fee_htlc_tx( ) ) ;
2716+ let funding = get_confirmed_funding_scope ! ( self ) ;
2717+ debug_assert ! ( !funding. channel_type_features( ) . supports_anchors_zero_fee_htlc_tx( ) ) ;
26792718 BitcoinOutPoint :: new ( * txid, 0 )
26802719 }
26812720 } else {
@@ -2837,8 +2876,9 @@ impl<Signer: EcdsaChannelSigner> ChannelMonitor<Signer> {
28372876 }
28382877
28392878 if let Some ( txid) = confirmed_txid {
2879+ let funding_spent = get_confirmed_funding_scope ! ( us) ;
28402880 let mut found_commitment_tx = false ;
2841- if let Some ( counterparty_tx_htlcs) = us . funding . counterparty_claimable_outpoints . get ( & txid) {
2881+ if let Some ( counterparty_tx_htlcs) = funding_spent . counterparty_claimable_outpoints . get ( & txid) {
28422882 // First look for the to_remote output back to us.
28432883 if let Some ( conf_thresh) = pending_commitment_tx_conf_thresh {
28442884 if let Some ( value) = us. onchain_events_awaiting_threshold_conf . iter ( ) . find_map ( |event| {
@@ -2859,7 +2899,7 @@ impl<Signer: EcdsaChannelSigner> ChannelMonitor<Signer> {
28592899 // confirmation with the same height or have never met our dust amount.
28602900 }
28612901 }
2862- if Some ( txid) == us . funding . current_counterparty_commitment_txid || Some ( txid) == us . funding . prev_counterparty_commitment_txid {
2902+ if Some ( txid) == funding_spent . current_counterparty_commitment_txid || Some ( txid) == funding_spent . prev_counterparty_commitment_txid {
28632903 walk_htlcs ! ( false , false , counterparty_tx_htlcs. iter( ) . map( |( a, b) | ( a, b. as_ref( ) . map( |b| & * * b) ) ) ) ;
28642904 } else {
28652905 walk_htlcs ! ( false , true , counterparty_tx_htlcs. iter( ) . map( |( a, b) | ( a, b. as_ref( ) . map( |b| & * * b) ) ) ) ;
@@ -2902,17 +2942,17 @@ impl<Signer: EcdsaChannelSigner> ChannelMonitor<Signer> {
29022942 }
29032943 }
29042944 found_commitment_tx = true ;
2905- } else if txid == us . funding . current_holder_commitment_tx . trust ( ) . txid ( ) {
2945+ } else if txid == funding_spent . current_holder_commitment_tx . trust ( ) . txid ( ) {
29062946 walk_htlcs ! ( true , false , holder_commitment_htlcs!( us, CURRENT_WITH_SOURCES ) ) ;
29072947 if let Some ( conf_thresh) = pending_commitment_tx_conf_thresh {
29082948 res. push ( Balance :: ClaimableAwaitingConfirmations {
2909- amount_satoshis : us . funding . current_holder_commitment_tx . to_broadcaster_value_sat ( ) ,
2949+ amount_satoshis : funding_spent . current_holder_commitment_tx . to_broadcaster_value_sat ( ) ,
29102950 confirmation_height : conf_thresh,
29112951 source : BalanceSource :: HolderForceClosed ,
29122952 } ) ;
29132953 }
29142954 found_commitment_tx = true ;
2915- } else if let Some ( prev_holder_commitment_tx) = & us . funding . prev_holder_commitment_tx {
2955+ } else if let Some ( prev_holder_commitment_tx) = & funding_spent . prev_holder_commitment_tx {
29162956 if txid == prev_holder_commitment_tx. trust ( ) . txid ( ) {
29172957 walk_htlcs ! ( true , false , holder_commitment_htlcs!( us, PREV_WITH_SOURCES ) . unwrap( ) ) ;
29182958 if let Some ( conf_thresh) = pending_commitment_tx_conf_thresh {
@@ -2931,7 +2971,7 @@ impl<Signer: EcdsaChannelSigner> ChannelMonitor<Signer> {
29312971 // neither us nor our counterparty misbehaved. At worst we've under-estimated
29322972 // the amount we can claim as we'll punish a misbehaving counterparty.
29332973 res. push ( Balance :: ClaimableAwaitingConfirmations {
2934- amount_satoshis : us . funding . current_holder_commitment_tx . to_broadcaster_value_sat ( ) ,
2974+ amount_satoshis : funding_spent . current_holder_commitment_tx . to_broadcaster_value_sat ( ) ,
29352975 confirmation_height : conf_thresh,
29362976 source : BalanceSource :: CoopClose ,
29372977 } ) ;
@@ -2943,6 +2983,8 @@ impl<Signer: EcdsaChannelSigner> ChannelMonitor<Signer> {
29432983 let mut outbound_forwarded_htlc_rounded_msat = 0 ;
29442984 let mut inbound_claiming_htlc_rounded_msat = 0 ;
29452985 let mut inbound_htlc_rounded_msat = 0 ;
2986+ // We share the same set of HTLCs across all scopes, so we don't need to check the other
2987+ // scopes as it'd be redundant.
29462988 for ( htlc, source) in holder_commitment_htlcs ! ( us, CURRENT_WITH_SOURCES ) {
29472989 let rounded_value_msat = if htlc. transaction_output_index . is_none ( ) {
29482990 htlc. amount_msat
@@ -2984,16 +3026,40 @@ impl<Signer: EcdsaChannelSigner> ChannelMonitor<Signer> {
29843026 }
29853027 }
29863028 }
2987- let to_self_value_sat = us. funding . current_holder_commitment_tx . to_broadcaster_value_sat ( ) ;
3029+ let balance_candidates = core:: iter:: once ( & us. funding )
3030+ . chain ( us. pending_funding . iter ( ) )
3031+ . map ( |funding| {
3032+ let to_self_value_sat = funding. current_holder_commitment_tx . to_broadcaster_value_sat ( ) ;
3033+ // In addition to `commit_tx_fee_sat`, this can also include dust HTLCs, any
3034+ // elided anchors, and the total msat amount rounded down from non-dust HTLCs.
3035+ let transaction_fee_satoshis = if us. holder_pays_commitment_tx_fee . unwrap_or ( true ) {
3036+ let transaction = & funding. current_holder_commitment_tx . trust ( ) . built_transaction ( ) . transaction ;
3037+ let output_value_sat: u64 = transaction. output . iter ( ) . map ( |txout| txout. value . to_sat ( ) ) . sum ( ) ;
3038+ funding. channel_parameters . channel_value_satoshis - output_value_sat
3039+ } else {
3040+ 0
3041+ } ;
3042+ HolderCommitmentTransactionBalance {
3043+ amount_satoshis : to_self_value_sat + claimable_inbound_htlc_value_sat,
3044+ transaction_fee_satoshis,
3045+ }
3046+ } )
3047+ . collect ( ) ;
3048+ let confirmed_balance_candidate_index = core:: iter:: once ( & us. funding )
3049+ . chain ( us. pending_funding . iter ( ) )
3050+ . enumerate ( )
3051+ . find ( |( _, funding) | {
3052+ us. alternative_funding_confirmed
3053+ . map ( |( funding_txid_confirmed, _) | funding. funding_txid ( ) == funding_txid_confirmed)
3054+ // If `alternative_funding_confirmed` is not set, we can assume the current
3055+ // funding is confirmed.
3056+ . unwrap_or ( true )
3057+ } )
3058+ . map ( |( idx, _) | idx)
3059+ . expect ( "We must have one FundingScope that is confirmed" ) ;
29883060 res. push ( Balance :: ClaimableOnChannelClose {
2989- amount_satoshis : to_self_value_sat + claimable_inbound_htlc_value_sat,
2990- // In addition to `commit_tx_fee_sat`, this can also include dust HTLCs, any elided anchors,
2991- // and the total msat amount rounded down from non-dust HTLCs
2992- transaction_fee_satoshis : if us. holder_pays_commitment_tx_fee . unwrap_or ( true ) {
2993- let transaction = & us. funding . current_holder_commitment_tx . trust ( ) . built_transaction ( ) . transaction ;
2994- let output_value_sat: u64 = transaction. output . iter ( ) . map ( |txout| txout. value . to_sat ( ) ) . sum ( ) ;
2995- us. funding . channel_parameters . channel_value_satoshis - output_value_sat
2996- } else { 0 } ,
3061+ balance_candidates,
3062+ confirmed_balance_candidate_index,
29973063 outbound_payment_htlc_rounded_msat,
29983064 outbound_forwarded_htlc_rounded_msat,
29993065 inbound_claiming_htlc_rounded_msat,
0 commit comments