@@ -70,7 +70,7 @@ use crate::ln::script::{self, ShutdownScript};
7070use crate::ln::types::ChannelId;
7171use crate::routing::gossip::NodeId;
7272use crate::sign::ecdsa::EcdsaChannelSigner;
73- use crate::sign::tx_builder::{SpecTxBuilder, TxBuilder};
73+ use crate::sign::tx_builder::{HTLCAmountDirection, NextCommitmentStats, SpecTxBuilder, TxBuilder};
7474use crate::sign::{ChannelSigner, EntropySource, NodeSigner, Recipient, SignerProvider};
7575use crate::types::features::{ChannelTypeFeatures, InitFeatures};
7676use crate::types::payment::{PaymentHash, PaymentPreimage};
@@ -4104,6 +4104,162 @@ where
41044104 );
41054105 }
41064106
4107+ #[allow(dead_code)]
4108+ fn pending_inbound_htlcs_value_msat(&self) -> u64 {
4109+ self.pending_inbound_htlcs.iter().map(|htlc| htlc.amount_msat).sum()
4110+ }
4111+
4112+ /// Returns a best-effort guess of the set of HTLCs that will be present
4113+ /// on the next local or remote commitment. We cannot be certain as the
4114+ /// actual set of HTLCs present on the next commitment depends on the
4115+ /// ordering of commitment_signed and revoke_and_ack messages.
4116+ ///
4117+ /// We take the conservative approach and only assume that a HTLC will
4118+ /// not be in the next commitment when it is guaranteed that it won't be.
4119+ ///
4120+ /// While we previously took into account HTLCs in the holding cell when
4121+ /// validating channel updates, we now choose to ignore them; our
4122+ /// counterparty certainly does not know about them, and we will re-validate
4123+ /// their addition to the channel upon freeing the holding cell, failing
4124+ /// them backwards if necessary.
4125+ #[allow(dead_code)]
4126+ #[rustfmt::skip]
4127+ fn get_next_commitment_htlcs(
4128+ &self, local: bool, htlc_candidate: Option<HTLCAmountDirection>,
4129+ ) -> Vec<HTLCAmountDirection> {
4130+ let mut commitment_htlcs = Vec::with_capacity(
4131+ 1 + self.pending_inbound_htlcs.len()
4132+ + self.pending_outbound_htlcs.len()
4133+ + self.holding_cell_htlc_updates.len(),
4134+ );
4135+ // `LocalRemoved` HTLCs will certainly not be present on any future remote
4136+ // commitments, but they could be in a future local commitment as the remote has
4137+ // not yet acknowledged the removal.
4138+ let pending_inbound_htlcs = self
4139+ .pending_inbound_htlcs
4140+ .iter()
4141+ .filter(|InboundHTLCOutput { state, .. }| match (state, local) {
4142+ (InboundHTLCState::RemoteAnnounced(..), _) => true,
4143+ (InboundHTLCState::AwaitingRemoteRevokeToAnnounce(..), _) => true,
4144+ (InboundHTLCState::AwaitingAnnouncedRemoteRevoke(..), _) => true,
4145+ (InboundHTLCState::Committed, _) => true,
4146+ (InboundHTLCState::LocalRemoved(..), true) => true,
4147+ (InboundHTLCState::LocalRemoved(..), false) => false,
4148+ })
4149+ .map(|&InboundHTLCOutput { amount_msat, .. }| HTLCAmountDirection { outbound: false, amount_msat });
4150+ // While `LocalAnnounced` HTLCs will for sure be present on the next remote commitment, it is
4151+ // also possible for `LocalAnnounced` HTLCs to be present on the next local commitment if the
4152+ // remote acks the update before producing the next local commitment.
4153+ //
4154+ // `RemoteRemoved` HTLCs can still be present on the next remote commitment if
4155+ // local produces a commitment before acknowledging the update. These HTLCs
4156+ // will for sure not be present on the next local commitment.
4157+ let pending_outbound_htlcs = self
4158+ .pending_outbound_htlcs
4159+ .iter()
4160+ .filter(|OutboundHTLCOutput { state, .. }| match (state, local) {
4161+ (OutboundHTLCState::LocalAnnounced(..), _) => true,
4162+ (OutboundHTLCState::Committed, _) => true,
4163+ (OutboundHTLCState::RemoteRemoved(..), true) => false,
4164+ (OutboundHTLCState::RemoteRemoved(..), false) => true,
4165+ (OutboundHTLCState::AwaitingRemoteRevokeToRemove(..), _) => false,
4166+ (OutboundHTLCState::AwaitingRemovedRemoteRevoke(..), _) => false,
4167+ })
4168+ .map(|&OutboundHTLCOutput { amount_msat, .. }| HTLCAmountDirection { outbound: true, amount_msat });
4169+
4170+ // We do not include holding cell HTLCs, we will validate them upon freeing the holding cell...
4171+ //let holding_cell_htlcs = self.holding_cell_htlc_updates.iter().filter_map(|htlc| if let HTLCUpdateAwaitingACK::AddHTLC { amount_msat, ..} = htlc { Some(HTLCAmountDirection { outbound: true, amount_msat: *amount_msat }) } else { None });
4172+
4173+ commitment_htlcs.extend(
4174+ htlc_candidate.into_iter().chain(pending_inbound_htlcs).chain(pending_outbound_htlcs),
4175+ );
4176+ commitment_htlcs
4177+ }
4178+
4179+ /// This returns the value of `value_to_self_msat` after accounting for all the
4180+ /// successful inbound and outbound HTLCs that won't be present on the next
4181+ /// commitment.
4182+ ///
4183+ /// To determine which HTLC claims to account for, we take the cases where a HTLC
4184+ /// will *not* be present on the next commitment from `next_commitment_htlcs`, and
4185+ /// check if their outcome is successful. If it is, we add the value of this claimed
4186+ /// HTLC to the balance of the claimer.
4187+ #[allow(dead_code)]
4188+ #[rustfmt::skip]
4189+ fn get_next_commitment_value_to_self_msat(&self, local: bool, funding: &FundingScope) -> u64 {
4190+ let inbound_claimed_htlc_msat: u64 =
4191+ self.pending_inbound_htlcs
4192+ .iter()
4193+ .filter(|InboundHTLCOutput { state, .. }| match (state, local) {
4194+ (InboundHTLCState::LocalRemoved(InboundHTLCRemovalReason::Fulfill(_, _)), true) => false,
4195+ (InboundHTLCState::LocalRemoved(InboundHTLCRemovalReason::Fulfill(_, _)), false) => true,
4196+ _ => false,
4197+ })
4198+ .map(|InboundHTLCOutput { amount_msat, .. }| amount_msat)
4199+ .sum();
4200+ let outbound_claimed_htlc_msat: u64 =
4201+ self.pending_outbound_htlcs
4202+ .iter()
4203+ .filter(|OutboundHTLCOutput { state, .. }| match (state, local) {
4204+ (OutboundHTLCState::RemoteRemoved(OutboundHTLCOutcome::Success(_, _)), true) => true,
4205+ (OutboundHTLCState::RemoteRemoved(OutboundHTLCOutcome::Success(_, _)), false) => false,
4206+ (OutboundHTLCState::AwaitingRemoteRevokeToRemove(OutboundHTLCOutcome::Success(_, _)), _) => true,
4207+ (OutboundHTLCState::AwaitingRemovedRemoteRevoke(OutboundHTLCOutcome::Success(_, _)), _) => true,
4208+ _ => false,
4209+ })
4210+ .map(|OutboundHTLCOutput { amount_msat, .. }| amount_msat)
4211+ .sum();
4212+
4213+ funding
4214+ .value_to_self_msat
4215+ .saturating_sub(outbound_claimed_htlc_msat)
4216+ .saturating_add(inbound_claimed_htlc_msat)
4217+ }
4218+
4219+ #[allow(dead_code)]
4220+ fn get_next_local_commitment_stats(
4221+ &self, funding: &FundingScope, candidate_htlc: Option<HTLCAmountDirection>,
4222+ addl_nondust_htlc_count: usize, feerate_per_kw: u32,
4223+ dust_exposure_limiting_feerate: Option<u32>,
4224+ ) -> NextCommitmentStats {
4225+ let next_commitment_htlcs = self.get_next_commitment_htlcs(true, candidate_htlc);
4226+ let next_value_to_self_msat = self.get_next_commitment_value_to_self_msat(true, funding);
4227+ SpecTxBuilder {}.get_next_commitment_stats(
4228+ true,
4229+ funding.is_outbound(),
4230+ funding.get_value_satoshis(),
4231+ next_value_to_self_msat,
4232+ next_commitment_htlcs,
4233+ addl_nondust_htlc_count,
4234+ feerate_per_kw,
4235+ dust_exposure_limiting_feerate,
4236+ self.holder_dust_limit_satoshis,
4237+ funding.get_channel_type(),
4238+ )
4239+ }
4240+
4241+ #[allow(dead_code)]
4242+ fn get_next_remote_commitment_stats(
4243+ &self, funding: &FundingScope, candidate_htlc: Option<HTLCAmountDirection>,
4244+ addl_nondust_htlc_count: usize, feerate_per_kw: u32,
4245+ dust_exposure_limiting_feerate: Option<u32>,
4246+ ) -> NextCommitmentStats {
4247+ let next_commitment_htlcs = self.get_next_commitment_htlcs(false, candidate_htlc);
4248+ let next_value_to_self_msat = self.get_next_commitment_value_to_self_msat(false, funding);
4249+ SpecTxBuilder {}.get_next_commitment_stats(
4250+ false,
4251+ funding.is_outbound(),
4252+ funding.get_value_satoshis(),
4253+ next_value_to_self_msat,
4254+ next_commitment_htlcs,
4255+ addl_nondust_htlc_count,
4256+ feerate_per_kw,
4257+ dust_exposure_limiting_feerate,
4258+ self.counterparty_dust_limit_satoshis,
4259+ funding.get_channel_type(),
4260+ )
4261+ }
4262+
41074263 #[rustfmt::skip]
41084264 fn validate_update_add_htlc<F: Deref>(
41094265 &self, funding: &FundingScope, msg: &msgs::UpdateAddHTLC,
0 commit comments