]> git.bitcoin.ninja Git - rust-lightning/commitdiff
Include rounded msat balances in `Balance::ClaimableOnChannelClose`
authorMatt Corallo <git@bluematt.me>
Tue, 14 Nov 2023 22:19:19 +0000 (22:19 +0000)
committerDuncan Dean <git@dunxen.dev>
Tue, 13 Aug 2024 11:26:57 +0000 (13:26 +0200)
If we're gonna push users towards using `Balance` to determine
their current balances, we really need to provide more information,
including msat balances.

Here we add rounded-out msat balances to the pre-close balance
information

lightning/src/chain/channelmonitor.rs
lightning/src/ln/monitor_tests.rs

index e12873d2f799c377222fb1cc752939cd8e292beb..ac70434c7101473d2c2bbc88f6e943c8028b19e2 100644 (file)
@@ -629,6 +629,32 @@ pub enum Balance {
                /// transaction fee) this value will be zero. For [`ChannelMonitor`]s created prior to LDK
                /// 0.0.124, the channel is always treated as outbound (and thus this value is never zero).
                transaction_fee_satoshis: u64,
+               /// The amount of millisatoshis which has been burned to fees from HTLCs which are outbound
+               /// from us and are related to a payment which was sent by us. This is the sum of the
+               /// millisatoshis part of all HTLCs which are otherwise represented by
+               /// [`Balance::MaybeTimeoutClaimableHTLC`] with their
+               /// [`Balance::MaybeTimeoutClaimableHTLC::outbound_payment`] flag set, as well as any dust
+               /// HTLCs which would otherwise be represented the same.
+               outbound_payment_htlc_rounded_msat: u64,
+               /// The amount of millisatoshis which has been burned to fees from HTLCs which are outbound
+               /// from us and are related to a forwarded HTLC. This is the sum of the millisatoshis part
+               /// of all HTLCs which are otherwise represented by [`Balance::MaybeTimeoutClaimableHTLC`]
+               /// with their [`Balance::MaybeTimeoutClaimableHTLC::outbound_payment`] flag *not* set, as
+               /// well as any dust HTLCs which would otherwise be represented the same.
+               outbound_forwarded_htlc_rounded_msat: u64,
+               /// The amount of millisatoshis which has been burned to fees from HTLCs which are inbound
+               /// to us and for which we know the preimage. This is the sum of the millisatoshis part of
+               /// all HTLCs which would be represented by [`Balance::ContentiousClaimable`] on channel
+               /// close, but whose current value is included in
+               /// [`Balance::ClaimableOnChannelClose::amount_satoshis`], as well as any dust HTLCs which
+               /// would otherwise be represented the same.
+               inbound_claiming_htlc_rounded_msat: u64,
+               /// The amount of millisatoshis which has been burned to fees from HTLCs which are inbound
+               /// to us and for which we do not know the preimage. This is the sum of the millisatoshis
+               /// part of all HTLCs which would be represented by [`Balance::MaybePreimageClaimableHTLC`]
+               /// on channel close, as well as any dust HTLCs which would otherwise be represented the
+               /// same.
+               inbound_htlc_rounded_msat: u64,
        },
        /// The channel has been closed, and the given balance is ours but awaiting confirmations until
        /// we consider it spendable.
@@ -2320,10 +2346,17 @@ impl<Signer: EcdsaChannelSigner> ChannelMonitor<Signer> {
                } else {
                        let mut claimable_inbound_htlc_value_sat = 0;
                        let mut nondust_htlc_count = 0;
+                       let mut outbound_payment_htlc_rounded_msat = 0;
+                       let mut outbound_forwarded_htlc_rounded_msat = 0;
+                       let mut inbound_claiming_htlc_rounded_msat = 0;
+                       let mut inbound_htlc_rounded_msat = 0;
                        for (htlc, _, source) in us.current_holder_commitment_tx.htlc_outputs.iter() {
                                if htlc.transaction_output_index.is_some() {
                                        nondust_htlc_count += 1;
-                               } else { continue; }
+                               }
+                               let rounded_value_msat = if htlc.transaction_output_index.is_none() {
+                                       htlc.amount_msat
+                               } else { htlc.amount_msat % 1000 };
                                if htlc.offered {
                                        let outbound_payment = match source {
                                                None => {
@@ -2333,22 +2366,35 @@ impl<Signer: EcdsaChannelSigner> ChannelMonitor<Signer> {
                                                Some(HTLCSource::PreviousHopData(_)) => false,
                                                Some(HTLCSource::OutboundRoute { .. }) => true,
                                        };
-                                       res.push(Balance::MaybeTimeoutClaimableHTLC {
-                                               amount_satoshis: htlc.amount_msat / 1000,
-                                               claimable_height: htlc.cltv_expiry,
-                                               payment_hash: htlc.payment_hash,
-                                               outbound_payment,
-                                       });
+                                       if outbound_payment {
+                                               outbound_payment_htlc_rounded_msat += rounded_value_msat;
+                                       } else {
+                                               outbound_forwarded_htlc_rounded_msat += rounded_value_msat;
+                                       }
+                                       if htlc.transaction_output_index.is_some() {
+                                               res.push(Balance::MaybeTimeoutClaimableHTLC {
+                                                       amount_satoshis: htlc.amount_msat / 1000,
+                                                       claimable_height: htlc.cltv_expiry,
+                                                       payment_hash: htlc.payment_hash,
+                                                       outbound_payment,
+                                               });
+                                       }
                                } else if us.payment_preimages.get(&htlc.payment_hash).is_some() {
-                                       claimable_inbound_htlc_value_sat += htlc.amount_msat / 1000;
+                                       inbound_claiming_htlc_rounded_msat += rounded_value_msat;
+                                       if htlc.transaction_output_index.is_some() {
+                                               claimable_inbound_htlc_value_sat += htlc.amount_msat / 1000;
+                                       }
                                } else {
-                                       // As long as the HTLC is still in our latest commitment state, treat
-                                       // it as potentially claimable, even if it has long-since expired.
-                                       res.push(Balance::MaybePreimageClaimableHTLC {
-                                               amount_satoshis: htlc.amount_msat / 1000,
-                                               expiry_height: htlc.cltv_expiry,
-                                               payment_hash: htlc.payment_hash,
-                                       });
+                                       inbound_htlc_rounded_msat += rounded_value_msat;
+                                       if htlc.transaction_output_index.is_some() {
+                                               // As long as the HTLC is still in our latest commitment state, treat
+                                               // it as potentially claimable, even if it has long-since expired.
+                                               res.push(Balance::MaybePreimageClaimableHTLC {
+                                                       amount_satoshis: htlc.amount_msat / 1000,
+                                                       expiry_height: htlc.cltv_expiry,
+                                                       payment_hash: htlc.payment_hash,
+                                               });
+                                       }
                                }
                        }
                        res.push(Balance::ClaimableOnChannelClose {
@@ -2358,6 +2404,10 @@ impl<Signer: EcdsaChannelSigner> ChannelMonitor<Signer> {
                                                us.current_holder_commitment_tx.feerate_per_kw, nondust_htlc_count,
                                                us.onchain_tx_handler.channel_type_features())
                                } else { 0 },
+                               outbound_payment_htlc_rounded_msat,
+                               outbound_forwarded_htlc_rounded_msat,
+                               inbound_claiming_htlc_rounded_msat,
+                               inbound_htlc_rounded_msat,
                        });
                }
 
index 757ca41e1b902f2abdd8c4017122bf84f72dcc43..8af3c84fb1700105f31b73788c196c3e1aedd7e1 100644 (file)
@@ -242,9 +242,19 @@ fn do_chanmon_claim_value_coop_close(anchors: bool) {
        assert_eq!(vec![Balance::ClaimableOnChannelClose {
                        amount_satoshis: 1_000_000 - 1_000 - commitment_tx_fee - anchor_outputs_value,
                        transaction_fee_satoshis: commitment_tx_fee,
+                       outbound_payment_htlc_rounded_msat: 0,
+                       outbound_forwarded_htlc_rounded_msat: 0,
+                       inbound_claiming_htlc_rounded_msat: 0,
+                       inbound_htlc_rounded_msat: 0,
                }],
                nodes[0].chain_monitor.chain_monitor.get_monitor(funding_outpoint).unwrap().get_claimable_balances());
-       assert_eq!(vec![Balance::ClaimableOnChannelClose { amount_satoshis: 1_000, transaction_fee_satoshis: 0 }],
+       assert_eq!(vec![Balance::ClaimableOnChannelClose {
+                       amount_satoshis: 1_000, transaction_fee_satoshis: 0,
+                       outbound_payment_htlc_rounded_msat: 0,
+                       outbound_forwarded_htlc_rounded_msat: 0,
+                       inbound_claiming_htlc_rounded_msat: 0,
+                       inbound_htlc_rounded_msat: 0,
+               }],
                nodes[1].chain_monitor.chain_monitor.get_monitor(funding_outpoint).unwrap().get_claimable_balances());
 
        nodes[0].node.close_channel(&chan_id, &nodes[1].node.get_our_node_id()).unwrap();
@@ -443,11 +453,19 @@ fn do_test_claim_value_force_close(anchors: bool, prev_commitment_tx: bool) {
        assert_eq!(sorted_vec(vec![Balance::ClaimableOnChannelClose {
                        amount_satoshis: 1_000_000 - 3_000 - 4_000 - 1_000 - 3 - commitment_tx_fee - anchor_outputs_value,
                        transaction_fee_satoshis: commitment_tx_fee,
+                       outbound_payment_htlc_rounded_msat: 3000,
+                       outbound_forwarded_htlc_rounded_msat: 0,
+                       inbound_claiming_htlc_rounded_msat: 0,
+                       inbound_htlc_rounded_msat: 0,
                }, sent_htlc_balance.clone(), sent_htlc_timeout_balance.clone()]),
                sorted_vec(nodes[0].chain_monitor.chain_monitor.get_monitor(funding_outpoint).unwrap().get_claimable_balances()));
        assert_eq!(sorted_vec(vec![Balance::ClaimableOnChannelClose {
                        amount_satoshis: 1_000,
                        transaction_fee_satoshis: 0,
+                       outbound_payment_htlc_rounded_msat: 0,
+                       outbound_forwarded_htlc_rounded_msat: 0,
+                       inbound_claiming_htlc_rounded_msat: 0,
+                       inbound_htlc_rounded_msat: 3000,
                }, received_htlc_balance.clone(), received_htlc_timeout_balance.clone()]),
                sorted_vec(nodes[1].chain_monitor.chain_monitor.get_monitor(funding_outpoint).unwrap().get_claimable_balances()));
 
@@ -495,6 +513,10 @@ fn do_test_claim_value_force_close(anchors: bool, prev_commitment_tx: bool) {
                                commitment_tx_fee - // The commitment transaction fee with two HTLC outputs
                                anchor_outputs_value, // The anchor outputs value in satoshis
                        transaction_fee_satoshis: commitment_tx_fee,
+                       outbound_payment_htlc_rounded_msat: 3000,
+                       outbound_forwarded_htlc_rounded_msat: 0,
+                       inbound_claiming_htlc_rounded_msat: 0,
+                       inbound_htlc_rounded_msat: 0,
                }, sent_htlc_timeout_balance.clone()];
        if !prev_commitment_tx {
                a_expected_balances.push(sent_htlc_balance.clone());
@@ -504,6 +526,10 @@ fn do_test_claim_value_force_close(anchors: bool, prev_commitment_tx: bool) {
        assert_eq!(vec![Balance::ClaimableOnChannelClose {
                        amount_satoshis: 1_000 + 3_000 + 4_000,
                        transaction_fee_satoshis: 0,
+                       outbound_payment_htlc_rounded_msat: 0,
+                       outbound_forwarded_htlc_rounded_msat: 0,
+                       inbound_claiming_htlc_rounded_msat: 3000,
+                       inbound_htlc_rounded_msat: 0,
                }],
                nodes[1].chain_monitor.chain_monitor.get_monitor(funding_outpoint).unwrap().get_claimable_balances());
 
@@ -987,12 +1013,20 @@ fn test_no_preimage_inbound_htlc_balances() {
        assert_eq!(sorted_vec(vec![Balance::ClaimableOnChannelClose {
                        amount_satoshis: 1_000_000 - 500_000 - 10_000 - commitment_tx_fee,
                        transaction_fee_satoshis: commitment_tx_fee,
+                       outbound_payment_htlc_rounded_msat: 0,
+                       outbound_forwarded_htlc_rounded_msat: 0,
+                       inbound_claiming_htlc_rounded_msat: 0,
+                       inbound_htlc_rounded_msat: 0,
                }, a_received_htlc_balance.clone(), a_sent_htlc_balance.clone()]),
                sorted_vec(nodes[0].chain_monitor.chain_monitor.get_monitor(funding_outpoint).unwrap().get_claimable_balances()));
 
        assert_eq!(sorted_vec(vec![Balance::ClaimableOnChannelClose {
                        amount_satoshis: 500_000 - 20_000,
                        transaction_fee_satoshis: 0,
+                       outbound_payment_htlc_rounded_msat: 0,
+                       outbound_forwarded_htlc_rounded_msat: 0,
+                       inbound_claiming_htlc_rounded_msat: 0,
+                       inbound_htlc_rounded_msat: 0,
                }, b_received_htlc_balance.clone(), b_sent_htlc_balance.clone()]),
                sorted_vec(nodes[1].chain_monitor.chain_monitor.get_monitor(funding_outpoint).unwrap().get_claimable_balances()));
 
@@ -1272,6 +1306,10 @@ fn do_test_revoked_counterparty_commitment_balances(anchors: bool, confirm_htlc_
        assert_eq!(sorted_vec(vec![Balance::ClaimableOnChannelClose {
                        amount_satoshis: 100_000 - 5_000 - 4_000 - 3 - 2_000 + 3_000,
                        transaction_fee_satoshis: 0,
+                       outbound_payment_htlc_rounded_msat: 3000,
+                       outbound_forwarded_htlc_rounded_msat: 0,
+                       inbound_claiming_htlc_rounded_msat: 0,
+                       inbound_htlc_rounded_msat: 0,
                }, Balance::MaybeTimeoutClaimableHTLC {
                        amount_satoshis: 2_000,
                        claimable_height: missing_htlc_cltv_timeout,
@@ -1826,6 +1864,10 @@ fn do_test_revoked_counterparty_aggregated_claims(anchors: bool) {
        assert_eq!(sorted_vec(vec![Balance::ClaimableOnChannelClose {
                        amount_satoshis: 100_000 - 4_000 - 3_000,
                        transaction_fee_satoshis: 0,
+                       outbound_payment_htlc_rounded_msat: 0,
+                       outbound_forwarded_htlc_rounded_msat: 0,
+                       inbound_claiming_htlc_rounded_msat: 0,
+                       inbound_htlc_rounded_msat: 0,
                }, Balance::MaybeTimeoutClaimableHTLC {
                        amount_satoshis: 4_000,
                        claimable_height: htlc_cltv_timeout,