@@ -4198,6 +4198,7 @@ impl<SP: SignerProvider> ChannelContext<SP> {
41984198 include_counterparty_unknown_htlcs,
41994199 addl_nondust_htlc_count,
42004200 channel_context.feerate_per_kw,
4201+ false,
42014202 dust_exposure_limiting_feerate,
42024203 )
42034204 .map_err(|()| {
@@ -4494,6 +4495,7 @@ impl<SP: SignerProvider> ChannelContext<SP> {
44944495 include_counterparty_unknown_htlcs,
44954496 addl_nondust_htlc_count,
44964497 channel_context.feerate_per_kw,
4498+ false,
44974499 dust_exposure_limiting_feerate,
44984500 )
44994501 .map_err(|()| APIError::APIMisuseError {
@@ -5284,7 +5286,7 @@ impl<SP: SignerProvider> ChannelContext<SP> {
52845286 fn get_next_local_commitment_stats(
52855287 &self, funding: &FundingScope, htlc_candidate: Option<HTLCAmountDirection>,
52865288 include_counterparty_unknown_htlcs: bool, addl_nondust_htlc_count: usize,
5287- feerate_per_kw: u32, dust_exposure_limiting_feerate: Option<u32>,
5289+ feerate_per_kw: u32, assume_fee_spike: bool, dust_exposure_limiting_feerate: Option<u32>,
52885290 ) -> Result<(ChannelStats, Vec<HTLCAmountDirection>), ()> {
52895291 let next_commitment_htlcs = self.get_next_commitment_htlcs(
52905292 true,
@@ -5306,6 +5308,7 @@ impl<SP: SignerProvider> ChannelContext<SP> {
53065308 &next_commitment_htlcs,
53075309 addl_nondust_htlc_count,
53085310 feerate_per_kw,
5311+ assume_fee_spike,
53095312 dust_exposure_limiting_feerate,
53105313 max_dust_htlc_exposure_msat,
53115314 channel_constraints,
@@ -5330,6 +5333,7 @@ impl<SP: SignerProvider> ChannelContext<SP> {
53305333 &next_commitment_htlcs,
53315334 0,
53325335 feerate_per_kw,
5336+ false,
53335337 dust_exposure_limiting_feerate,
53345338 max_dust_htlc_exposure_msat,
53355339 channel_constraints,
@@ -5351,7 +5355,7 @@ impl<SP: SignerProvider> ChannelContext<SP> {
53515355 fn get_next_remote_commitment_stats(
53525356 &self, funding: &FundingScope, htlc_candidate: Option<HTLCAmountDirection>,
53535357 include_counterparty_unknown_htlcs: bool, addl_nondust_htlc_count: usize,
5354- feerate_per_kw: u32, dust_exposure_limiting_feerate: Option<u32>,
5358+ feerate_per_kw: u32, assume_fee_spike: bool, dust_exposure_limiting_feerate: Option<u32>,
53555359 ) -> Result<(ChannelStats, Vec<HTLCAmountDirection>), ()> {
53565360 let next_commitment_htlcs = self.get_next_commitment_htlcs(
53575361 false,
@@ -5373,6 +5377,7 @@ impl<SP: SignerProvider> ChannelContext<SP> {
53735377 &next_commitment_htlcs,
53745378 addl_nondust_htlc_count,
53755379 feerate_per_kw,
5380+ assume_fee_spike,
53765381 dust_exposure_limiting_feerate,
53775382 max_dust_htlc_exposure_msat,
53785383 channel_constraints,
@@ -5397,6 +5402,7 @@ impl<SP: SignerProvider> ChannelContext<SP> {
53975402 &next_commitment_htlcs,
53985403 0,
53995404 feerate_per_kw,
5405+ false,
54005406 dust_exposure_limiting_feerate,
54015407 max_dust_htlc_exposure_msat,
54025408 channel_constraints,
@@ -5439,6 +5445,7 @@ impl<SP: SignerProvider> ChannelContext<SP> {
54395445 include_counterparty_unknown_htlcs,
54405446 fee_spike_buffer_htlc,
54415447 self.feerate_per_kw,
5448+ false,
54425449 dust_exposure_limiting_feerate,
54435450 )
54445451 .map_err(|()| {
@@ -5497,6 +5504,7 @@ impl<SP: SignerProvider> ChannelContext<SP> {
54975504 include_counterparty_unknown_htlcs,
54985505 fee_spike_buffer_htlc,
54995506 self.feerate_per_kw,
5507+ false,
55005508 dust_exposure_limiting_feerate,
55015509 )
55025510 .map_err(|()| {
@@ -5523,6 +5531,7 @@ impl<SP: SignerProvider> ChannelContext<SP> {
55235531 include_counterparty_unknown_htlcs,
55245532 0,
55255533 new_feerate_per_kw,
5534+ false,
55265535 dust_exposure_limiting_feerate,
55275536 )
55285537 .map_err(|()| {
@@ -5544,6 +5553,7 @@ impl<SP: SignerProvider> ChannelContext<SP> {
55445553 include_counterparty_unknown_htlcs,
55455554 0,
55465555 new_feerate_per_kw,
5556+ false,
55475557 dust_exposure_limiting_feerate,
55485558 )
55495559 .map_err(|()| {
@@ -5724,6 +5734,7 @@ impl<SP: SignerProvider> ChannelContext<SP> {
57245734 include_counterparty_unknown_htlcs,
57255735 CONCURRENT_INBOUND_HTLC_FEE_BUFFER as usize,
57265736 feerate_per_kw,
5737+ false,
57275738 dust_exposure_limiting_feerate,
57285739 ) {
57295740 stats
@@ -5763,6 +5774,7 @@ impl<SP: SignerProvider> ChannelContext<SP> {
57635774 include_counterparty_unknown_htlcs,
57645775 CONCURRENT_INBOUND_HTLC_FEE_BUFFER as usize,
57655776 feerate_per_kw,
5777+ false,
57665778 dust_exposure_limiting_feerate,
57675779 ) {
57685780 stats
@@ -5810,6 +5822,7 @@ impl<SP: SignerProvider> ChannelContext<SP> {
58105822 include_counterparty_unknown_htlcs,
58115823 fee_spike_buffer_htlc,
58125824 feerate,
5825+ false,
58135826 dust_exposure_limiting_feerate,
58145827 )
58155828 .map_err(|()| {
@@ -5826,6 +5839,7 @@ impl<SP: SignerProvider> ChannelContext<SP> {
58265839 include_counterparty_unknown_htlcs,
58275840 fee_spike_buffer_htlc,
58285841 feerate,
5842+ false,
58295843 dust_exposure_limiting_feerate,
58305844 )
58315845 .map_err(|()| {
@@ -5862,21 +5876,14 @@ impl<SP: SignerProvider> ChannelContext<SP> {
58625876 if !funding.is_outbound() {
58635877 // Note that with anchor outputs we are no longer as sensitive to fee spikes, so we don't need
58645878 // to account for them.
5865- let fee_spike_multiple =
5866- if !funding.get_channel_type().supports_anchors_zero_fee_htlc_tx() {
5867- FEE_SPIKE_BUFFER_FEE_INCREASE_MULTIPLE as u32
5868- } else {
5869- 1
5870- };
5871- // Note that the feerate is 0 in zero-fee commitment channels, so this statement is a noop
5872- let spiked_feerate = feerate.saturating_mul(fee_spike_multiple);
58735879 let (remote_stats, _remote_htlcs) = self
58745880 .get_next_remote_commitment_stats(
58755881 funding,
58765882 None,
58775883 include_counterparty_unknown_htlcs,
58785884 fee_spike_buffer_htlc,
5879- spiked_feerate,
5885+ feerate,
5886+ true,
58805887 dust_exposure_limiting_feerate,
58815888 )
58825889 .map_err(|()| {
@@ -6231,6 +6238,7 @@ impl<SP: SignerProvider> ChannelContext<SP> {
62316238 include_counterparty_unknown_htlcs,
62326239 addl_nondust_htlc_count,
62336240 self.feerate_per_kw,
6241+ false,
62346242 dust_exposure_limiting_feerate,
62356243 )
62366244 .map(|(remote_stats, _)| remote_stats.available_balances)?;
@@ -6252,6 +6260,7 @@ impl<SP: SignerProvider> ChannelContext<SP> {
62526260 include_counterparty_unknown_htlcs,
62536261 addl_nondust_htlc_count,
62546262 self.feerate_per_kw,
6263+ false,
62556264 dust_exposure_limiting_feerate,
62566265 )
62576266 .unwrap();
@@ -13372,16 +13381,6 @@ where
1337213381 // We are not interested in dust exposure
1337313382 let dust_exposure_limiting_feerate = None;
1337413383
13375- // Note that the feerate is 0 in zero-fee commitment channels, so this statement is a noop
13376- let feerate_per_kw = if !funding.get_channel_type().supports_anchors_zero_fee_htlc_tx() {
13377- // Similar to HTLC additions, require the funder to have enough funds reserved for
13378- // fees such that the feerate can jump without rendering the channel useless.
13379- let spike_mul = FEE_SPIKE_BUFFER_FEE_INCREASE_MULTIPLE as u32;
13380- self.context.feerate_per_kw.saturating_mul(spike_mul)
13381- } else {
13382- self.context.feerate_per_kw
13383- };
13384-
1338513384 // Different dust limits on the local and remote commitments cause the commitment
1338613385 // transaction fee to be different depending on the commitment, so we grab the floor
1338713386 // of both balances across both commitments here.
@@ -13399,7 +13398,8 @@ where
1339913398 None, // htlc_candidate
1340013399 include_counterparty_unknown_htlcs,
1340113400 addl_nondust_htlc_count,
13402- feerate_per_kw,
13401+ self.context.feerate_per_kw,
13402+ true,
1340313403 dust_exposure_limiting_feerate,
1340413404 )
1340513405 .map_err(|()| "Balance exhausted on local commitment")?;
@@ -13411,7 +13411,8 @@ where
1341113411 None, // htlc_candidate
1341213412 include_counterparty_unknown_htlcs,
1341313413 addl_nondust_htlc_count,
13414- feerate_per_kw,
13414+ self.context.feerate_per_kw,
13415+ true,
1341513416 dust_exposure_limiting_feerate,
1341613417 )
1341713418 .map_err(|()| "Balance exhausted on remote commitment")?;
@@ -13451,6 +13452,7 @@ where
1345113452 include_counterparty_unknown_htlcs,
1345213453 0,
1345313454 self.context.feerate_per_kw,
13455+ false,
1345413456 dust_exposure_limiting_feerate,
1345513457 )
1345613458 .map_err(|()| "Balance exhausted on remote commitment")?;
@@ -17186,7 +17188,7 @@ mod tests {
1718617188 // Make sure when Node A calculates their local commitment transaction, none of the HTLCs pass
1718717189 // the dust limit check.
1718817190 let htlc_candidate = HTLCAmountDirection { amount_msat: htlc_amount_msat, outbound: true };
17189- let local_commit_tx_fee = node_a_chan.context.get_next_local_commitment_stats(&node_a_chan.funding, Some(htlc_candidate), false, 0, node_a_chan.context.feerate_per_kw, None).unwrap().0.commitment_stats.commit_tx_fee_sat * 1000;
17191+ let local_commit_tx_fee = node_a_chan.context.get_next_local_commitment_stats(&node_a_chan.funding, Some(htlc_candidate), false, 0, node_a_chan.context.feerate_per_kw, false, None).unwrap().0.commitment_stats.commit_tx_fee_sat * 1000;
1719017192 let local_commit_fee_0_htlcs = commit_tx_fee_sat(node_a_chan.context.feerate_per_kw, 0, node_a_chan.funding.get_channel_type()) * 1000;
1719117193 assert_eq!(local_commit_tx_fee, local_commit_fee_0_htlcs);
1719217194
@@ -17195,7 +17197,7 @@ mod tests {
1719517197 node_a_chan.funding.channel_transaction_parameters.is_outbound_from_holder = false;
1719617198 let remote_commit_fee_3_htlcs = commit_tx_fee_sat(node_a_chan.context.feerate_per_kw, 3, node_a_chan.funding.get_channel_type()) * 1000;
1719717199 let htlc_candidate = HTLCAmountDirection { amount_msat: htlc_amount_msat, outbound: true };
17198- let remote_commit_tx_fee = node_a_chan.context.get_next_remote_commitment_stats(&node_a_chan.funding, Some(htlc_candidate), false, 0, node_a_chan.context.feerate_per_kw, None).unwrap().0.commitment_stats.commit_tx_fee_sat * 1000;
17200+ let remote_commit_tx_fee = node_a_chan.context.get_next_remote_commitment_stats(&node_a_chan.funding, Some(htlc_candidate), false, 0, node_a_chan.context.feerate_per_kw, false, None).unwrap().0.commitment_stats.commit_tx_fee_sat * 1000;
1719917201 assert_eq!(remote_commit_tx_fee, remote_commit_fee_3_htlcs);
1720017202 }
1720117203
@@ -17230,27 +17232,27 @@ mod tests {
1723017232 // counted as dust when it shouldn't be.
1723117233 let htlc_amt_above_timeout = (htlc_timeout_tx_fee_sat + chan.context.holder_dust_limit_satoshis + 1) * 1000;
1723217234 let htlc_candidate = HTLCAmountDirection { amount_msat: htlc_amt_above_timeout, outbound: true };
17233- let commitment_tx_fee = chan.context.get_next_local_commitment_stats(&chan.funding, Some(htlc_candidate), false, 0, chan.context.feerate_per_kw, None).unwrap().0.commitment_stats.commit_tx_fee_sat * 1000;
17235+ let commitment_tx_fee = chan.context.get_next_local_commitment_stats(&chan.funding, Some(htlc_candidate), false, 0, chan.context.feerate_per_kw, false, None).unwrap().0.commitment_stats.commit_tx_fee_sat * 1000;
1723417236 assert_eq!(commitment_tx_fee, commitment_tx_fee_1_htlc);
1723517237
1723617238 // If swapped: this HTLC would be counted as non-dust when it shouldn't be.
1723717239 let dust_htlc_amt_below_success = (htlc_success_tx_fee_sat + chan.context.holder_dust_limit_satoshis - 1) * 1000;
1723817240 let htlc_candidate = HTLCAmountDirection { amount_msat: dust_htlc_amt_below_success, outbound: false };
17239- let commitment_tx_fee = chan.context.get_next_local_commitment_stats(&chan.funding, Some(htlc_candidate), false, 0, chan.context.feerate_per_kw, None).unwrap().0.commitment_stats.commit_tx_fee_sat * 1000;
17241+ let commitment_tx_fee = chan.context.get_next_local_commitment_stats(&chan.funding, Some(htlc_candidate), false, 0, chan.context.feerate_per_kw, false, None).unwrap().0.commitment_stats.commit_tx_fee_sat * 1000;
1724017242 assert_eq!(commitment_tx_fee, commitment_tx_fee_0_htlcs);
1724117243
1724217244 chan.funding.channel_transaction_parameters.is_outbound_from_holder = false;
1724317245
1724417246 // If swapped: this HTLC would be counted as non-dust when it shouldn't be.
1724517247 let dust_htlc_amt_above_timeout = (htlc_timeout_tx_fee_sat + chan.context.counterparty_dust_limit_satoshis + 1) * 1000;
1724617248 let htlc_candidate = HTLCAmountDirection { amount_msat: dust_htlc_amt_above_timeout, outbound: true };
17247- let commitment_tx_fee = chan.context.get_next_remote_commitment_stats(&chan.funding, Some(htlc_candidate), false, 0, chan.context.feerate_per_kw, None).unwrap().0.commitment_stats.commit_tx_fee_sat * 1000;
17249+ let commitment_tx_fee = chan.context.get_next_remote_commitment_stats(&chan.funding, Some(htlc_candidate), false, 0, chan.context.feerate_per_kw, false, None).unwrap().0.commitment_stats.commit_tx_fee_sat * 1000;
1724817250 assert_eq!(commitment_tx_fee, commitment_tx_fee_0_htlcs);
1724917251
1725017252 // If swapped: this HTLC would be counted as dust when it shouldn't be.
1725117253 let htlc_amt_below_success = (htlc_success_tx_fee_sat + chan.context.counterparty_dust_limit_satoshis - 1) * 1000;
1725217254 let htlc_candidate = HTLCAmountDirection { amount_msat: htlc_amt_below_success, outbound: false };
17253- let commitment_tx_fee = chan.context.get_next_remote_commitment_stats(&chan.funding, Some(htlc_candidate), false, 0, chan.context.feerate_per_kw, None).unwrap().0.commitment_stats.commit_tx_fee_sat * 1000;
17255+ let commitment_tx_fee = chan.context.get_next_remote_commitment_stats(&chan.funding, Some(htlc_candidate), false, 0, chan.context.feerate_per_kw, false, None).unwrap().0.commitment_stats.commit_tx_fee_sat * 1000;
1725417256 assert_eq!(commitment_tx_fee, commitment_tx_fee_1_htlc);
1725517257 }
1725617258
0 commit comments