From b6a7baac1ca98f27755918a8a23869905f1b7b88 Mon Sep 17 00:00:00 2001 From: Matt Corallo Date: Thu, 28 Sep 2023 23:02:26 +0000 Subject: [PATCH 1/9] Include an `outbound_payment` flag in `MaybeTimeoutClaimableHTLC` When the user is fetching their current balances after forwarding a payment (before it clears), they'll see a `MaybePreimageClaimableHTLC` and a `MaybeTimeoutClaimableHTLC` but if they sum up their balance using `Balance::claimable_amount_satoshis` neither will be included. Obviously, exactly one of the two balances should be included - one of the two resolutions should happen in our favor. This causes our visible balance to fluctuate up and down by the full value of any HTLCs we're in the middle of forwarding, which is incredibly confusing to see. If we want to stop the fluctuations, we need to pick one of the two balances to include. The obvious candidate is `MaybeTimeoutClaimableHTLC` as it is the lower of the two, and represents our balance without the fee we'd receive from the forward. Sadly, if we always include it, we'll end up also including any HTLCs which we've sent but which haven't yet been claimed by their recipient, which is the wrong behavior. Luckily, we have access to the `Option` while walking HTLCs, which allows us to add an `outbound_payment` flag to `MaybeTimeoutClaimableHTLC`. This allows us to only include forwarded payments in `claimable_amount_satoshis`. Sadly, even with this in place our balance still fluctuates by the changes in the commitment transaction fees we have to pay during forwarding, but addressing that is left for later. --- lightning/src/chain/channelmonitor.rs | 51 ++++++++++++++++++++------- lightning/src/ln/monitor_tests.rs | 11 ++++++ 2 files changed, 49 insertions(+), 13 deletions(-) diff --git a/lightning/src/chain/channelmonitor.rs b/lightning/src/chain/channelmonitor.rs index af0f56d882a..3845328cda4 100644 --- a/lightning/src/chain/channelmonitor.rs +++ b/lightning/src/chain/channelmonitor.rs @@ -620,6 +620,10 @@ pub enum Balance { claimable_height: u32, /// The payment hash whose preimage our counterparty needs to claim this HTLC. payment_hash: PaymentHash, + /// Whether this HTLC represents a payment which was sent outbound from us. Otherwise it + /// represents an HTLC which was forwarded (and should, thus, have a corresponding inbound + /// edge on another channel). + outbound_payment: bool, }, /// HTLCs which we received from our counterparty which are claimable with a preimage which we /// do not currently have. This will only be claimable if we receive the preimage from the node @@ -662,9 +666,9 @@ impl Balance { Balance::ContentiousClaimable { amount_satoshis, .. }| Balance::CounterpartyRevokedOutputClaimable { amount_satoshis, .. } => *amount_satoshis, - Balance::MaybeTimeoutClaimableHTLC { .. }| - Balance::MaybePreimageClaimableHTLC { .. } - => 0, + Balance::MaybeTimeoutClaimableHTLC { amount_satoshis, outbound_payment, .. } + => if *outbound_payment { 0 } else { *amount_satoshis }, + Balance::MaybePreimageClaimableHTLC { .. } => 0, } } } @@ -1719,9 +1723,10 @@ impl ChannelMonitor { impl ChannelMonitorImpl { /// Helper for get_claimable_balances which does the work for an individual HTLC, generating up /// to one `Balance` for the HTLC. - fn get_htlc_balance(&self, htlc: &HTLCOutputInCommitment, holder_commitment: bool, - counterparty_revoked_commitment: bool, confirmed_txid: Option) - -> Option { + fn get_htlc_balance(&self, htlc: &HTLCOutputInCommitment, source: Option<&HTLCSource>, + holder_commitment: bool, counterparty_revoked_commitment: bool, + confirmed_txid: Option + ) -> Option { let htlc_commitment_tx_output_idx = if let Some(v) = htlc.transaction_output_index { v } else { return None; }; @@ -1858,10 +1863,19 @@ impl ChannelMonitorImpl { confirmation_height: conf_thresh, }); } else { + let outbound_payment = match source { + None => { + debug_assert!(false, "Outbound HTLCs should have a source"); + true + }, + Some(&HTLCSource::PreviousHopData(_)) => false, + Some(&HTLCSource::OutboundRoute { .. }) => true, + }; return Some(Balance::MaybeTimeoutClaimableHTLC { amount_satoshis: htlc.amount_msat / 1000, claimable_height: htlc.cltv_expiry, payment_hash: htlc.payment_hash, + outbound_payment, }); } } else if let Some(payment_preimage) = self.payment_preimages.get(&htlc.payment_hash) { @@ -1934,10 +1948,12 @@ impl ChannelMonitor { macro_rules! walk_htlcs { ($holder_commitment: expr, $counterparty_revoked_commitment: expr, $htlc_iter: expr) => { - for htlc in $htlc_iter { + for (htlc, source) in $htlc_iter { if htlc.transaction_output_index.is_some() { - if let Some(bal) = us.get_htlc_balance(htlc, $holder_commitment, $counterparty_revoked_commitment, confirmed_txid) { + if let Some(bal) = us.get_htlc_balance( + htlc, source, $holder_commitment, $counterparty_revoked_commitment, confirmed_txid + ) { res.push(bal); } } @@ -1968,9 +1984,9 @@ impl ChannelMonitor { } } if Some(txid) == us.current_counterparty_commitment_txid || Some(txid) == us.prev_counterparty_commitment_txid { - walk_htlcs!(false, false, counterparty_tx_htlcs.iter().map(|(a, _)| a)); + walk_htlcs!(false, false, counterparty_tx_htlcs.iter().map(|(a, b)| (a, b.as_ref().map(|b| &**b)))); } else { - walk_htlcs!(false, true, counterparty_tx_htlcs.iter().map(|(a, _)| a)); + walk_htlcs!(false, true, counterparty_tx_htlcs.iter().map(|(a, b)| (a, b.as_ref().map(|b| &**b)))); // The counterparty broadcasted a revoked state! // Look for any StaticOutputs first, generating claimable balances for those. // If any match the confirmed counterparty revoked to_self output, skip @@ -2010,7 +2026,7 @@ impl ChannelMonitor { } found_commitment_tx = true; } else if txid == us.current_holder_commitment_tx.txid { - walk_htlcs!(true, false, us.current_holder_commitment_tx.htlc_outputs.iter().map(|(a, _, _)| a)); + walk_htlcs!(true, false, us.current_holder_commitment_tx.htlc_outputs.iter().map(|(a, _, c)| (a, c.as_ref()))); if let Some(conf_thresh) = pending_commitment_tx_conf_thresh { res.push(Balance::ClaimableAwaitingConfirmations { amount_satoshis: us.current_holder_commitment_tx.to_self_value_sat, @@ -2020,7 +2036,7 @@ impl ChannelMonitor { found_commitment_tx = true; } else if let Some(prev_commitment) = &us.prev_holder_signed_commitment_tx { if txid == prev_commitment.txid { - walk_htlcs!(true, false, prev_commitment.htlc_outputs.iter().map(|(a, _, _)| a)); + walk_htlcs!(true, false, prev_commitment.htlc_outputs.iter().map(|(a, _, c)| (a, c.as_ref()))); if let Some(conf_thresh) = pending_commitment_tx_conf_thresh { res.push(Balance::ClaimableAwaitingConfirmations { amount_satoshis: prev_commitment.to_self_value_sat, @@ -2043,13 +2059,22 @@ impl ChannelMonitor { } } else { let mut claimable_inbound_htlc_value_sat = 0; - for (htlc, _, _) in us.current_holder_commitment_tx.htlc_outputs.iter() { + for (htlc, _, source) in us.current_holder_commitment_tx.htlc_outputs.iter() { if htlc.transaction_output_index.is_none() { continue; } if htlc.offered { + let outbound_payment = match source { + None => { + debug_assert!(false, "Outbound HTLCs should have a source"); + true + }, + 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, }); } else if us.payment_preimages.get(&htlc.payment_hash).is_some() { claimable_inbound_htlc_value_sat += htlc.amount_msat / 1000; diff --git a/lightning/src/ln/monitor_tests.rs b/lightning/src/ln/monitor_tests.rs index 60caed4dbdc..685ec75c7e9 100644 --- a/lightning/src/ln/monitor_tests.rs +++ b/lightning/src/ln/monitor_tests.rs @@ -346,11 +346,13 @@ fn do_test_claim_value_force_close(anchors: bool, prev_commitment_tx: bool) { amount_satoshis: 3_000, claimable_height: htlc_cltv_timeout, payment_hash, + outbound_payment: true, }; let sent_htlc_timeout_balance = Balance::MaybeTimeoutClaimableHTLC { amount_satoshis: 4_000, claimable_height: htlc_cltv_timeout, payment_hash: timeout_payment_hash, + outbound_payment: true, }; let received_htlc_balance = Balance::MaybePreimageClaimableHTLC { amount_satoshis: 3_000, @@ -746,11 +748,13 @@ fn do_test_balances_on_local_commitment_htlcs(anchors: bool) { amount_satoshis: 10_000, claimable_height: htlc_cltv_timeout, payment_hash, + outbound_payment: true, }; let htlc_balance_unknown_preimage = Balance::MaybeTimeoutClaimableHTLC { amount_satoshis: 20_000, claimable_height: htlc_cltv_timeout, payment_hash: payment_hash_2, + outbound_payment: true, }; let commitment_tx_fee = chan_feerate * @@ -893,6 +897,7 @@ fn test_no_preimage_inbound_htlc_balances() { amount_satoshis: 10_000, claimable_height: htlc_cltv_timeout, payment_hash: to_b_failed_payment_hash, + outbound_payment: true, }; let a_received_htlc_balance = Balance::MaybePreimageClaimableHTLC { amount_satoshis: 20_000, @@ -908,6 +913,7 @@ fn test_no_preimage_inbound_htlc_balances() { amount_satoshis: 20_000, claimable_height: htlc_cltv_timeout, payment_hash: to_a_failed_payment_hash, + outbound_payment: true, }; // Both A and B will have an HTLC that's claimable on timeout and one that's claimable if they @@ -1204,14 +1210,17 @@ fn do_test_revoked_counterparty_commitment_balances(anchors: bool, confirm_htlc_ amount_satoshis: 2_000, claimable_height: missing_htlc_cltv_timeout, payment_hash: missing_htlc_payment_hash, + outbound_payment: true, }, Balance::MaybeTimeoutClaimableHTLC { amount_satoshis: 4_000, claimable_height: htlc_cltv_timeout, payment_hash: timeout_payment_hash, + outbound_payment: true, }, Balance::MaybeTimeoutClaimableHTLC { amount_satoshis: 5_000, claimable_height: live_htlc_cltv_timeout, payment_hash: live_payment_hash, + outbound_payment: true, }]), sorted_vec(nodes[1].chain_monitor.chain_monitor.get_monitor(funding_outpoint).unwrap().get_claimable_balances())); @@ -1754,10 +1763,12 @@ fn do_test_revoked_counterparty_aggregated_claims(anchors: bool) { amount_satoshis: 4_000, claimable_height: htlc_cltv_timeout, payment_hash: revoked_payment_hash, + outbound_payment: true, }, Balance::MaybeTimeoutClaimableHTLC { amount_satoshis: 3_000, claimable_height: htlc_cltv_timeout, payment_hash: claimed_payment_hash, + outbound_payment: true, }]), sorted_vec(nodes[1].chain_monitor.chain_monitor.get_monitor(funding_outpoint).unwrap().get_claimable_balances())); From 5e628d6f61f457506d01e0d346d4296a7d92cd85 Mon Sep 17 00:00:00 2001 From: Matt Corallo Date: Fri, 29 Sep 2023 17:10:40 +0000 Subject: [PATCH 2/9] Drop `chan_utils` self-import There's no reason to `use` a module within that module to refer to that module... --- lightning/src/ln/chan_utils.rs | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/lightning/src/ln/chan_utils.rs b/lightning/src/ln/chan_utils.rs index 1c068025b8f..0a777710e97 100644 --- a/lightning/src/ln/chan_utils.rs +++ b/lightning/src/ln/chan_utils.rs @@ -37,7 +37,6 @@ use bitcoin::PublicKey as BitcoinPublicKey; use crate::io; use crate::prelude::*; use core::cmp; -use crate::ln::chan_utils; use crate::util::transaction_utils::sort_outputs; use crate::ln::channel::{INITIAL_COMMITMENT_NUMBER, ANCHOR_OUTPUT_VALUE_SATOSHI}; use core::ops::Deref; @@ -843,7 +842,7 @@ pub fn get_anchor_redeemscript(funding_pubkey: &PublicKey) -> Script { /// Locates the output with an anchor script paying to `funding_pubkey` within `commitment_tx`. pub(crate) fn get_anchor_output<'a>(commitment_tx: &'a Transaction, funding_pubkey: &PublicKey) -> Option<(u32, &'a TxOut)> { - let anchor_script = chan_utils::get_anchor_redeemscript(funding_pubkey).to_v0_p2wsh(); + let anchor_script = get_anchor_redeemscript(funding_pubkey).to_v0_p2wsh(); commitment_tx.output.iter().enumerate() .find(|(_, txout)| txout.script_pubkey == anchor_script) .map(|(idx, txout)| (idx as u32, txout)) @@ -851,7 +850,7 @@ pub(crate) fn get_anchor_output<'a>(commitment_tx: &'a Transaction, funding_pubk /// Returns the witness required to satisfy and spend an anchor input. pub fn build_anchor_input_witness(funding_key: &PublicKey, funding_sig: &Signature) -> Witness { - let anchor_redeem_script = chan_utils::get_anchor_redeemscript(funding_key); + let anchor_redeem_script = get_anchor_redeemscript(funding_key); let mut ret = Witness::new(); ret.push_bitcoin_signature(&funding_sig.serialize_der(), EcdsaSighashType::All); ret.push(anchor_redeem_script.as_bytes()); @@ -1533,7 +1532,7 @@ impl CommitmentTransaction { let mut htlcs = Vec::with_capacity(htlcs_with_aux.len()); for (htlc, _) in htlcs_with_aux { - let script = chan_utils::get_htlc_redeemscript(&htlc, &channel_parameters.channel_type_features(), &keys); + let script = get_htlc_redeemscript(&htlc, &channel_parameters.channel_type_features(), &keys); let txout = TxOut { script_pubkey: script.to_v0_p2wsh(), value: htlc.amount_msat / 1000, @@ -1756,7 +1755,7 @@ impl<'a> TrustedCommitmentTransaction<'a> { &self.inner.htlcs[htlc_index], &self.channel_type_features, &keys.broadcaster_htlc_key, &keys.countersignatory_htlc_key, &keys.revocation_key ); - chan_utils::build_htlc_input_witness( + build_htlc_input_witness( signature, counterparty_signature, preimage, &htlc_redeemscript, &self.channel_type_features, ) } From adc77df5b3c427b0e3322a59fc11e861c323ee79 Mon Sep 17 00:00:00 2001 From: Matt Corallo Date: Fri, 29 Sep 2023 17:26:01 +0000 Subject: [PATCH 3/9] Move commitment tx fee calculation helpers to `chan_utils` These don't really belong in `channel` as they're now used in other parts of the codebase. --- lightning/src/ln/chan_utils.rs | 20 ++++++++++ lightning/src/ln/channel.rs | 58 +++++++++------------------- lightning/src/ln/functional_tests.rs | 4 +- lightning/src/ln/monitor_tests.rs | 23 +++++------ 4 files changed, 53 insertions(+), 52 deletions(-) diff --git a/lightning/src/ln/chan_utils.rs b/lightning/src/ln/chan_utils.rs index 0a777710e97..6304d288964 100644 --- a/lightning/src/ln/chan_utils.rs +++ b/lightning/src/ln/chan_utils.rs @@ -163,6 +163,26 @@ impl HTLCClaim { } } +#[cfg(not(test))] +const COMMITMENT_TX_WEIGHT_PER_HTLC: u64 = 172; +#[cfg(test)] +pub const COMMITMENT_TX_WEIGHT_PER_HTLC: u64 = 172; + +pub(crate) fn commitment_tx_base_weight(channel_type_features: &ChannelTypeFeatures) -> u64 { + const COMMITMENT_TX_BASE_WEIGHT: u64 = 724; + const COMMITMENT_TX_BASE_ANCHOR_WEIGHT: u64 = 1124; + if channel_type_features.supports_anchors_zero_fee_htlc_tx() { COMMITMENT_TX_BASE_ANCHOR_WEIGHT } else { COMMITMENT_TX_BASE_WEIGHT } +} + +/// Get the fee cost of a commitment tx with a given number of HTLC outputs. +/// Note that num_htlcs should not include dust HTLCs. +pub(crate) fn commit_tx_fee_sat(feerate_per_kw: u32, num_htlcs: usize, channel_type_features: &ChannelTypeFeatures) -> u64 { + feerate_per_kw as u64 * + (commitment_tx_base_weight(channel_type_features) + + num_htlcs as u64 * COMMITMENT_TX_WEIGHT_PER_HTLC) + / 1000 +} + // Various functions for key derivation and transaction creation for use within channels. Primarily // used in Channel and ChannelMonitor. diff --git a/lightning/src/ln/channel.rs b/lightning/src/ln/channel.rs index 87f3c43aab0..ff78c2636f3 100644 --- a/lightning/src/ln/channel.rs +++ b/lightning/src/ln/channel.rs @@ -29,7 +29,13 @@ use crate::ln::msgs; use crate::ln::msgs::DecodeError; use crate::ln::script::{self, ShutdownScript}; use crate::ln::channelmanager::{self, CounterpartyForwardingInfo, PendingHTLCStatus, HTLCSource, SentHTLCId, HTLCFailureMsg, PendingHTLCInfo, RAACommitmentOrder, BREAKDOWN_TIMEOUT, MIN_CLTV_EXPIRY_DELTA, MAX_LOCAL_BREAKDOWN_TIMEOUT, ChannelShutdownState}; -use crate::ln::chan_utils::{CounterpartyCommitmentSecrets, TxCreationKeys, HTLCOutputInCommitment, htlc_success_tx_weight, htlc_timeout_tx_weight, make_funding_redeemscript, ChannelPublicKeys, CommitmentTransaction, HolderCommitmentTransaction, ChannelTransactionParameters, CounterpartyChannelTransactionParameters, MAX_HTLCS, get_commitment_transaction_number_obscure_factor, ClosingTransaction}; +use crate::ln::chan_utils::{ + CounterpartyCommitmentSecrets, TxCreationKeys, HTLCOutputInCommitment, htlc_success_tx_weight, + htlc_timeout_tx_weight, make_funding_redeemscript, ChannelPublicKeys, CommitmentTransaction, + HolderCommitmentTransaction, ChannelTransactionParameters, + CounterpartyChannelTransactionParameters, MAX_HTLCS, commit_tx_fee_sat, + get_commitment_transaction_number_obscure_factor, ClosingTransaction +}; use crate::ln::chan_utils; use crate::ln::onion_utils::HTLCFailReason; use crate::chain::BestBlock; @@ -327,17 +333,6 @@ pub const INITIAL_COMMITMENT_NUMBER: u64 = (1 << 48) - 1; pub const DEFAULT_MAX_HTLCS: u16 = 50; -pub(crate) fn commitment_tx_base_weight(channel_type_features: &ChannelTypeFeatures) -> u64 { - const COMMITMENT_TX_BASE_WEIGHT: u64 = 724; - const COMMITMENT_TX_BASE_ANCHOR_WEIGHT: u64 = 1124; - if channel_type_features.supports_anchors_zero_fee_htlc_tx() { COMMITMENT_TX_BASE_ANCHOR_WEIGHT } else { COMMITMENT_TX_BASE_WEIGHT } -} - -#[cfg(not(test))] -const COMMITMENT_TX_WEIGHT_PER_HTLC: u64 = 172; -#[cfg(test)] -pub const COMMITMENT_TX_WEIGHT_PER_HTLC: u64 = 172; - pub const ANCHOR_OUTPUT_VALUE_SATOSHI: u64 = 330; /// The percentage of the channel value `holder_max_htlc_value_in_flight_msat` used to be set to, @@ -1918,12 +1913,12 @@ impl ChannelContext where SP::Target: SignerProvider { } let num_htlcs = included_htlcs + addl_htlcs; - let res = commit_tx_fee_msat(context.feerate_per_kw, num_htlcs, &context.channel_type); + let res = commit_tx_fee_sat(context.feerate_per_kw, num_htlcs, &context.channel_type) * 1000; #[cfg(any(test, fuzzing))] { let mut fee = res; if fee_spike_buffer_htlc.is_some() { - fee = commit_tx_fee_msat(context.feerate_per_kw, num_htlcs - 1, &context.channel_type); + fee = commit_tx_fee_sat(context.feerate_per_kw, num_htlcs - 1, &context.channel_type) * 1000; } let total_pending_htlcs = context.pending_inbound_htlcs.len() + context.pending_outbound_htlcs.len() + context.holding_cell_htlc_updates.len(); @@ -2009,12 +2004,12 @@ impl ChannelContext where SP::Target: SignerProvider { } let num_htlcs = included_htlcs + addl_htlcs; - let res = commit_tx_fee_msat(context.feerate_per_kw, num_htlcs, &context.channel_type); + let res = commit_tx_fee_sat(context.feerate_per_kw, num_htlcs, &context.channel_type) * 1000; #[cfg(any(test, fuzzing))] { let mut fee = res; if fee_spike_buffer_htlc.is_some() { - fee = commit_tx_fee_msat(context.feerate_per_kw, num_htlcs - 1, &context.channel_type); + fee = commit_tx_fee_sat(context.feerate_per_kw, num_htlcs - 1, &context.channel_type) * 1000; } let total_pending_htlcs = context.pending_inbound_htlcs.len() + context.pending_outbound_htlcs.len(); let commitment_tx_info = CommitmentTxInfoCached { @@ -2229,21 +2224,6 @@ pub(crate) fn get_legacy_default_holder_selected_channel_reserve_satoshis(channe cmp::min(channel_value_satoshis, cmp::max(q, 1000)) } -// Get the fee cost in SATS of a commitment tx with a given number of HTLC outputs. -// Note that num_htlcs should not include dust HTLCs. -#[inline] -fn commit_tx_fee_sat(feerate_per_kw: u32, num_htlcs: usize, channel_type_features: &ChannelTypeFeatures) -> u64 { - feerate_per_kw as u64 * (commitment_tx_base_weight(channel_type_features) + num_htlcs as u64 * COMMITMENT_TX_WEIGHT_PER_HTLC) / 1000 -} - -// Get the fee cost in MSATS of a commitment tx with a given number of HTLC outputs. -// Note that num_htlcs should not include dust HTLCs. -pub(crate) fn commit_tx_fee_msat(feerate_per_kw: u32, num_htlcs: usize, channel_type_features: &ChannelTypeFeatures) -> u64 { - // Note that we need to divide before multiplying to round properly, - // since the lowest denomination of bitcoin on-chain is the satoshi. - (commitment_tx_base_weight(channel_type_features) + num_htlcs as u64 * COMMITMENT_TX_WEIGHT_PER_HTLC) * feerate_per_kw as u64 / 1000 * 1000 -} - // Holder designates channel data owned for the benefit of the user client. // Counterparty designates channel data owned by the another channel participant entity. pub(super) struct Channel where SP::Target: SignerProvider { @@ -5668,7 +5648,7 @@ impl Channel where && info.next_holder_htlc_id == self.context.next_holder_htlc_id && info.next_counterparty_htlc_id == self.context.next_counterparty_htlc_id && info.feerate == self.context.feerate_per_kw { - let actual_fee = commit_tx_fee_msat(self.context.feerate_per_kw, commitment_stats.num_nondust_htlcs, self.context.get_channel_type()); + let actual_fee = commit_tx_fee_sat(self.context.feerate_per_kw, commitment_stats.num_nondust_htlcs, self.context.get_channel_type()) * 1000; assert_eq!(actual_fee, info.fee); } } @@ -5946,7 +5926,7 @@ impl OutboundV1Channel where SP::Target: SignerProvider { let commitment_feerate = fee_estimator.bounded_sat_per_1000_weight(commitment_conf_target); let value_to_self_msat = channel_value_satoshis * 1000 - push_msat; - let commitment_tx_fee = commit_tx_fee_msat(commitment_feerate, MIN_AFFORDABLE_HTLC_COUNT, &channel_type); + let commitment_tx_fee = commit_tx_fee_sat(commitment_feerate, MIN_AFFORDABLE_HTLC_COUNT, &channel_type) * 1000; if value_to_self_msat.saturating_sub(anchor_outputs_value_msat) < commitment_tx_fee { return Err(APIError::APIMisuseError{ err: format!("Funding amount ({}) can't even pay fee for initial commitment transaction fee of {}.", value_to_self_msat / 1000, commitment_tx_fee / 1000) }); } @@ -6549,7 +6529,7 @@ impl InboundV1Channel where SP::Target: SignerProvider { 0 }; let funders_amount_msat = msg.funding_satoshis * 1000 - msg.push_msat; - let commitment_tx_fee = commit_tx_fee_msat(msg.feerate_per_kw, MIN_AFFORDABLE_HTLC_COUNT, &channel_type) / 1000; + let commitment_tx_fee = commit_tx_fee_sat(msg.feerate_per_kw, MIN_AFFORDABLE_HTLC_COUNT, &channel_type); if (funders_amount_msat / 1000).saturating_sub(anchor_outputs_value) < commitment_tx_fee { return Err(ChannelError::Close(format!("Funding amount ({} sats) can't even pay fee for initial commitment transaction fee of {} sats.", (funders_amount_msat / 1000).saturating_sub(anchor_outputs_value), commitment_tx_fee))); } @@ -7816,7 +7796,7 @@ mod tests { use crate::ln::PaymentHash; use crate::ln::channelmanager::{self, HTLCSource, PaymentId}; use crate::ln::channel::InitFeatures; - use crate::ln::channel::{Channel, ChannelState, InboundHTLCOutput, OutboundV1Channel, InboundV1Channel, OutboundHTLCOutput, InboundHTLCState, OutboundHTLCState, HTLCCandidate, HTLCInitiator, commit_tx_fee_msat}; + use crate::ln::channel::{Channel, ChannelState, InboundHTLCOutput, OutboundV1Channel, InboundV1Channel, OutboundHTLCOutput, InboundHTLCState, OutboundHTLCState, HTLCCandidate, HTLCInitiator, commit_tx_fee_sat}; use crate::ln::channel::{MAX_FUNDING_SATOSHIS_NO_WUMBO, TOTAL_BITCOIN_SUPPLY_SATOSHIS, MIN_THEIR_CHAN_RESERVE_SATOSHIS}; use crate::ln::features::ChannelTypeFeatures; use crate::ln::msgs::{ChannelUpdate, DecodeError, UnsignedChannelUpdate, MAX_VALUE_MSAT}; @@ -8030,13 +8010,13 @@ mod tests { // the dust limit check. let htlc_candidate = HTLCCandidate::new(htlc_amount_msat, HTLCInitiator::LocalOffered); let local_commit_tx_fee = node_a_chan.context.next_local_commit_tx_fee_msat(htlc_candidate, None); - let local_commit_fee_0_htlcs = commit_tx_fee_msat(node_a_chan.context.feerate_per_kw, 0, node_a_chan.context.get_channel_type()); + let local_commit_fee_0_htlcs = commit_tx_fee_sat(node_a_chan.context.feerate_per_kw, 0, node_a_chan.context.get_channel_type()) * 1000; assert_eq!(local_commit_tx_fee, local_commit_fee_0_htlcs); // Finally, make sure that when Node A calculates the remote's commitment transaction fees, all // of the HTLCs are seen to be above the dust limit. node_a_chan.context.channel_transaction_parameters.is_outbound_from_holder = false; - let remote_commit_fee_3_htlcs = commit_tx_fee_msat(node_a_chan.context.feerate_per_kw, 3, node_a_chan.context.get_channel_type()); + let remote_commit_fee_3_htlcs = commit_tx_fee_sat(node_a_chan.context.feerate_per_kw, 3, node_a_chan.context.get_channel_type()) * 1000; let htlc_candidate = HTLCCandidate::new(htlc_amount_msat, HTLCInitiator::LocalOffered); let remote_commit_tx_fee = node_a_chan.context.next_remote_commit_tx_fee_msat(htlc_candidate, None); assert_eq!(remote_commit_tx_fee, remote_commit_fee_3_htlcs); @@ -8058,8 +8038,8 @@ mod tests { let config = UserConfig::default(); let mut chan = OutboundV1Channel::<&TestKeysInterface>::new(&fee_est, &&keys_provider, &&keys_provider, node_id, &channelmanager::provided_init_features(&config), 10000000, 100000, 42, &config, 0, 42, None).unwrap(); - let commitment_tx_fee_0_htlcs = commit_tx_fee_msat(chan.context.feerate_per_kw, 0, chan.context.get_channel_type()); - let commitment_tx_fee_1_htlc = commit_tx_fee_msat(chan.context.feerate_per_kw, 1, chan.context.get_channel_type()); + let commitment_tx_fee_0_htlcs = commit_tx_fee_sat(chan.context.feerate_per_kw, 0, chan.context.get_channel_type()) * 1000; + let commitment_tx_fee_1_htlc = commit_tx_fee_sat(chan.context.feerate_per_kw, 1, chan.context.get_channel_type()) * 1000; // If HTLC_SUCCESS_TX_WEIGHT and HTLC_TIMEOUT_TX_WEIGHT were swapped: then this HTLC would be // counted as dust when it shouldn't be. diff --git a/lightning/src/ln/functional_tests.rs b/lightning/src/ln/functional_tests.rs index 98bb83a7f9d..a5fb91efe0e 100644 --- a/lightning/src/ln/functional_tests.rs +++ b/lightning/src/ln/functional_tests.rs @@ -20,11 +20,11 @@ use crate::chain::transaction::OutPoint; use crate::sign::{EcdsaChannelSigner, EntropySource, SignerProvider}; use crate::events::{Event, MessageSendEvent, MessageSendEventsProvider, PathFailure, PaymentPurpose, ClosureReason, HTLCDestination, PaymentFailureReason}; use crate::ln::{ChannelId, PaymentPreimage, PaymentSecret, PaymentHash}; -use crate::ln::channel::{commitment_tx_base_weight, COMMITMENT_TX_WEIGHT_PER_HTLC, CONCURRENT_INBOUND_HTLC_FEE_BUFFER, FEE_SPIKE_BUFFER_FEE_INCREASE_MULTIPLE, MIN_AFFORDABLE_HTLC_COUNT, get_holder_selected_channel_reserve_satoshis, OutboundV1Channel, InboundV1Channel, COINBASE_MATURITY, ChannelPhase}; +use crate::ln::channel::{CONCURRENT_INBOUND_HTLC_FEE_BUFFER, FEE_SPIKE_BUFFER_FEE_INCREASE_MULTIPLE, MIN_AFFORDABLE_HTLC_COUNT, get_holder_selected_channel_reserve_satoshis, OutboundV1Channel, InboundV1Channel, COINBASE_MATURITY, ChannelPhase}; use crate::ln::channelmanager::{self, PaymentId, RAACommitmentOrder, PaymentSendFailure, RecipientOnionFields, BREAKDOWN_TIMEOUT, ENABLE_GOSSIP_TICKS, DISABLE_GOSSIP_TICKS, MIN_CLTV_EXPIRY_DELTA}; use crate::ln::channel::{DISCONNECT_PEER_AWAITING_RESPONSE_TICKS, ChannelError}; use crate::ln::{chan_utils, onion_utils}; -use crate::ln::chan_utils::{OFFERED_HTLC_SCRIPT_WEIGHT, htlc_success_tx_weight, htlc_timeout_tx_weight, HTLCOutputInCommitment}; +use crate::ln::chan_utils::{commitment_tx_base_weight, COMMITMENT_TX_WEIGHT_PER_HTLC, OFFERED_HTLC_SCRIPT_WEIGHT, htlc_success_tx_weight, htlc_timeout_tx_weight, HTLCOutputInCommitment}; use crate::routing::gossip::{NetworkGraph, NetworkUpdate}; use crate::routing::router::{Path, PaymentParameters, Route, RouteHop, get_route, RouteParameters}; use crate::ln::features::{ChannelFeatures, ChannelTypeFeatures, NodeFeatures}; diff --git a/lightning/src/ln/monitor_tests.rs b/lightning/src/ln/monitor_tests.rs index 685ec75c7e9..996cb74e8c2 100644 --- a/lightning/src/ln/monitor_tests.rs +++ b/lightning/src/ln/monitor_tests.rs @@ -16,6 +16,7 @@ use crate::chain::chaininterface::{LowerBoundedFeeEstimator, compute_feerate_sat use crate::events::bump_transaction::{BumpTransactionEvent, WalletSource}; use crate::events::{Event, MessageSendEvent, MessageSendEventsProvider, ClosureReason, HTLCDestination}; use crate::ln::channel; +use crate::ln::chan_utils; use crate::ln::channelmanager::{BREAKDOWN_TIMEOUT, PaymentId, RecipientOnionFields}; use crate::ln::msgs::ChannelMessageHandler; use crate::util::config::UserConfig; @@ -180,7 +181,7 @@ fn do_chanmon_claim_value_coop_close(anchors: bool) { let chan_feerate = get_feerate!(nodes[0], nodes[1], chan_id) as u64; let channel_type_features = get_channel_type_features!(nodes[0], nodes[1], chan_id); - let commitment_tx_fee = chan_feerate * channel::commitment_tx_base_weight(&channel_type_features) / 1000; + let commitment_tx_fee = chan_feerate * chan_utils::commitment_tx_base_weight(&channel_type_features) / 1000; let anchor_outputs_value = if anchors { channel::ANCHOR_OUTPUT_VALUE_SATOSHI * 2 } else { 0 }; assert_eq!(vec![Balance::ClaimableOnChannelClose { amount_satoshis: 1_000_000 - 1_000 - commitment_tx_fee - anchor_outputs_value @@ -380,8 +381,8 @@ fn do_test_claim_value_force_close(anchors: bool, prev_commitment_tx: bool) { // Before B receives the payment preimage, it only suggests the push_msat value of 1_000 sats // as claimable. A lists both its to-self balance and the (possibly-claimable) HTLCs. let commitment_tx_fee = chan_feerate as u64 * - (channel::commitment_tx_base_weight(&channel_type_features) + 2 * channel::COMMITMENT_TX_WEIGHT_PER_HTLC) / 1000; - let anchor_outputs_value = if anchors { 2 * channel::ANCHOR_OUTPUT_VALUE_SATOSHI } else { 0 }; + (chan_utils::commitment_tx_base_weight(&channel_type_features) + 2 * chan_utils::COMMITMENT_TX_WEIGHT_PER_HTLC) / 1000; + let anchor_outputs_value = if anchors { 2 * chan_utils::ANCHOR_OUTPUT_VALUE_SATOSHI } else { 0 }; 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, }, sent_htlc_balance.clone(), sent_htlc_timeout_balance.clone()]), @@ -424,8 +425,8 @@ fn do_test_claim_value_force_close(anchors: bool, prev_commitment_tx: bool) { // Once B has received the payment preimage, it includes the value of the HTLC in its // "claimable if you were to close the channel" balance. let commitment_tx_fee = chan_feerate as u64 * - (channel::commitment_tx_base_weight(&channel_type_features) + - if prev_commitment_tx { 1 } else { 2 } * channel::COMMITMENT_TX_WEIGHT_PER_HTLC) / 1000; + (chan_utils::commitment_tx_base_weight(&channel_type_features) + + if prev_commitment_tx { 1 } else { 2 } * chan_utils::COMMITMENT_TX_WEIGHT_PER_HTLC) / 1000; let mut a_expected_balances = vec![Balance::ClaimableOnChannelClose { amount_satoshis: 1_000_000 - // Channel funding value in satoshis 4_000 - // The to-be-failed HTLC value in satoshis @@ -503,7 +504,7 @@ fn do_test_claim_value_force_close(anchors: bool, prev_commitment_tx: bool) { assert!(nodes[0].chain_monitor.chain_monitor.get_and_clear_pending_events().is_empty()); assert!(nodes[1].chain_monitor.chain_monitor.get_and_clear_pending_events().is_empty()); let commitment_tx_fee = chan_feerate as u64 * - (channel::commitment_tx_base_weight(&channel_type_features) + 2 * channel::COMMITMENT_TX_WEIGHT_PER_HTLC) / 1000; + (chan_utils::commitment_tx_base_weight(&channel_type_features) + 2 * chan_utils::COMMITMENT_TX_WEIGHT_PER_HTLC) / 1000; assert_eq!(sorted_vec(vec![Balance::ClaimableAwaitingConfirmations { amount_satoshis: 1_000_000 - 3_000 - 4_000 - 1_000 - 3 - commitment_tx_fee - anchor_outputs_value, confirmation_height: nodes[0].best_block_info().1 + ANTI_REORG_DELAY - 1, @@ -922,7 +923,7 @@ fn test_no_preimage_inbound_htlc_balances() { assert_eq!(sorted_vec(vec![Balance::ClaimableOnChannelClose { amount_satoshis: 1_000_000 - 500_000 - 10_000 - chan_feerate * - (channel::commitment_tx_base_weight(&channel_type_features) + 2 * channel::COMMITMENT_TX_WEIGHT_PER_HTLC) / 1000, + (chan_utils::commitment_tx_base_weight(&channel_type_features) + 2 * chan_utils::COMMITMENT_TX_WEIGHT_PER_HTLC) / 1000, }, 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())); @@ -942,7 +943,7 @@ fn test_no_preimage_inbound_htlc_balances() { let node_a_commitment_claimable = nodes[0].best_block_info().1 + BREAKDOWN_TIMEOUT as u32; let as_pre_spend_claims = sorted_vec(vec![Balance::ClaimableAwaitingConfirmations { amount_satoshis: 1_000_000 - 500_000 - 10_000 - chan_feerate * - (channel::commitment_tx_base_weight(&channel_type_features) + 2 * channel::COMMITMENT_TX_WEIGHT_PER_HTLC) / 1000, + (chan_utils::commitment_tx_base_weight(&channel_type_features) + 2 * chan_utils::COMMITMENT_TX_WEIGHT_PER_HTLC) / 1000, confirmation_height: node_a_commitment_claimable, }, a_received_htlc_balance.clone(), a_sent_htlc_balance.clone()]); @@ -1014,7 +1015,7 @@ fn test_no_preimage_inbound_htlc_balances() { let as_timeout_claimable_height = nodes[0].best_block_info().1 + (BREAKDOWN_TIMEOUT as u32) - 1; assert_eq!(sorted_vec(vec![Balance::ClaimableAwaitingConfirmations { amount_satoshis: 1_000_000 - 500_000 - 10_000 - chan_feerate * - (channel::commitment_tx_base_weight(&channel_type_features) + 2 * channel::COMMITMENT_TX_WEIGHT_PER_HTLC) / 1000, + (chan_utils::commitment_tx_base_weight(&channel_type_features) + 2 * chan_utils::COMMITMENT_TX_WEIGHT_PER_HTLC) / 1000, confirmation_height: node_a_commitment_claimable, }, a_received_htlc_balance.clone(), Balance::ClaimableAwaitingConfirmations { amount_satoshis: 10_000, @@ -1025,7 +1026,7 @@ fn test_no_preimage_inbound_htlc_balances() { mine_transaction(&nodes[0], &bs_htlc_timeout_claim[0]); assert_eq!(sorted_vec(vec![Balance::ClaimableAwaitingConfirmations { amount_satoshis: 1_000_000 - 500_000 - 10_000 - chan_feerate * - (channel::commitment_tx_base_weight(&channel_type_features) + 2 * channel::COMMITMENT_TX_WEIGHT_PER_HTLC) / 1000, + (chan_utils::commitment_tx_base_weight(&channel_type_features) + 2 * chan_utils::COMMITMENT_TX_WEIGHT_PER_HTLC) / 1000, confirmation_height: node_a_commitment_claimable, }, a_received_htlc_balance.clone(), Balance::ClaimableAwaitingConfirmations { amount_satoshis: 10_000, @@ -1041,7 +1042,7 @@ fn test_no_preimage_inbound_htlc_balances() { connect_blocks(&nodes[0], 1); assert_eq!(sorted_vec(vec![Balance::ClaimableAwaitingConfirmations { amount_satoshis: 1_000_000 - 500_000 - 10_000 - chan_feerate * - (channel::commitment_tx_base_weight(&channel_type_features) + 2 * channel::COMMITMENT_TX_WEIGHT_PER_HTLC) / 1000, + (chan_utils::commitment_tx_base_weight(&channel_type_features) + 2 * chan_utils::COMMITMENT_TX_WEIGHT_PER_HTLC) / 1000, confirmation_height: node_a_commitment_claimable, }, Balance::ClaimableAwaitingConfirmations { amount_satoshis: 10_000, From 80a2598d936cf3a79f02eb02b90b889ea0c7af50 Mon Sep 17 00:00:00 2001 From: Matt Corallo Date: Tue, 14 Nov 2023 22:00:42 +0000 Subject: [PATCH 4/9] f --- lightning/src/ln/monitor_tests.rs | 10 +++++----- lightning/src/ln/payment_tests.rs | 8 ++++---- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/lightning/src/ln/monitor_tests.rs b/lightning/src/ln/monitor_tests.rs index 996cb74e8c2..e432b8bc012 100644 --- a/lightning/src/ln/monitor_tests.rs +++ b/lightning/src/ln/monitor_tests.rs @@ -382,7 +382,7 @@ fn do_test_claim_value_force_close(anchors: bool, prev_commitment_tx: bool) { // as claimable. A lists both its to-self balance and the (possibly-claimable) HTLCs. let commitment_tx_fee = chan_feerate as u64 * (chan_utils::commitment_tx_base_weight(&channel_type_features) + 2 * chan_utils::COMMITMENT_TX_WEIGHT_PER_HTLC) / 1000; - let anchor_outputs_value = if anchors { 2 * chan_utils::ANCHOR_OUTPUT_VALUE_SATOSHI } else { 0 }; + let anchor_outputs_value = if anchors { 2 * channel::ANCHOR_OUTPUT_VALUE_SATOSHI } else { 0 }; 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, }, sent_htlc_balance.clone(), sent_htlc_timeout_balance.clone()]), @@ -759,7 +759,7 @@ fn do_test_balances_on_local_commitment_htlcs(anchors: bool) { }; let commitment_tx_fee = chan_feerate * - (channel::commitment_tx_base_weight(&channel_type_features) + 2 * channel::COMMITMENT_TX_WEIGHT_PER_HTLC) / 1000; + (chan_utils::commitment_tx_base_weight(&channel_type_features) + 2 * chan_utils::COMMITMENT_TX_WEIGHT_PER_HTLC) / 1000; let anchor_outputs_value = if anchors { 2 * channel::ANCHOR_OUTPUT_VALUE_SATOSHI } else { 0 }; assert_eq!(sorted_vec(vec![Balance::ClaimableAwaitingConfirmations { amount_satoshis: 1_000_000 - 10_000 - 20_000 - commitment_tx_fee - anchor_outputs_value, @@ -1245,7 +1245,7 @@ fn do_test_revoked_counterparty_commitment_balances(anchors: bool, confirm_htlc_ fuzzy_assert_eq(claim_txn[3].weight(), BS_TO_SELF_CLAIM_EXP_WEIGHT); let commitment_tx_fee = chan_feerate * - (channel::commitment_tx_base_weight(&channel_type_features) + 3 * channel::COMMITMENT_TX_WEIGHT_PER_HTLC) / 1000; + (chan_utils::commitment_tx_base_weight(&channel_type_features) + 3 * chan_utils::COMMITMENT_TX_WEIGHT_PER_HTLC) / 1000; let anchor_outputs_value = if anchors { channel::ANCHOR_OUTPUT_VALUE_SATOSHI * 2 } else { 0 }; let inbound_htlc_claim_fee = chan_feerate * inbound_htlc_claim_exp_weight as u64 / 1000; let outbound_htlc_claim_fee = chan_feerate * outbound_htlc_claim_exp_weight as u64 / 1000; @@ -1505,7 +1505,7 @@ fn do_test_revoked_counterparty_htlc_tx_balances(anchors: bool) { // transaction our balance tracking doesn't use the on-chain value so the // `CounterpartyRevokedOutputClaimable` entry doesn't change. let commitment_tx_fee = chan_feerate * - (channel::commitment_tx_base_weight(&channel_type_features) + 2 * channel::COMMITMENT_TX_WEIGHT_PER_HTLC) / 1000; + (chan_utils::commitment_tx_base_weight(&channel_type_features) + 2 * chan_utils::COMMITMENT_TX_WEIGHT_PER_HTLC) / 1000; let anchor_outputs_value = if anchors { channel::ANCHOR_OUTPUT_VALUE_SATOSHI * 2 } else { 0 }; let as_balances = sorted_vec(vec![Balance::ClaimableAwaitingConfirmations { // to_remote output in B's revoked commitment @@ -1801,7 +1801,7 @@ fn do_test_revoked_counterparty_aggregated_claims(anchors: bool) { let to_remote_maturity = nodes[1].best_block_info().1 + ANTI_REORG_DELAY - 1; let commitment_tx_fee = chan_feerate * - (channel::commitment_tx_base_weight(&channel_type_features) + 2 * channel::COMMITMENT_TX_WEIGHT_PER_HTLC) / 1000; + (chan_utils::commitment_tx_base_weight(&channel_type_features) + 2 * chan_utils::COMMITMENT_TX_WEIGHT_PER_HTLC) / 1000; let anchor_outputs_value = if anchors { channel::ANCHOR_OUTPUT_VALUE_SATOSHI * 2 } else { 0 }; assert_eq!(sorted_vec(vec![Balance::ClaimableAwaitingConfirmations { // to_remote output in A's revoked commitment diff --git a/lightning/src/ln/payment_tests.rs b/lightning/src/ln/payment_tests.rs index 87952a1bbdf..14d8748998a 100644 --- a/lightning/src/ln/payment_tests.rs +++ b/lightning/src/ln/payment_tests.rs @@ -16,10 +16,10 @@ use crate::chain::channelmonitor::{ANTI_REORG_DELAY, HTLC_FAIL_BACK_BUFFER, LATE use crate::sign::EntropySource; use crate::chain::transaction::OutPoint; use crate::events::{ClosureReason, Event, HTLCDestination, MessageSendEvent, MessageSendEventsProvider, PathFailure, PaymentFailureReason, PaymentPurpose}; -use crate::ln::channel::{EXPIRE_PREV_CONFIG_TICKS, commit_tx_fee_msat, get_holder_selected_channel_reserve_satoshis, ANCHOR_OUTPUT_VALUE_SATOSHI}; +use crate::ln::channel::{EXPIRE_PREV_CONFIG_TICKS, get_holder_selected_channel_reserve_satoshis, ANCHOR_OUTPUT_VALUE_SATOSHI}; use crate::ln::channelmanager::{BREAKDOWN_TIMEOUT, MPP_TIMEOUT_TICKS, MIN_CLTV_EXPIRY_DELTA, PaymentId, PaymentSendFailure, RecentPaymentDetails, RecipientOnionFields, HTLCForwardInfo, PendingHTLCRouting, PendingAddHTLCInfo}; use crate::ln::features::{Bolt11InvoiceFeatures, ChannelTypeFeatures}; -use crate::ln::{msgs, ChannelId, PaymentSecret, PaymentPreimage}; +use crate::ln::{chan_utils, msgs, ChannelId, PaymentSecret, PaymentPreimage}; use crate::ln::msgs::ChannelMessageHandler; use crate::ln::outbound_payment::{IDEMPOTENCY_TIMEOUT_TICKS, Retry}; use crate::routing::gossip::{EffectiveCapacity, RoutingFees}; @@ -4131,9 +4131,9 @@ fn test_htlc_forward_considers_anchor_outputs_value() { let (_, _, chan_id_2, _) = create_announced_chan_between_nodes_with_value(&nodes, 1, 2, CHAN_AMT, PUSH_MSAT); let channel_reserve_msat = get_holder_selected_channel_reserve_satoshis(CHAN_AMT, &config) * 1000; - let commitment_fee_msat = commit_tx_fee_msat( + let commitment_fee_msat = chan_utils::commit_tx_fee_sat( *nodes[1].fee_estimator.sat_per_kw.lock().unwrap(), 2, &ChannelTypeFeatures::anchors_zero_htlc_fee_and_dependencies() - ); + ) * 1000; let anchor_outpus_value_msat = ANCHOR_OUTPUT_VALUE_SATOSHI * 2 * 1000; let sendable_balance_msat = CHAN_AMT * 1000 - PUSH_MSAT - channel_reserve_msat - commitment_fee_msat - anchor_outpus_value_msat; let channel_details = nodes[1].node.list_channels().into_iter().find(|channel| channel.channel_id == chan_id_2).unwrap(); From b5ad3c91e81f3d47b9afdd004f38689448647bfb Mon Sep 17 00:00:00 2001 From: Matt Corallo Date: Fri, 29 Sep 2023 17:54:24 +0000 Subject: [PATCH 5/9] Add tx fee information to `Balance::ClaimableOnChannelClose` `Balance::ClaimableOnChannelClose` excludes the commitment transaction fee, which makes it hard to use for current balance calculation. Here we add it, setting the value to zero for inbound channels (i.e. ones for which we don't pay the fee). --- lightning/src/chain/channelmonitor.rs | 30 ++++++++++++++++++++++++--- lightning/src/ln/channel.rs | 4 ++-- lightning/src/ln/monitor_tests.rs | 19 ++++++++++++----- 3 files changed, 43 insertions(+), 10 deletions(-) diff --git a/lightning/src/chain/channelmonitor.rs b/lightning/src/chain/channelmonitor.rs index 3845328cda4..7f9d40b502c 100644 --- a/lightning/src/chain/channelmonitor.rs +++ b/lightning/src/chain/channelmonitor.rs @@ -578,6 +578,13 @@ pub enum Balance { /// The amount available to claim, in satoshis, excluding the on-chain fees which will be /// required to do so. amount_satoshis: u64, + /// The transaction fee we pay for the closing commitment transaction. This amount is not + /// included in the [`Balance::ClaimableOnChannelClose::amount_satoshis`] value. + /// + /// Note that if this channel is inbound (and thus our counterparty pays the commitment + /// transaction fee) this value will be zero. For [`ChannelMonitor`]s created prior to LDK + /// 0.0.117, the channel is always treated as outbound (and thus this value is never zero). + transaction_fee_satoshis: u64, }, /// The channel has been closed, and the given balance is ours but awaiting confirmations until /// we consider it spendable. @@ -861,6 +868,10 @@ pub(crate) struct ChannelMonitorImpl { // of block connection between ChannelMonitors and the ChannelManager. funding_spend_seen: bool, + /// True if the commitment transaction fee is paid by us. + /// Added in 0.0.117. + holder_pays_commitment_tx_fee: Option, + /// Set to `Some` of the confirmed transaction spending the funding input of the channel after /// reaching `ANTI_REORG_DELAY` confirmations. funding_spend_confirmed: Option, @@ -1086,6 +1097,7 @@ impl Writeable for ChannelMonitorImpl ChannelMonitor { pub(crate) fn new(secp_ctx: Secp256k1, keys: Signer, shutdown_script: Option