diff --git a/lightning/src/chain/channelmonitor.rs b/lightning/src/chain/channelmonitor.rs index 10aab828753..b9ced655399 100644 --- a/lightning/src/chain/channelmonitor.rs +++ b/lightning/src/chain/channelmonitor.rs @@ -608,6 +608,21 @@ impl_writeable_tlv_based_enum_upgradable!(ChannelMonitorUpdateStep, }, ); +/// Indicates whether the balance is derived from a cooperative close, a force-close +/// (for holder or counterparty), or whether it is for an HTLC. +#[derive(Clone, Debug, PartialEq, Eq)] +#[cfg_attr(test, derive(PartialOrd, Ord))] +pub enum BalanceSource { + /// The channel was force closed by the holder. + HolderForceClosed, + /// The channel was force closed by the counterparty. + CounterpartyForceClosed, + /// The channel was cooperatively closed. + CoopClose, + /// This balance is the result of an HTLC. + Htlc, +} + /// Details about the balance(s) available for spending once the channel appears on chain. /// /// See [`ChannelMonitor::get_claimable_balances`] for more details on when these will or will not @@ -622,6 +637,49 @@ 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.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. + /// + /// This amount (rounded up to a whole satoshi value) will not be included in `amount_satoshis`. + 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. + /// + /// This amount (rounded up to a whole satoshi value) will not be included in `amount_satoshis`. + 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. + /// + /// This amount (rounded up to a whole satoshi value) will not be included in the counterparty's + /// `amount_satoshis`. + 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. + /// + /// This amount (rounded up to a whole satoshi value) will not be included in the counterparty's + /// `amount_satoshis`. + inbound_htlc_rounded_msat: u64, }, /// The channel has been closed, and the given balance is ours but awaiting confirmations until /// we consider it spendable. @@ -632,6 +690,8 @@ pub enum Balance { /// The height at which an [`Event::SpendableOutputs`] event will be generated for this /// amount. confirmation_height: u32, + /// Whether this balance is a result of cooperative close, a force-close, or an HTLC. + source: BalanceSource, }, /// The channel has been closed, and the given balance should be ours but awaiting spending /// transaction confirmation. If the spending transaction does not confirm in time, it is @@ -664,6 +724,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 @@ -693,9 +757,15 @@ pub enum Balance { } impl Balance { - /// The amount claimable, in satoshis. This excludes balances that we are unsure if we are able - /// to claim, this is because we are waiting for a preimage or for a timeout to expire. For more - /// information on these balances see [`Balance::MaybeTimeoutClaimableHTLC`] and + /// The amount claimable, in satoshis. + /// + /// For outbound payments, this excludes the balance from the possible HTLC timeout. + /// + /// For forwarded payments, this includes the balance from the possible HTLC timeout as + /// (to be conservative) that balance does not include routing fees we'd earn if we'd claim + /// the balance from a preimage in a successful forward. + /// + /// For more information on these balances see [`Balance::MaybeTimeoutClaimableHTLC`] and /// [`Balance::MaybePreimageClaimableHTLC`]. /// /// On-chain fees required to claim the balance are not included in this amount. @@ -706,9 +776,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, } } } @@ -902,6 +972,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.124. + 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, @@ -1150,6 +1224,7 @@ impl Writeable for ChannelMonitorImpl { (17, self.initial_counterparty_commitment_info, option), (19, self.channel_id, required), (21, self.balances_empty_height, option), + (23, self.holder_pays_commitment_tx_fee, option), }); Ok(()) @@ -1251,7 +1326,7 @@ impl ChannelMonitor { pub(crate) fn new(secp_ctx: Secp256k1, keys: Signer, shutdown_script: Option, on_counterparty_tx_csv: u16, destination_script: &Script, funding_info: (OutPoint, ScriptBuf), - channel_parameters: &ChannelTransactionParameters, + channel_parameters: &ChannelTransactionParameters, holder_pays_commitment_tx_fee: bool, funding_redeemscript: ScriptBuf, channel_value_satoshis: u64, commitment_transaction_number_obscure_factor: u64, initial_holder_commitment_tx: HolderCommitmentTransaction, @@ -1343,6 +1418,7 @@ impl ChannelMonitor { onchain_tx_handler, + holder_pays_commitment_tx_fee: Some(holder_pays_commitment_tx_fee), lockdown_from_offchain: false, holder_tx_signed: false, funding_spend_seen: false, @@ -1960,9 +2036,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; }; @@ -2050,6 +2127,7 @@ impl ChannelMonitorImpl { return Some(Balance::ClaimableAwaitingConfirmations { amount_satoshis: htlc.amount_msat / 1000, confirmation_height: conf_thresh, + source: BalanceSource::Htlc, }); } else if htlc_resolved.is_some() && !htlc_output_spend_pending { // Funding transaction spends should be fully confirmed by the time any @@ -2097,12 +2175,22 @@ impl ChannelMonitorImpl { return Some(Balance::ClaimableAwaitingConfirmations { amount_satoshis: htlc.amount_msat / 1000, confirmation_height: conf_thresh, + source: BalanceSource::Htlc, }); } 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) { @@ -2116,6 +2204,7 @@ impl ChannelMonitorImpl { return Some(Balance::ClaimableAwaitingConfirmations { amount_satoshis: htlc.amount_msat / 1000, confirmation_height: conf_thresh, + source: BalanceSource::Htlc, }); } else { return Some(Balance::ContentiousClaimable { @@ -2175,10 +2264,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); } } @@ -2201,6 +2292,7 @@ impl ChannelMonitor { res.push(Balance::ClaimableAwaitingConfirmations { amount_satoshis: value.to_sat(), confirmation_height: conf_thresh, + source: BalanceSource::CounterpartyForceClosed, }); } else { // If a counterparty commitment transaction is awaiting confirmation, we @@ -2209,9 +2301,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 @@ -2224,6 +2316,7 @@ impl ChannelMonitor { res.push(Balance::ClaimableAwaitingConfirmations { amount_satoshis: output.value.to_sat(), confirmation_height: event.confirmation_threshold(), + source: BalanceSource::CounterpartyForceClosed, }); if let Some(confirmed_to_self_idx) = confirmed_counterparty_output.map(|(idx, _)| idx) { if event.transaction.as_ref().map(|tx| @@ -2251,21 +2344,23 @@ 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, confirmation_height: conf_thresh, + source: BalanceSource::HolderForceClosed, }); } 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, confirmation_height: conf_thresh, + source: BalanceSource::HolderForceClosed, }); } found_commitment_tx = true; @@ -2279,33 +2374,75 @@ impl ChannelMonitor { res.push(Balance::ClaimableAwaitingConfirmations { amount_satoshis: us.current_holder_commitment_tx.to_self_value_sat, confirmation_height: conf_thresh, + source: BalanceSource::CoopClose, }); } } } else { let mut claimable_inbound_htlc_value_sat = 0; - for (htlc, _, _) in us.current_holder_commitment_tx.htlc_outputs.iter() { - if htlc.transaction_output_index.is_none() { continue; } + 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; + } + let rounded_value_msat = if htlc.transaction_output_index.is_none() { + htlc.amount_msat + } else { htlc.amount_msat % 1000 }; if htlc.offered { - res.push(Balance::MaybeTimeoutClaimableHTLC { - amount_satoshis: htlc.amount_msat / 1000, - claimable_height: htlc.cltv_expiry, - payment_hash: htlc.payment_hash, - }); + let outbound_payment = match source { + None => { + debug_assert!(false, "Outbound HTLCs should have a source"); + true + }, + Some(HTLCSource::PreviousHopData(_)) => false, + Some(HTLCSource::OutboundRoute { .. }) => true, + }; + 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 { amount_satoshis: us.current_holder_commitment_tx.to_self_value_sat + claimable_inbound_htlc_value_sat, + transaction_fee_satoshis: if us.holder_pays_commitment_tx_fee.unwrap_or(true) { + chan_utils::commit_tx_fee_sat( + 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, }); } @@ -4712,6 +4849,7 @@ impl<'a, 'b, ES: EntropySource, SP: SignerProvider> ReadableArgs<(&'a ES, &'b SP let mut initial_counterparty_commitment_info = None; let mut balances_empty_height = None; let mut channel_id = None; + let mut holder_pays_commitment_tx_fee = None; read_tlv_fields!(reader, { (1, funding_spend_confirmed, option), (3, htlcs_resolved_on_chain, optional_vec), @@ -4724,6 +4862,7 @@ impl<'a, 'b, ES: EntropySource, SP: SignerProvider> ReadableArgs<(&'a ES, &'b SP (17, initial_counterparty_commitment_info, option), (19, channel_id, option), (21, balances_empty_height, option), + (23, holder_pays_commitment_tx_fee, option), }); // `HolderForceClosedWithInfo` replaced `HolderForceClosed` in v0.0.122. If we have both @@ -4793,6 +4932,7 @@ impl<'a, 'b, ES: EntropySource, SP: SignerProvider> ReadableArgs<(&'a ES, &'b SP lockdown_from_offchain, holder_tx_signed, + holder_pays_commitment_tx_fee, funding_spend_seen: funding_spend_seen.unwrap(), funding_spend_confirmed, confirmed_commitment_tx_counterparty_output, @@ -5032,7 +5172,7 @@ mod tests { let monitor = ChannelMonitor::new(Secp256k1::new(), keys, Some(ShutdownScript::new_p2wpkh_from_pubkey(shutdown_pubkey).into_inner()), 0, &ScriptBuf::new(), (OutPoint { txid: Txid::from_slice(&[43; 32]).unwrap(), index: 0 }, ScriptBuf::new()), - &channel_parameters, ScriptBuf::new(), 46, 0, HolderCommitmentTransaction::dummy(&mut Vec::new()), + &channel_parameters, true, ScriptBuf::new(), 46, 0, HolderCommitmentTransaction::dummy(&mut Vec::new()), best_block, dummy_key, channel_id); let mut htlcs = preimages_slice_to_htlcs!(preimages[0..10]); @@ -5280,7 +5420,7 @@ mod tests { let monitor = ChannelMonitor::new(Secp256k1::new(), keys, Some(ShutdownScript::new_p2wpkh_from_pubkey(shutdown_pubkey).into_inner()), 0, &ScriptBuf::new(), (OutPoint { txid: Txid::from_slice(&[43; 32]).unwrap(), index: 0 }, ScriptBuf::new()), - &channel_parameters, ScriptBuf::new(), 46, 0, HolderCommitmentTransaction::dummy(&mut Vec::new()), + &channel_parameters, true, ScriptBuf::new(), 46, 0, HolderCommitmentTransaction::dummy(&mut Vec::new()), best_block, dummy_key, channel_id); let chan_id = monitor.inner.lock().unwrap().channel_id(); diff --git a/lightning/src/ln/chan_utils.rs b/lightning/src/ln/chan_utils.rs index 8c811c920c0..6d47e1b9d44 100644 --- a/lightning/src/ln/chan_utils.rs +++ b/lightning/src/ln/chan_utils.rs @@ -41,7 +41,6 @@ use bitcoin::{secp256k1, Sequence, Witness}; use crate::io; 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; @@ -172,6 +171,37 @@ 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 +} + +pub(crate) fn per_outbound_htlc_counterparty_commit_tx_fee_msat(feerate_per_kw: u32, 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. + let commitment_tx_fee = COMMITMENT_TX_WEIGHT_PER_HTLC * feerate_per_kw as u64 / 1000 * 1000; + if channel_type_features.supports_anchors_zero_fee_htlc_tx() { + commitment_tx_fee + htlc_success_tx_weight(channel_type_features) * feerate_per_kw as u64 / 1000 + } else { + commitment_tx_fee + } +} + // Various functions for key derivation and transaction creation for use within channels. Primarily // used in Channel and ChannelMonitor. @@ -812,7 +842,7 @@ pub fn get_anchor_redeemscript(funding_pubkey: &PublicKey) -> ScriptBuf { /// 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_p2wsh(); + let anchor_script = get_anchor_redeemscript(funding_pubkey).to_p2wsh(); commitment_tx.output.iter().enumerate() .find(|(_, txout)| txout.script_pubkey == anchor_script) .map(|(idx, txout)| (idx as u32, txout)) @@ -820,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_ecdsa_signature(&BitcoinSignature::sighash_all(*funding_sig)); ret.push(anchor_redeem_script.as_bytes()); @@ -1512,7 +1542,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_p2wsh(), value: htlc.to_bitcoin_amount(), @@ -1735,7 +1765,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, ) } diff --git a/lightning/src/ln/channel.rs b/lightning/src/ln/channel.rs index 7ba94998a0a..4db39f0d69c 100644 --- a/lightning/src/ln/channel.rs +++ b/lightning/src/ln/channel.rs @@ -32,7 +32,14 @@ use crate::ln::msgs::DecodeError; use crate::ln::script::{self, ShutdownScript}; use crate::ln::channel_state::{ChannelShutdownState, CounterpartyForwardingInfo, InboundHTLCDetails, InboundHTLCStateDetails, OutboundHTLCDetails, OutboundHTLCStateDetails}; use crate::ln::channelmanager::{self, PendingHTLCStatus, HTLCSource, SentHTLCId, HTLCFailureMsg, PendingHTLCInfo, RAACommitmentOrder, BREAKDOWN_TIMEOUT, MIN_CLTV_EXPIRY_DELTA, MAX_LOCAL_BREAKDOWN_TIMEOUT}; -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, + get_commitment_transaction_number_obscure_factor, + ClosingTransaction, commit_tx_fee_sat, per_outbound_htlc_counterparty_commit_tx_fee_msat, +}; use crate::ln::chan_utils; use crate::ln::onion_utils::HTLCFailReason; use crate::chain::BestBlock; @@ -655,17 +662,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, @@ -1621,7 +1617,7 @@ impl ChannelContext where SP::Target: SignerProvider { 0 }; let funders_amount_msat = open_channel_fields.funding_satoshis * 1000 - msg_push_msat; - let commitment_tx_fee = commit_tx_fee_msat(open_channel_fields.commitment_feerate_sat_per_1000_weight, MIN_AFFORDABLE_HTLC_COUNT, &channel_type) / 1000; + let commitment_tx_fee = commit_tx_fee_sat(open_channel_fields.commitment_feerate_sat_per_1000_weight, 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))); } @@ -1888,7 +1884,7 @@ impl ChannelContext 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) }); } @@ -2949,7 +2945,7 @@ impl ChannelContext where SP::Target: SignerProvider { let on_counterparty_tx_nondust_htlcs = on_counterparty_tx_accepted_nondust_htlcs + on_counterparty_tx_offered_nondust_htlcs; on_counterparty_tx_dust_exposure_msat += - commit_tx_fee_msat(excess_feerate, on_counterparty_tx_nondust_htlcs, &self.channel_type); + commit_tx_fee_sat(excess_feerate, on_counterparty_tx_nondust_htlcs, &self.channel_type) * 1000; if !self.channel_type.supports_anchors_zero_fee_htlc_tx() { on_counterparty_tx_dust_exposure_msat += on_counterparty_tx_accepted_nondust_htlcs as u64 * htlc_success_tx_weight(&self.channel_type) @@ -3314,12 +3310,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(); @@ -3405,12 +3401,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 { @@ -3676,32 +3672,6 @@ fn get_v2_channel_reserve_satoshis(channel_value_satoshis: u64, dust_limit_satos cmp::min(channel_value_satoshis, cmp::max(q, dust_limit_satoshis)) } -// 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 -} - -pub(crate) fn per_outbound_htlc_counterparty_commit_tx_fee_msat(feerate_per_kw: u32, 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. - let commitment_tx_fee = COMMITMENT_TX_WEIGHT_PER_HTLC * feerate_per_kw as u64 / 1000 * 1000; - if channel_type_features.supports_anchors_zero_fee_htlc_tx() { - commitment_tx_fee + htlc_success_tx_weight(channel_type_features) * feerate_per_kw as u64 / 1000 - } else { - commitment_tx_fee - } -} - /// Context for dual-funded channels. #[cfg(any(dual_funding, splicing))] pub(super) struct DualFundingChannelContext { @@ -7396,7 +7366,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); } } @@ -7892,7 +7862,7 @@ impl OutboundV1Channel where SP::Target: SignerProvider { let channel_monitor = ChannelMonitor::new(self.context.secp_ctx.clone(), monitor_signer, shutdown_script, self.context.get_holder_selected_contest_delay(), &self.context.destination_script, (funding_txo, funding_txo_script), - &self.context.channel_transaction_parameters, + &self.context.channel_transaction_parameters, self.context.is_outbound(), funding_redeemscript.clone(), self.context.channel_value_satoshis, obscure_factor, holder_commitment_tx, best_block, self.context.counterparty_node_id, self.context.channel_id()); @@ -8204,7 +8174,7 @@ impl InboundV1Channel where SP::Target: SignerProvider { let channel_monitor = ChannelMonitor::new(self.context.secp_ctx.clone(), monitor_signer, shutdown_script, self.context.get_holder_selected_contest_delay(), &self.context.destination_script, (funding_txo, funding_txo_script.clone()), - &self.context.channel_transaction_parameters, + &self.context.channel_transaction_parameters, self.context.is_outbound(), funding_redeemscript.clone(), self.context.channel_value_satoshis, obscure_factor, holder_commitment_tx, best_block, self.context.counterparty_node_id, self.context.channel_id()); @@ -9597,7 +9567,7 @@ mod tests { use crate::ln::channel_keys::{RevocationKey, RevocationBasepoint}; use crate::ln::channelmanager::{self, HTLCSource, PaymentId}; use crate::ln::channel::InitFeatures; - use crate::ln::channel::{AwaitingChannelReadyFlags, Channel, ChannelState, InboundHTLCOutput, OutboundV1Channel, InboundV1Channel, OutboundHTLCOutput, InboundHTLCState, OutboundHTLCState, HTLCCandidate, HTLCInitiator, HTLCUpdateAwaitingACK, commit_tx_fee_msat}; + use crate::ln::channel::{AwaitingChannelReadyFlags, Channel, ChannelState, InboundHTLCOutput, OutboundV1Channel, InboundV1Channel, OutboundHTLCOutput, InboundHTLCState, OutboundHTLCState, HTLCCandidate, HTLCInitiator, HTLCUpdateAwaitingACK, 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::{ChannelFeatures, ChannelTypeFeatures, NodeFeatures}; use crate::ln::msgs; @@ -9820,13 +9790,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); @@ -9849,8 +9819,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, &logger).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 3dd16ae5c2c..99063334a28 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::{ecdsa::EcdsaChannelSigner, EntropySource, OutputSpender, SignerProvider}; use crate::events::{Event, MessageSendEvent, MessageSendEventsProvider, PathFailure, PaymentPurpose, ClosureReason, HTLCDestination, PaymentFailureReason}; use crate::ln::types::{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 6f9a1457712..2e4b7326cbd 100644 --- a/lightning/src/ln/monitor_tests.rs +++ b/lightning/src/ln/monitor_tests.rs @@ -10,13 +10,14 @@ //! Further functional tests which test blockchain reorganizations. use crate::sign::{ecdsa::EcdsaChannelSigner, OutputSpender, SpendableOutputDescriptor}; -use crate::chain::channelmonitor::{ANTI_REORG_DELAY, LATENCY_GRACE_PERIOD_BLOCKS, Balance}; +use crate::chain::channelmonitor::{ANTI_REORG_DELAY, LATENCY_GRACE_PERIOD_BLOCKS, Balance, BalanceSource}; use crate::chain::transaction::OutPoint; use crate::chain::chaininterface::{LowerBoundedFeeEstimator, compute_feerate_sat_per_1000_weight}; use crate::events::bump_transaction::{BumpTransactionEvent, WalletSource}; use crate::events::{Event, MessageSendEvent, MessageSendEventsProvider, ClosureReason, HTLCDestination}; use crate::ln::channel; use crate::ln::types::ChannelId; +use crate::ln::chan_utils; use crate::ln::channelmanager::{BREAKDOWN_TIMEOUT, PaymentId, RecipientOnionFields}; use crate::ln::msgs::ChannelMessageHandler; use crate::crypto::utils::sign; @@ -236,13 +237,24 @@ 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 + 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, }], + 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(); @@ -276,11 +288,13 @@ fn do_chanmon_claim_value_coop_close(anchors: bool) { assert_eq!(vec![Balance::ClaimableAwaitingConfirmations { amount_satoshis: 1_000_000 - 1_000 - commitment_tx_fee - anchor_outputs_value, confirmation_height: nodes[0].best_block_info().1 + ANTI_REORG_DELAY - 1, + source: BalanceSource::CoopClose, }], nodes[0].chain_monitor.chain_monitor.get_monitor(funding_outpoint).unwrap().get_claimable_balances()); assert_eq!(vec![Balance::ClaimableAwaitingConfirmations { amount_satoshis: 1000, confirmation_height: nodes[1].best_block_info().1 + ANTI_REORG_DELAY - 1, + source: BalanceSource::CoopClose, }], nodes[1].chain_monitor.chain_monitor.get_monitor(funding_outpoint).unwrap().get_claimable_balances()); @@ -385,10 +399,10 @@ fn do_test_claim_value_force_close(anchors: bool, prev_commitment_tx: bool) { assert_eq!(ChannelId::v1_from_funding_outpoint(funding_outpoint), chan_id); // This HTLC is immediately claimed, giving node B the preimage - let (payment_preimage, payment_hash, ..) = route_payment(&nodes[0], &[&nodes[1]], 3_000_000); + let (payment_preimage, payment_hash, ..) = route_payment(&nodes[0], &[&nodes[1]], 3_000_100); // This HTLC is allowed to time out, letting A claim it. However, in order to test claimable // balances more fully we also give B the preimage for this HTLC. - let (timeout_payment_preimage, timeout_payment_hash, ..) = route_payment(&nodes[0], &[&nodes[1]], 4_000_000); + let (timeout_payment_preimage, timeout_payment_hash, ..) = route_payment(&nodes[0], &[&nodes[1]], 4_000_200); // This HTLC will be dust, and not be claimable at all: let (dust_payment_preimage, dust_payment_hash, ..) = route_payment(&nodes[0], &[&nodes[1]], 3_000); @@ -402,11 +416,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, @@ -434,20 +450,30 @@ 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; + (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::ClaimableOnChannelClose { - amount_satoshis: 1_000_000 - 3_000 - 4_000 - 1_000 - 3 - commitment_tx_fee - anchor_outputs_value, + amount_satoshis: 1_000_000 - 3_000 - 4_000 - 1_000 - 3 - commitment_tx_fee - anchor_outputs_value - 1 /* msat amount that is burned to fees */, + transaction_fee_satoshis: commitment_tx_fee, + outbound_payment_htlc_rounded_msat: 3300, + 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: 3300, }, 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())); nodes[1].node.claim_funds(payment_preimage); check_added_monitors!(nodes[1], 1); - expect_payment_claimed!(nodes[1], payment_hash, 3_000_000); + expect_payment_claimed!(nodes[1], payment_hash, 3_000_100); let b_htlc_msgs = get_htlc_update_msgs!(&nodes[1], nodes[0].node.get_our_node_id()); // We claim the dust payment here as well, but it won't impact our claimable balances as its @@ -458,7 +484,7 @@ fn do_test_claim_value_force_close(anchors: bool, prev_commitment_tx: bool) { nodes[1].node.claim_funds(timeout_payment_preimage); check_added_monitors!(nodes[1], 1); - expect_payment_claimed!(nodes[1], timeout_payment_hash, 4_000_000); + expect_payment_claimed!(nodes[1], timeout_payment_hash, 4_000_200); if prev_commitment_tx { // To build a previous commitment transaction, deliver one round of commitment messages. @@ -478,8 +504,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 @@ -487,7 +513,14 @@ fn do_test_claim_value_force_close(anchors: bool, prev_commitment_tx: bool) { 1_000 - // The push_msat value in satoshis 3 - // The dust HTLC value in satoshis commitment_tx_fee - // The commitment transaction fee with two HTLC outputs - anchor_outputs_value, // The anchor outputs value in satoshis + anchor_outputs_value - // The anchor outputs value in satoshis + 1, // The rounded up msat part of the one HTLC + transaction_fee_satoshis: commitment_tx_fee, + outbound_payment_htlc_rounded_msat: 3000 + if prev_commitment_tx { + 200 /* 1 to-be-failed HTLC */ } else { 300 /* 2 HTLCs */ }, + 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()); @@ -496,6 +529,12 @@ fn do_test_claim_value_force_close(anchors: bool, prev_commitment_tx: bool) { sorted_vec(nodes[0].chain_monitor.chain_monitor.get_monitor(funding_outpoint).unwrap().get_claimable_balances())); 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 + if prev_commitment_tx { + 200 /* 1 HTLC */ } else { 300 /* 2 HTLCs */ }, + inbound_htlc_rounded_msat: 0, }], nodes[1].chain_monitor.chain_monitor.get_monitor(funding_outpoint).unwrap().get_claimable_balances()); @@ -557,10 +596,18 @@ 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, + amount_satoshis: 1_000_000 - // Channel funding value in satoshis + 4_000 - // The to-be-failed HTLC value in satoshis + 3_000 - // The claimed HTLC value in satoshis + 1_000 - // The push_msat value in satoshis + 3 - // The dust HTLC value in satoshis + commitment_tx_fee - // The commitment transaction fee with two HTLC outputs + anchor_outputs_value - // The anchor outputs value in satoshis + 1, // The rounded up msat parts of HTLCs confirmation_height: nodes[0].best_block_info().1 + ANTI_REORG_DELAY - 1, + source: BalanceSource::CounterpartyForceClosed, }, 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())); // The main non-HTLC balance is just awaiting confirmations, but the claimable height is the @@ -568,6 +615,7 @@ fn do_test_claim_value_force_close(anchors: bool, prev_commitment_tx: bool) { assert_eq!(sorted_vec(vec![Balance::ClaimableAwaitingConfirmations { amount_satoshis: 1_000, confirmation_height: node_b_commitment_claimable, + source: BalanceSource::HolderForceClosed, }, // Both HTLC balances are "contentious" as our counterparty could claim them if we wait too // long. @@ -585,6 +633,7 @@ fn do_test_claim_value_force_close(anchors: bool, prev_commitment_tx: bool) { assert_eq!(sorted_vec(vec![Balance::ClaimableAwaitingConfirmations { amount_satoshis: 1_000, confirmation_height: node_b_commitment_claimable, + source: BalanceSource::HolderForceClosed, }, received_htlc_claiming_balance.clone(), received_htlc_timeout_claiming_balance.clone()]), sorted_vec(nodes[1].chain_monitor.chain_monitor.get_monitor(funding_outpoint).unwrap().get_claimable_balances())); @@ -626,6 +675,7 @@ fn do_test_claim_value_force_close(anchors: bool, prev_commitment_tx: bool) { assert_eq!(vec![Balance::ClaimableAwaitingConfirmations { amount_satoshis: 4_000, confirmation_height: nodes[0].best_block_info().1 + ANTI_REORG_DELAY - 1, + source: BalanceSource::Htlc, }], nodes[0].chain_monitor.chain_monitor.get_monitor(funding_outpoint).unwrap().get_claimable_balances()); // After ANTI_REORG_DELAY, A will generate a SpendableOutputs event and drop the claimable @@ -646,9 +696,11 @@ fn do_test_claim_value_force_close(anchors: bool, prev_commitment_tx: bool) { assert_eq!(sorted_vec(vec![Balance::ClaimableAwaitingConfirmations { amount_satoshis: 1_000, confirmation_height: node_b_commitment_claimable, + source: BalanceSource::HolderForceClosed, }, Balance::ClaimableAwaitingConfirmations { amount_satoshis: 3_000, confirmation_height: node_b_htlc_claimable, + source: BalanceSource::Htlc, }, received_htlc_timeout_claiming_balance.clone()]), sorted_vec(nodes[1].chain_monitor.chain_monitor.get_monitor(funding_outpoint).unwrap().get_claimable_balances())); @@ -660,6 +712,7 @@ fn do_test_claim_value_force_close(anchors: bool, prev_commitment_tx: bool) { assert_eq!(sorted_vec(vec![Balance::ClaimableAwaitingConfirmations { amount_satoshis: 3_000, confirmation_height: node_b_htlc_claimable, + source: BalanceSource::Htlc, }, received_htlc_timeout_claiming_balance.clone()]), sorted_vec(nodes[1].chain_monitor.chain_monitor.get_monitor(funding_outpoint).unwrap().get_claimable_balances())); @@ -803,19 +856,22 @@ 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 * - (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, confirmation_height: node_a_commitment_claimable, + source: BalanceSource::HolderForceClosed, }, htlc_balance_known_preimage.clone(), htlc_balance_unknown_preimage.clone()]), sorted_vec(nodes[0].chain_monitor.chain_monitor.get_monitor(funding_outpoint).unwrap().get_claimable_balances())); @@ -834,6 +890,7 @@ fn do_test_balances_on_local_commitment_htlcs(anchors: bool) { assert_eq!(sorted_vec(vec![Balance::ClaimableAwaitingConfirmations { amount_satoshis: 1_000_000 - 10_000 - 20_000 - commitment_tx_fee - anchor_outputs_value, confirmation_height: node_a_commitment_claimable, + source: BalanceSource::HolderForceClosed, }, htlc_balance_known_preimage.clone(), htlc_balance_unknown_preimage.clone()]), sorted_vec(nodes[0].chain_monitor.chain_monitor.get_monitor(funding_outpoint).unwrap().get_claimable_balances())); if anchors { @@ -854,9 +911,11 @@ fn do_test_balances_on_local_commitment_htlcs(anchors: bool) { assert_eq!(sorted_vec(vec![Balance::ClaimableAwaitingConfirmations { amount_satoshis: 1_000_000 - 10_000 - 20_000 - commitment_tx_fee - anchor_outputs_value, confirmation_height: node_a_commitment_claimable, + source: BalanceSource::HolderForceClosed, }, Balance::ClaimableAwaitingConfirmations { amount_satoshis: 10_000, confirmation_height: node_a_htlc_claimable, + source: BalanceSource::Htlc, }, htlc_balance_unknown_preimage.clone()]), sorted_vec(nodes[0].chain_monitor.chain_monitor.get_monitor(funding_outpoint).unwrap().get_claimable_balances())); @@ -867,9 +926,11 @@ fn do_test_balances_on_local_commitment_htlcs(anchors: bool) { assert_eq!(sorted_vec(vec![Balance::ClaimableAwaitingConfirmations { amount_satoshis: 1_000_000 - 10_000 - 20_000 - commitment_tx_fee - anchor_outputs_value, confirmation_height: node_a_commitment_claimable, + source: BalanceSource::HolderForceClosed, }, Balance::ClaimableAwaitingConfirmations { amount_satoshis: 10_000, confirmation_height: node_a_htlc_claimable, + source: BalanceSource::Htlc, }, htlc_balance_unknown_preimage.clone()]), sorted_vec(nodes[0].chain_monitor.chain_monitor.get_monitor(funding_outpoint).unwrap().get_claimable_balances())); @@ -882,9 +943,11 @@ fn do_test_balances_on_local_commitment_htlcs(anchors: bool) { assert_eq!(sorted_vec(vec![Balance::ClaimableAwaitingConfirmations { amount_satoshis: 1_000_000 - 10_000 - 20_000 - commitment_tx_fee - anchor_outputs_value, confirmation_height: node_a_commitment_claimable, + source: BalanceSource::HolderForceClosed, }, Balance::ClaimableAwaitingConfirmations { amount_satoshis: 10_000, confirmation_height: node_a_htlc_claimable, + source: BalanceSource::Htlc, }]), sorted_vec(nodes[0].chain_monitor.chain_monitor.get_monitor(funding_outpoint).unwrap().get_claimable_balances())); @@ -897,6 +960,7 @@ fn do_test_balances_on_local_commitment_htlcs(anchors: bool) { assert_eq!(vec![Balance::ClaimableAwaitingConfirmations { amount_satoshis: 10_000, confirmation_height: node_a_htlc_claimable, + source: BalanceSource::Htlc, }], nodes[0].chain_monitor.chain_monitor.get_monitor(funding_outpoint).unwrap().get_claimable_balances()); let to_self_spendable_output = test_spendable_output(&nodes[0], &commitment_tx, false); @@ -950,6 +1014,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, @@ -965,20 +1030,31 @@ 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 // receive the preimage. These will remain the same through the channel closure and until the // HTLC output is spent. - + let commitment_tx_fee = chan_feerate * + (chan_utils::commitment_tx_base_weight(&channel_type_features) + 2 * chan_utils::COMMITMENT_TX_WEIGHT_PER_HTLC) / 1000; 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, + 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())); @@ -993,8 +1069,9 @@ 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, + source: BalanceSource::HolderForceClosed, }, a_received_htlc_balance.clone(), a_sent_htlc_balance.clone()]); mine_transaction(&nodes[0], &as_txn[0]); @@ -1015,6 +1092,7 @@ fn test_no_preimage_inbound_htlc_balances() { let mut bs_pre_spend_claims = sorted_vec(vec![Balance::ClaimableAwaitingConfirmations { amount_satoshis: 500_000 - 20_000, confirmation_height: node_b_commitment_claimable, + source: BalanceSource::CounterpartyForceClosed, }, b_received_htlc_balance.clone(), b_sent_htlc_balance.clone()]); assert_eq!(bs_pre_spend_claims, sorted_vec(nodes[1].chain_monitor.chain_monitor.get_monitor(funding_outpoint).unwrap().get_claimable_balances())); @@ -1065,22 +1143,26 @@ 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, + source: BalanceSource::HolderForceClosed, }, a_received_htlc_balance.clone(), Balance::ClaimableAwaitingConfirmations { amount_satoshis: 10_000, confirmation_height: as_timeout_claimable_height, + source: BalanceSource::Htlc, }]), sorted_vec(nodes[0].chain_monitor.chain_monitor.get_monitor(funding_outpoint).unwrap().get_claimable_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, + source: BalanceSource::HolderForceClosed, }, a_received_htlc_balance.clone(), Balance::ClaimableAwaitingConfirmations { amount_satoshis: 10_000, confirmation_height: as_timeout_claimable_height, + source: BalanceSource::Htlc, }]), sorted_vec(nodes[0].chain_monitor.chain_monitor.get_monitor(funding_outpoint).unwrap().get_claimable_balances())); @@ -1092,11 +1174,13 @@ 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, + source: BalanceSource::HolderForceClosed, }, Balance::ClaimableAwaitingConfirmations { amount_satoshis: 10_000, confirmation_height: core::cmp::max(as_timeout_claimable_height, htlc_cltv_timeout), + source: BalanceSource::Htlc, }]), sorted_vec(nodes[0].chain_monitor.chain_monitor.get_monitor(funding_outpoint).unwrap().get_claimable_balances())); @@ -1104,6 +1188,7 @@ fn test_no_preimage_inbound_htlc_balances() { assert_eq!(vec![Balance::ClaimableAwaitingConfirmations { amount_satoshis: 10_000, confirmation_height: core::cmp::max(as_timeout_claimable_height, htlc_cltv_timeout), + source: BalanceSource::Htlc, }], nodes[0].chain_monitor.chain_monitor.get_monitor(funding_outpoint).unwrap().get_claimable_balances()); test_spendable_output(&nodes[0], &as_txn[0], false); @@ -1119,6 +1204,7 @@ fn test_no_preimage_inbound_htlc_balances() { assert_eq!(sorted_vec(vec![b_received_htlc_balance.clone(), Balance::ClaimableAwaitingConfirmations { amount_satoshis: 20_000, confirmation_height: bs_timeout_claimable_height, + source: BalanceSource::Htlc, }]), sorted_vec(nodes[1].chain_monitor.chain_monitor.get_monitor(funding_outpoint).unwrap().get_claimable_balances())); @@ -1126,6 +1212,7 @@ fn test_no_preimage_inbound_htlc_balances() { assert_eq!(sorted_vec(vec![b_received_htlc_balance.clone(), Balance::ClaimableAwaitingConfirmations { amount_satoshis: 20_000, confirmation_height: bs_timeout_claimable_height, + source: BalanceSource::Htlc, }]), sorted_vec(nodes[1].chain_monitor.chain_monitor.get_monitor(funding_outpoint).unwrap().get_claimable_balances())); @@ -1192,8 +1279,8 @@ fn do_test_revoked_counterparty_commitment_balances(anchors: bool, confirm_htlc_ // are all currently claimed in separate transactions, which helps us test as we can claim // HTLCs individually. - let (claimed_payment_preimage, claimed_payment_hash, ..) = route_payment(&nodes[0], &[&nodes[1]], 3_000_000); - let timeout_payment_hash = route_payment(&nodes[1], &[&nodes[0]], 4_000_000).1; + let (claimed_payment_preimage, claimed_payment_hash, ..) = route_payment(&nodes[0], &[&nodes[1]], 3_000_100); + let timeout_payment_hash = route_payment(&nodes[1], &[&nodes[0]], 4_000_200).1; let dust_payment_hash = route_payment(&nodes[1], &[&nodes[0]], 3_000).1; let htlc_cltv_timeout = nodes[0].best_block_info().1 + TEST_FINAL_CLTV + 1; // Note ChannelManager adds one to CLTV timeouts for safety @@ -1214,7 +1301,7 @@ fn do_test_revoked_counterparty_commitment_balances(anchors: bool, confirm_htlc_ let missing_htlc_payment_hash = route_payment(&nodes[1], &[&nodes[0]], 2_000_000).1; nodes[1].node.claim_funds(claimed_payment_preimage); - expect_payment_claimed!(nodes[1], claimed_payment_hash, 3_000_000); + expect_payment_claimed!(nodes[1], claimed_payment_hash, 3_000_100); check_added_monitors!(nodes[1], 1); let _b_htlc_msgs = get_htlc_update_msgs!(&nodes[1], nodes[0].node.get_our_node_id()); @@ -1256,19 +1343,27 @@ fn do_test_revoked_counterparty_commitment_balances(anchors: bool, confirm_htlc_ // Prior to channel closure, B considers the preimage HTLC as its own, and otherwise only // lists the two on-chain timeout-able HTLCs as claimable balances. assert_eq!(sorted_vec(vec![Balance::ClaimableOnChannelClose { - amount_satoshis: 100_000 - 5_000 - 4_000 - 3 - 2_000 + 3_000, + amount_satoshis: 100_000 - 5_000 - 4_000 - 3 - 2_000 + 3_000 - 1 /* rounded up msat parts of HTLCs */, + transaction_fee_satoshis: 0, + outbound_payment_htlc_rounded_msat: 3200, + outbound_forwarded_htlc_rounded_msat: 0, + inbound_claiming_htlc_rounded_msat: 100, + inbound_htlc_rounded_msat: 0, }, Balance::MaybeTimeoutClaimableHTLC { 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())); @@ -1292,7 +1387,7 @@ fn do_test_revoked_counterparty_commitment_balances(anchors: bool, confirm_htlc_ fuzzy_assert_eq(claim_txn[3].weight().to_wu(), 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 / 1000; let outbound_htlc_claim_fee = chan_feerate * outbound_htlc_claim_exp_weight / 1000; @@ -1300,10 +1395,11 @@ fn do_test_revoked_counterparty_commitment_balances(anchors: bool, confirm_htlc_ // The expected balance for the next three checks, with the largest-HTLC and to_self output // claim balances separated out. - let expected_balance = vec![Balance::ClaimableAwaitingConfirmations { + let expected_balance_b = vec![Balance::ClaimableAwaitingConfirmations { // to_remote output in A's revoked commitment - amount_satoshis: 100_000 - 5_000 - 4_000 - 3, + amount_satoshis: 100_000 - 5_000 - 4_000 - 3 - 1 /* rounded up msat parts of HTLCs */, confirmation_height: nodes[1].best_block_info().1 + 5, + source: BalanceSource::CounterpartyForceClosed, }, Balance::CounterpartyRevokedOutputClaimable { amount_satoshis: 3_000, }, Balance::CounterpartyRevokedOutputClaimable { @@ -1311,7 +1407,7 @@ fn do_test_revoked_counterparty_commitment_balances(anchors: bool, confirm_htlc_ }]; let to_self_unclaimed_balance = Balance::CounterpartyRevokedOutputClaimable { - amount_satoshis: 1_000_000 - 100_000 - 3_000 - commitment_tx_fee - anchor_outputs_value, + amount_satoshis: 1_000_000 - 100_000 - 3_000 - commitment_tx_fee - anchor_outputs_value - 1 /* rounded up msat parts of HTLCs */, }; let to_self_claimed_avail_height; let largest_htlc_unclaimed_balance = Balance::CounterpartyRevokedOutputClaimable { @@ -1321,7 +1417,7 @@ fn do_test_revoked_counterparty_commitment_balances(anchors: bool, confirm_htlc_ // Once the channel has been closed by A, B now considers all of the commitment transactions' // outputs as `CounterpartyRevokedOutputClaimable`. - assert_eq!(sorted_vec_with_additions(&expected_balance, &[&to_self_unclaimed_balance, &largest_htlc_unclaimed_balance]), + assert_eq!(sorted_vec_with_additions(&expected_balance_b, &[&to_self_unclaimed_balance, &largest_htlc_unclaimed_balance]), sorted_vec(nodes[1].chain_monitor.chain_monitor.get_monitor(funding_outpoint).unwrap().get_claimable_balances())); if confirm_htlc_spend_first { @@ -1338,17 +1434,19 @@ fn do_test_revoked_counterparty_commitment_balances(anchors: bool, confirm_htlc_ let largest_htlc_claimed_balance = Balance::ClaimableAwaitingConfirmations { amount_satoshis: 5_000 - inbound_htlc_claim_fee, confirmation_height: largest_htlc_claimed_avail_height, + source: BalanceSource::CounterpartyForceClosed, }; let to_self_claimed_balance = Balance::ClaimableAwaitingConfirmations { - amount_satoshis: 1_000_000 - 100_000 - 3_000 - commitment_tx_fee - anchor_outputs_value - to_self_claim_fee, + amount_satoshis: 1_000_000 - 100_000 - 3_000 - commitment_tx_fee - anchor_outputs_value - to_self_claim_fee - 1 /* rounded up msat parts of HTLCs */, confirmation_height: to_self_claimed_avail_height, + source: BalanceSource::CounterpartyForceClosed, }; if confirm_htlc_spend_first { - assert_eq!(sorted_vec_with_additions(&expected_balance, &[&to_self_unclaimed_balance, &largest_htlc_claimed_balance]), + assert_eq!(sorted_vec_with_additions(&expected_balance_b, &[&to_self_unclaimed_balance, &largest_htlc_claimed_balance]), sorted_vec(nodes[1].chain_monitor.chain_monitor.get_monitor(funding_outpoint).unwrap().get_claimable_balances())); } else { - assert_eq!(sorted_vec_with_additions(&expected_balance, &[&to_self_claimed_balance, &largest_htlc_unclaimed_balance]), + assert_eq!(sorted_vec_with_additions(&expected_balance_b, &[&to_self_claimed_balance, &largest_htlc_unclaimed_balance]), sorted_vec(nodes[1].chain_monitor.chain_monitor.get_monitor(funding_outpoint).unwrap().get_claimable_balances())); } @@ -1357,7 +1455,7 @@ fn do_test_revoked_counterparty_commitment_balances(anchors: bool, confirm_htlc_ } else { mine_transaction(&nodes[1], &claim_txn[2]); } - assert_eq!(sorted_vec_with_additions(&expected_balance, &[&to_self_claimed_balance, &largest_htlc_claimed_balance]), + assert_eq!(sorted_vec_with_additions(&expected_balance_b, &[&to_self_claimed_balance, &largest_htlc_claimed_balance]), sorted_vec(nodes[1].chain_monitor.chain_monitor.get_monitor(funding_outpoint).unwrap().get_claimable_balances())); // Finally, connect the last two remaining HTLC spends and check that they move to @@ -1367,20 +1465,25 @@ fn do_test_revoked_counterparty_commitment_balances(anchors: bool, confirm_htlc_ assert_eq!(sorted_vec(vec![Balance::ClaimableAwaitingConfirmations { // to_remote output in A's revoked commitment - amount_satoshis: 100_000 - 5_000 - 4_000 - 3, + amount_satoshis: 100_000 - 5_000 - 4_000 - 3 - 1 /* rounded up msat parts of HTLCs */, confirmation_height: nodes[1].best_block_info().1 + 1, + source: BalanceSource::CounterpartyForceClosed, }, Balance::ClaimableAwaitingConfirmations { - amount_satoshis: 1_000_000 - 100_000 - 3_000 - commitment_tx_fee - anchor_outputs_value - to_self_claim_fee, + amount_satoshis: 1_000_000 - 100_000 - 3_000 - commitment_tx_fee - anchor_outputs_value - to_self_claim_fee - 1 /* rounded up msat parts of HTLCs */, confirmation_height: to_self_claimed_avail_height, + source: BalanceSource::CounterpartyForceClosed, }, Balance::ClaimableAwaitingConfirmations { amount_satoshis: 3_000 - outbound_htlc_claim_fee, confirmation_height: nodes[1].best_block_info().1 + 4, + source: BalanceSource::CounterpartyForceClosed, }, Balance::ClaimableAwaitingConfirmations { amount_satoshis: 4_000 - inbound_htlc_claim_fee, confirmation_height: nodes[1].best_block_info().1 + 5, + source: BalanceSource::CounterpartyForceClosed, }, Balance::ClaimableAwaitingConfirmations { amount_satoshis: 5_000 - inbound_htlc_claim_fee, confirmation_height: largest_htlc_claimed_avail_height, + source: BalanceSource::CounterpartyForceClosed, }]), sorted_vec(nodes[1].chain_monitor.chain_monitor.get_monitor(funding_outpoint).unwrap().get_claimable_balances())); @@ -1461,7 +1564,7 @@ fn do_test_revoked_counterparty_htlc_tx_balances(anchors: bool) { let funding_outpoint = OutPoint { txid: funding_tx.txid(), index: 0 }; assert_eq!(ChannelId::v1_from_funding_outpoint(funding_outpoint), chan_id); - let payment_preimage = route_payment(&nodes[0], &[&nodes[1]], 3_000_000).0; + let payment_preimage = route_payment(&nodes[0], &[&nodes[1]], 3_000_100).0; let failed_payment_hash = route_payment(&nodes[1], &[&nodes[0]], 1_000_000).1; let revoked_local_txn = get_local_commitment_txn!(nodes[1], chan_id); assert_eq!(revoked_local_txn[0].input.len(), 1); @@ -1552,12 +1655,13 @@ 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 - amount_satoshis: 1_000_000 - 12_000 - 3_000 - commitment_tx_fee - anchor_outputs_value, + amount_satoshis: 1_000_000 - 12_000 - 3_000 - commitment_tx_fee - anchor_outputs_value - 1 /* The rounded up msat part of the one HTLC */, confirmation_height: to_remote_conf_height, + source: BalanceSource::CounterpartyForceClosed, }, Balance::CounterpartyRevokedOutputClaimable { // to_self output in B's revoked commitment amount_satoshis: 11_000, @@ -1601,8 +1705,9 @@ fn do_test_revoked_counterparty_htlc_tx_balances(anchors: bool) { mine_transaction(&nodes[0], &as_htlc_claim_tx[0]); assert_eq!(sorted_vec(vec![Balance::ClaimableAwaitingConfirmations { // to_remote output in B's revoked commitment - amount_satoshis: 1_000_000 - 12_000 - 3_000 - commitment_tx_fee - anchor_outputs_value, + amount_satoshis: 1_000_000 - 12_000 - 3_000 - commitment_tx_fee - anchor_outputs_value - 1 /* rounded up msat parts of HTLCs */, confirmation_height: to_remote_conf_height, + source: BalanceSource::CounterpartyForceClosed, }, Balance::CounterpartyRevokedOutputClaimable { // to_self output in B's revoked commitment amount_satoshis: 11_000, @@ -1611,6 +1716,7 @@ fn do_test_revoked_counterparty_htlc_tx_balances(anchors: bool) { }, Balance::ClaimableAwaitingConfirmations { amount_satoshis: as_htlc_claim_tx[0].output[0].value.to_sat(), confirmation_height: nodes[0].best_block_info().1 + ANTI_REORG_DELAY - 1, + source: BalanceSource::CounterpartyForceClosed, }]), sorted_vec(nodes[0].chain_monitor.chain_monitor.get_monitor(funding_outpoint).unwrap().get_claimable_balances())); @@ -1624,6 +1730,7 @@ fn do_test_revoked_counterparty_htlc_tx_balances(anchors: bool) { }, Balance::ClaimableAwaitingConfirmations { amount_satoshis: as_htlc_claim_tx[0].output[0].value.to_sat(), confirmation_height: nodes[0].best_block_info().1 + 2, + source: BalanceSource::CounterpartyForceClosed, }]), sorted_vec(nodes[0].chain_monitor.chain_monitor.get_monitor(funding_outpoint).unwrap().get_claimable_balances())); @@ -1693,6 +1800,7 @@ fn do_test_revoked_counterparty_htlc_tx_balances(anchors: bool) { }, Balance::ClaimableAwaitingConfirmations { amount_satoshis: revoked_htlc_timeout_claim.output[0].value.to_sat(), confirmation_height: nodes[0].best_block_info().1 + ANTI_REORG_DELAY - 1, + source: BalanceSource::CounterpartyForceClosed, }]), sorted_vec(nodes[0].chain_monitor.chain_monitor.get_monitor(funding_outpoint).unwrap().get_claimable_balances())); @@ -1701,9 +1809,11 @@ fn do_test_revoked_counterparty_htlc_tx_balances(anchors: bool) { // to_self output in B's revoked commitment amount_satoshis: revoked_to_self_claim.output[0].value.to_sat(), confirmation_height: nodes[0].best_block_info().1 + ANTI_REORG_DELAY - 1, + source: BalanceSource::CounterpartyForceClosed, }, Balance::ClaimableAwaitingConfirmations { amount_satoshis: revoked_htlc_timeout_claim.output[0].value.to_sat(), confirmation_height: nodes[0].best_block_info().1 + ANTI_REORG_DELAY - 2, + source: BalanceSource::CounterpartyForceClosed, }]), sorted_vec(nodes[0].chain_monitor.chain_monitor.get_monitor(funding_outpoint).unwrap().get_claimable_balances())); @@ -1767,7 +1877,7 @@ fn do_test_revoked_counterparty_aggregated_claims(anchors: bool) { // transaction, and one which we will not, allowing B to claim the HTLC output in an aggregated // revocation-claim transaction. - let (claimed_payment_preimage, claimed_payment_hash, ..) = route_payment(&nodes[1], &[&nodes[0]], 3_000_000); + let (claimed_payment_preimage, claimed_payment_hash, ..) = route_payment(&nodes[1], &[&nodes[0]], 3_000_100); let revoked_payment_hash = route_payment(&nodes[1], &[&nodes[0]], 4_000_000).1; let htlc_cltv_timeout = nodes[1].best_block_info().1 + TEST_FINAL_CLTV + 1; // Note ChannelManager adds one to CLTV timeouts for safety @@ -1801,20 +1911,27 @@ fn do_test_revoked_counterparty_aggregated_claims(anchors: bool) { commitment_signed_dance!(nodes[1], nodes[0], fee_update.commitment_signed, false); nodes[0].node.claim_funds(claimed_payment_preimage); - expect_payment_claimed!(nodes[0], claimed_payment_hash, 3_000_000); + expect_payment_claimed!(nodes[0], claimed_payment_hash, 3_000_100); check_added_monitors!(nodes[0], 1); let _a_htlc_msgs = get_htlc_update_msgs!(&nodes[0], nodes[1].node.get_our_node_id()); assert_eq!(sorted_vec(vec![Balance::ClaimableOnChannelClose { - amount_satoshis: 100_000 - 4_000 - 3_000, + amount_satoshis: 100_000 - 4_000 - 3_000 - 1 /* rounded up msat parts of HTLCs */, + transaction_fee_satoshis: 0, + outbound_payment_htlc_rounded_msat: 100, + 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, 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())); @@ -1846,12 +1963,13 @@ 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 - amount_satoshis: 100_000 - 4_000 - 3_000, + amount_satoshis: 100_000 - 4_000 - 3_000 - 1 /* rounded up msat parts of HTLCs */, confirmation_height: to_remote_maturity, + source: BalanceSource::CounterpartyForceClosed, }, Balance::CounterpartyRevokedOutputClaimable { // to_self output in A's revoked commitment amount_satoshis: 1_000_000 - 100_000 - commitment_tx_fee - anchor_outputs_value, @@ -1905,8 +2023,9 @@ fn do_test_revoked_counterparty_aggregated_claims(anchors: bool) { assert_eq!(sorted_vec(vec![Balance::ClaimableAwaitingConfirmations { // to_remote output in A's revoked commitment - amount_satoshis: 100_000 - 4_000 - 3_000, + amount_satoshis: 100_000 - 4_000 - 3_000 - 1 /* rounded up msat parts of HTLCs */, confirmation_height: to_remote_maturity, + source: BalanceSource::CounterpartyForceClosed, }, Balance::CounterpartyRevokedOutputClaimable { // to_self output in A's revoked commitment amount_satoshis: 1_000_000 - 100_000 - commitment_tx_fee - anchor_outputs_value, @@ -1947,6 +2066,7 @@ fn do_test_revoked_counterparty_aggregated_claims(anchors: bool) { }, Balance::ClaimableAwaitingConfirmations { // HTLC 2 amount_satoshis: claim_txn_2[0].output[0].value.to_sat(), confirmation_height: htlc_2_claim_maturity, + source: BalanceSource::CounterpartyForceClosed, }]), sorted_vec(nodes[1].chain_monitor.chain_monitor.get_monitor(funding_outpoint).unwrap().get_claimable_balances())); @@ -1972,15 +2092,18 @@ fn do_test_revoked_counterparty_aggregated_claims(anchors: bool) { assert_eq!(vec![Balance::ClaimableAwaitingConfirmations { amount_satoshis: claim_txn_2[1].output[0].value.to_sat(), confirmation_height: rest_claim_maturity, + source: BalanceSource::CounterpartyForceClosed, }, Balance::ClaimableAwaitingConfirmations { amount_satoshis: revoked_to_self_claim.as_ref().unwrap().output[0].value.to_sat(), confirmation_height: rest_claim_maturity, + source: BalanceSource::CounterpartyForceClosed, }], nodes[1].chain_monitor.chain_monitor.get_monitor(funding_outpoint).unwrap().get_claimable_balances()); } else { assert_eq!(vec![Balance::ClaimableAwaitingConfirmations { amount_satoshis: claim_txn_2[1].output[0].value.to_sat(), confirmation_height: rest_claim_maturity, + source: BalanceSource::CounterpartyForceClosed, }], nodes[1].chain_monitor.chain_monitor.get_monitor(funding_outpoint).unwrap().get_claimable_balances()); } @@ -2022,6 +2145,100 @@ fn test_revoked_counterparty_aggregated_claims() { do_test_revoked_counterparty_aggregated_claims(true); } +fn do_test_claimable_balance_correct_while_payment_pending(outbound_payment: bool, anchors: bool) { + // Previously when a user fetched their balances via `get_claimable_balances` after forwarding a + // payment, but before it cleared, and summed up their balance using `Balance::claimable_amount_satoshis` + // neither the value of preimage claimable HTLC nor the timeout claimable HTLC would be included. + // This was incorrect as exactly one of these outcomes is true. This has been fixed by including the + // timeout claimable HTLC value in the balance as this excludes the routing fees and is the more + // prudent approach. + // + // In the case of the holder sending a payment, the above value will not be included while the payment + // is pending. + // + // This tests that we get the correct balance in either of the cases above. + let mut chanmon_cfgs = create_chanmon_cfgs(3); + let node_cfgs = create_node_cfgs(3, &chanmon_cfgs); + let mut user_config = test_default_channel_config(); + if anchors { + user_config.channel_handshake_config.negotiate_anchors_zero_fee_htlc_tx = true; + user_config.manually_accept_inbound_channels = true; + } + let node_chanmgrs = create_node_chanmgrs(3, &node_cfgs, &[Some(user_config), Some(user_config), Some(user_config)]); + let nodes = create_network(3, &node_cfgs, &node_chanmgrs); + + let coinbase_tx = Transaction { + version: Version::TWO, + lock_time: LockTime::ZERO, + input: vec![TxIn { ..Default::default() }], + output: vec![ + TxOut { + value: Amount::ONE_BTC, + script_pubkey: nodes[0].wallet_source.get_change_script().unwrap(), + }, + TxOut { + value: Amount::ONE_BTC, + script_pubkey: nodes[1].wallet_source.get_change_script().unwrap(), + }, + ], + }; + if anchors { + nodes[0].wallet_source.add_utxo(bitcoin::OutPoint { txid: coinbase_tx.txid(), vout: 0 }, coinbase_tx.output[0].value); + nodes[1].wallet_source.add_utxo(bitcoin::OutPoint { txid: coinbase_tx.txid(), vout: 1 }, coinbase_tx.output[1].value); + } + + // Create a channel from A -> B + let (_, _, chan_ab_id, funding_tx_ab) = + create_announced_chan_between_nodes_with_value(&nodes, 0, 1, 1_000_000 /* channel_value (sat) */, 0 /* push_msat */); + let funding_outpoint_ab = OutPoint { txid: funding_tx_ab.txid(), index: 0 }; + assert_eq!(ChannelId::v1_from_funding_outpoint(funding_outpoint_ab), chan_ab_id); + // Create a channel from B -> C + let (_, _, chan_bc_id, funding_tx_bc) = + create_announced_chan_between_nodes_with_value(&nodes, 1, 2, 1_000_000 /* channel_value (sat) */, 0 /* push_msat */); + let funding_outpoint_bc = OutPoint { txid: funding_tx_bc.txid(), index: 0 }; + assert_eq!(ChannelId::v1_from_funding_outpoint(funding_outpoint_bc), chan_bc_id); + + let (chan_feerate, channel_type_features) = if outbound_payment { + let chan_ab_feerate = get_feerate!(nodes[0], nodes[1], chan_ab_id); + let channel_type_features_ab = get_channel_type_features!(nodes[0], nodes[1], chan_ab_id); + (chan_ab_feerate, channel_type_features_ab) + } else { + let chan_bc_feerate = get_feerate!(nodes[1], nodes[2], chan_bc_id); + let channel_type_features_bc = get_channel_type_features!(nodes[1], nodes[2], chan_bc_id); + (chan_bc_feerate, channel_type_features_bc) + }; + let commitment_tx_fee = chan_feerate as u64 * + (chan_utils::commitment_tx_base_weight(&channel_type_features) + chan_utils::COMMITMENT_TX_WEIGHT_PER_HTLC) / 1000; + + // This HTLC will be forwarded by B from A -> C + let _ = route_payment(&nodes[0], &[&nodes[1], &nodes[2]], 4_000_000); + let anchor_outputs_value = if anchors { 2 * channel::ANCHOR_OUTPUT_VALUE_SATOSHI } else { 0 }; + + if outbound_payment { + assert_eq!( + 1_000_000 - commitment_tx_fee - anchor_outputs_value - 4_001 /* Note HTLC timeout amount of 4001 sats is excluded for outbound payment */, + nodes[0].chain_monitor.chain_monitor.get_monitor(funding_outpoint_ab).unwrap().get_claimable_balances().iter().map( + |x| x.claimable_amount_satoshis()).sum()); + } else { + assert_eq!( + 0u64, + nodes[1].chain_monitor.chain_monitor.get_monitor(funding_outpoint_ab).unwrap().get_claimable_balances().iter().map( + |x| x.claimable_amount_satoshis()).sum()); + assert_eq!( + 1_000_000 - commitment_tx_fee - anchor_outputs_value /* Note HTLC timeout amount of 4000 sats is included */, + nodes[1].chain_monitor.chain_monitor.get_monitor(funding_outpoint_bc).unwrap().get_claimable_balances().iter().map( + |x| x.claimable_amount_satoshis()).sum()); + } +} + +#[test] +fn test_claimable_balance_correct_while_payment_pending() { + do_test_claimable_balance_correct_while_payment_pending(false, false); + do_test_claimable_balance_correct_while_payment_pending(false, true); + do_test_claimable_balance_correct_while_payment_pending(true, false); + do_test_claimable_balance_correct_while_payment_pending(true, true); +} + fn do_test_restored_packages_retry(check_old_monitor_retries_after_upgrade: bool) { // Tests that we'll retry packages that were previously timelocked after we've restored them. let chanmon_cfgs = create_chanmon_cfgs(2); diff --git a/lightning/src/ln/payment_tests.rs b/lightning/src/ln/payment_tests.rs index 55dee794612..3ab055d2ada 100644 --- a/lightning/src/ln/payment_tests.rs +++ b/lightning/src/ln/payment_tests.rs @@ -15,11 +15,12 @@ use crate::chain::{ChannelMonitorUpdateStatus, Confirm, Listen}; use crate::chain::channelmonitor::{ANTI_REORG_DELAY, HTLC_FAIL_BACK_BUFFER, LATENCY_GRACE_PERIOD_BLOCKS}; use crate::sign::EntropySource; 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; use crate::ln::types::{ChannelId, PaymentHash, PaymentSecret, PaymentPreimage}; +use crate::ln::chan_utils; use crate::ln::msgs::ChannelMessageHandler; use crate::ln::onion_utils; use crate::ln::outbound_payment::{IDEMPOTENCY_TIMEOUT_TICKS, Retry}; @@ -4182,9 +4183,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();