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