@@ -1059,7 +1059,6 @@ pub enum AnnouncementSigsState {
1059
1059
1060
1060
/// An enum indicating whether the local or remote side offered a given HTLC.
1061
1061
enum HTLCInitiator {
1062
- LocalOffered,
1063
1062
RemoteOffered,
1064
1063
}
1065
1064
@@ -4145,7 +4144,7 @@ where
4145
4144
{
4146
4145
let remote_commit_tx_fee_msat = if funding.is_outbound() { 0 } else {
4147
4146
let htlc_candidate = HTLCCandidate::new(msg.amount_msat, HTLCInitiator::RemoteOffered);
4148
- self.next_remote_commit_tx_fee_msat(funding, Some(htlc_candidate), None ) // Don't include the extra fee spike buffer HTLC in calculations
4147
+ self.next_remote_commit_tx_fee_msat(funding, Some(htlc_candidate), 0 ) // Don't include the extra fee spike buffer HTLC in calculations
4149
4148
};
4150
4149
if remote_balance_before_fee_msat.saturating_sub(msg.amount_msat) < remote_commit_tx_fee_msat {
4151
4150
return Err(ChannelError::close("Remote HTLC add would not leave enough to pay for fees".to_owned()));
@@ -4158,7 +4157,7 @@ where
4158
4157
if funding.is_outbound() {
4159
4158
// Check that they won't violate our local required channel reserve by adding this HTLC.
4160
4159
let htlc_candidate = HTLCCandidate::new(msg.amount_msat, HTLCInitiator::RemoteOffered);
4161
- let local_commit_tx_fee_msat = self.next_local_commit_tx_fee_msat(funding, htlc_candidate, None );
4160
+ let local_commit_tx_fee_msat = self.next_local_commit_tx_fee_msat(funding, Some( htlc_candidate), 0 );
4162
4161
if local_balance_before_fee_msat < funding.counterparty_selected_channel_reserve_satoshis.unwrap() * 1000 + local_commit_tx_fee_msat {
4163
4162
return Err(ChannelError::close("Cannot accept HTLC that would put our balance under counterparty-announced channel reserve value".to_owned()));
4164
4163
}
@@ -4372,7 +4371,7 @@ where
4372
4371
//
4373
4372
// A `None` `HTLCCandidate` is used as in this case because we're already accounting for
4374
4373
// the incoming HTLC as it has been fully committed by both sides.
4375
- let mut remote_fee_cost_incl_stuck_buffer_msat = self.next_remote_commit_tx_fee_msat(funding, None, Some(()) );
4374
+ let mut remote_fee_cost_incl_stuck_buffer_msat = self.next_remote_commit_tx_fee_msat(funding, None, 1 );
4376
4375
if !funding.get_channel_type().supports_anchors_zero_fee_htlc_tx() {
4377
4376
remote_fee_cost_incl_stuck_buffer_msat *= FEE_SPIKE_BUFFER_FEE_INCREASE_MULTIPLE;
4378
4377
}
@@ -4865,10 +4864,8 @@ where
4865
4864
// dependency.
4866
4865
// This complicates the computation around dust-values, up to the one-htlc-value.
4867
4866
4868
- let htlc_above_dust = HTLCCandidate::new(real_dust_limit_timeout_sat * 1000, HTLCInitiator::LocalOffered);
4869
- let mut max_reserved_commit_tx_fee_msat = context.next_local_commit_tx_fee_msat(funding, htlc_above_dust, Some(()));
4870
- let htlc_dust = HTLCCandidate::new(real_dust_limit_timeout_sat * 1000 - 1, HTLCInitiator::LocalOffered);
4871
- let mut min_reserved_commit_tx_fee_msat = context.next_local_commit_tx_fee_msat(funding, htlc_dust, Some(()));
4867
+ let mut max_reserved_commit_tx_fee_msat = context.next_local_commit_tx_fee_msat(funding, None, 2);
4868
+ let mut min_reserved_commit_tx_fee_msat = context.next_local_commit_tx_fee_msat(funding, None, 1);
4872
4869
if !funding.get_channel_type().supports_anchors_zero_fee_htlc_tx() {
4873
4870
max_reserved_commit_tx_fee_msat *= FEE_SPIKE_BUFFER_FEE_INCREASE_MULTIPLE;
4874
4871
min_reserved_commit_tx_fee_msat *= FEE_SPIKE_BUFFER_FEE_INCREASE_MULTIPLE;
@@ -4891,8 +4888,7 @@ where
4891
4888
} else {
4892
4889
// If the channel is inbound (i.e. counterparty pays the fee), we need to make sure
4893
4890
// sending a new HTLC won't reduce their balance below our reserve threshold.
4894
- let htlc_above_dust = HTLCCandidate::new(real_dust_limit_success_sat * 1000, HTLCInitiator::LocalOffered);
4895
- let max_reserved_commit_tx_fee_msat = context.next_remote_commit_tx_fee_msat(funding, Some(htlc_above_dust), None);
4891
+ let max_reserved_commit_tx_fee_msat = context.next_remote_commit_tx_fee_msat(funding, None, 1);
4896
4892
4897
4893
let holder_selected_chan_reserve_msat = funding.holder_selected_channel_reserve_satoshis * 1000;
4898
4894
if remote_balance_before_fee_msat < max_reserved_commit_tx_fee_msat + holder_selected_chan_reserve_msat {
@@ -4975,18 +4971,22 @@ where
4975
4971
/// Dust HTLCs are excluded.
4976
4972
#[rustfmt::skip]
4977
4973
fn next_local_commit_tx_fee_msat(
4978
- &self, funding: &FundingScope, htlc: HTLCCandidate, fee_spike_buffer_htlc: Option<()> ,
4974
+ &self, funding: &FundingScope, htlc: Option< HTLCCandidate>, addl_nondust_htlc: usize ,
4979
4975
) -> u64 {
4976
+ debug_assert!(htlc.is_some() || addl_nondust_htlc != 0, "At least one of the options must be set");
4977
+
4980
4978
let context = self;
4981
4979
assert!(funding.is_outbound());
4982
4980
let mut htlcs: Vec<HTLCAmountDirection> = Vec::new();
4983
4981
4984
- match htlc.origin {
4985
- HTLCInitiator::LocalOffered => {
4986
- htlcs.push(HTLCAmountDirection { offered: true, amount_msat: htlc.amount_msat });
4987
- },
4988
- HTLCInitiator::RemoteOffered => {
4989
- htlcs.push(HTLCAmountDirection { offered: false, amount_msat: htlc.amount_msat });
4982
+ if let Some(htlc) = &htlc {
4983
+ match htlc.origin {
4984
+ HTLCInitiator::LocalOffered => {
4985
+ htlcs.push(HTLCAmountDirection { offered: true, amount_msat: htlc.amount_msat });
4986
+ },
4987
+ HTLCInitiator::RemoteOffered => {
4988
+ htlcs.push(HTLCAmountDirection { offered: false, amount_msat: htlc.amount_msat });
4989
+ }
4990
4990
}
4991
4991
}
4992
4992
@@ -5017,13 +5017,13 @@ where
5017
5017
}
5018
5018
5019
5019
#[cfg(any(test, fuzzing))]
5020
- let commit_tx_fee_msat = SpecTxBuilder {}.commit_tx_fee_sat(context.holder_dust_limit_satoshis, context.feerate_per_kw, &htlcs, fee_spike_buffer_htlc.map(|_| 1).unwrap_or(0) , funding.get_channel_type()) * 1000;
5020
+ let commit_tx_fee_msat = SpecTxBuilder {}.commit_tx_fee_sat(context.holder_dust_limit_satoshis, context.feerate_per_kw, &htlcs, addl_nondust_htlc , funding.get_channel_type()) * 1000;
5021
5021
#[cfg(not(any(test, fuzzing)))]
5022
- let commit_tx_fee_msat = SpecTxBuilder {}.commit_tx_fee_sat(context.holder_dust_limit_satoshis, context.feerate_per_kw, &htlcs, fee_spike_buffer_htlc.map(|_| 1).unwrap_or(0) , funding.get_channel_type()) * 1000;
5022
+ let commit_tx_fee_msat = SpecTxBuilder {}.commit_tx_fee_sat(context.holder_dust_limit_satoshis, context.feerate_per_kw, &htlcs, addl_nondust_htlc , funding.get_channel_type()) * 1000;
5023
5023
#[cfg(any(test, fuzzing))]
5024
- {
5024
+ if let Some(htlc) = htlc {
5025
5025
let mut fee = commit_tx_fee_msat;
5026
- if fee_spike_buffer_htlc.is_some() {
5026
+ if addl_nondust_htlc != 0 {
5027
5027
fee = SpecTxBuilder {}.commit_tx_fee_sat(context.holder_dust_limit_satoshis, context.feerate_per_kw, &htlcs, 0, funding.get_channel_type()) * 1000;
5028
5028
}
5029
5029
let total_pending_htlcs = context.pending_inbound_htlcs.len() + context.pending_outbound_htlcs.len()
@@ -5058,9 +5058,9 @@ where
5058
5058
/// Dust HTLCs are excluded.
5059
5059
#[rustfmt::skip]
5060
5060
fn next_remote_commit_tx_fee_msat(
5061
- &self, funding: &FundingScope, htlc: Option<HTLCCandidate>, fee_spike_buffer_htlc: Option<()> ,
5061
+ &self, funding: &FundingScope, htlc: Option<HTLCCandidate>, addl_nondust_htlc: usize ,
5062
5062
) -> u64 {
5063
- debug_assert!(htlc.is_some() || fee_spike_buffer_htlc.is_some() , "At least one of the options must be set");
5063
+ debug_assert!(htlc.is_some() || addl_nondust_htlc != 0 , "At least one of the options must be set");
5064
5064
5065
5065
let context = self;
5066
5066
assert!(!funding.is_outbound());
@@ -5097,13 +5097,13 @@ where
5097
5097
}
5098
5098
5099
5099
#[cfg(any(test, fuzzing))]
5100
- let commit_tx_fee_msat = SpecTxBuilder {}.commit_tx_fee_sat(context.counterparty_dust_limit_satoshis, context.feerate_per_kw, &htlcs, fee_spike_buffer_htlc.map(|_| 1).unwrap_or(0) , funding.get_channel_type()) * 1000;
5100
+ let commit_tx_fee_msat = SpecTxBuilder {}.commit_tx_fee_sat(context.counterparty_dust_limit_satoshis, context.feerate_per_kw, &htlcs, addl_nondust_htlc , funding.get_channel_type()) * 1000;
5101
5101
#[cfg(not(any(test, fuzzing)))]
5102
- let commit_tx_fee_msat = SpecTxBuilder {}.commit_tx_fee_sat(context.counterparty_dust_limit_satoshis, context.feerate_per_kw, &htlcs, fee_spike_buffer_htlc.map(|_| 1).unwrap_or(0) , funding.get_channel_type()) * 1000;
5102
+ let commit_tx_fee_msat = SpecTxBuilder {}.commit_tx_fee_sat(context.counterparty_dust_limit_satoshis, context.feerate_per_kw, &htlcs, addl_nondust_htlc , funding.get_channel_type()) * 1000;
5103
5103
#[cfg(any(test, fuzzing))]
5104
5104
if let Some(htlc) = &htlc {
5105
5105
let mut fee = commit_tx_fee_msat;
5106
- if fee_spike_buffer_htlc.is_some() {
5106
+ if addl_nondust_htlc != 0 {
5107
5107
fee = SpecTxBuilder {}.commit_tx_fee_sat(context.counterparty_dust_limit_satoshis, context.feerate_per_kw, &htlcs, 0, funding.get_channel_type()) * 1000;
5108
5108
}
5109
5109
let total_pending_htlcs = context.pending_inbound_htlcs.len() + context.pending_outbound_htlcs.len();
@@ -13450,7 +13450,7 @@ mod tests {
13450
13450
// Make sure when Node A calculates their local commitment transaction, none of the HTLCs pass
13451
13451
// the dust limit check.
13452
13452
let htlc_candidate = HTLCCandidate::new(htlc_amount_msat, HTLCInitiator::LocalOffered);
13453
- let local_commit_tx_fee = node_a_chan.context.next_local_commit_tx_fee_msat(&node_a_chan.funding, htlc_candidate, None );
13453
+ let local_commit_tx_fee = node_a_chan.context.next_local_commit_tx_fee_msat(&node_a_chan.funding, Some( htlc_candidate), 0 );
13454
13454
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;
13455
13455
assert_eq!(local_commit_tx_fee, local_commit_fee_0_htlcs);
13456
13456
@@ -13459,7 +13459,7 @@ mod tests {
13459
13459
node_a_chan.funding.channel_transaction_parameters.is_outbound_from_holder = false;
13460
13460
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;
13461
13461
let htlc_candidate = HTLCCandidate::new(htlc_amount_msat, HTLCInitiator::LocalOffered);
13462
- let remote_commit_tx_fee = node_a_chan.context.next_remote_commit_tx_fee_msat(&node_a_chan.funding, Some(htlc_candidate), None );
13462
+ let remote_commit_tx_fee = node_a_chan.context.next_remote_commit_tx_fee_msat(&node_a_chan.funding, Some(htlc_candidate), 0 );
13463
13463
assert_eq!(remote_commit_tx_fee, remote_commit_fee_3_htlcs);
13464
13464
}
13465
13465
@@ -13489,27 +13489,27 @@ mod tests {
13489
13489
// counted as dust when it shouldn't be.
13490
13490
let htlc_amt_above_timeout = ((253 * htlc_timeout_tx_weight(chan.funding.get_channel_type()) / 1000) + chan.context.holder_dust_limit_satoshis + 1) * 1000;
13491
13491
let htlc_candidate = HTLCCandidate::new(htlc_amt_above_timeout, HTLCInitiator::LocalOffered);
13492
- let commitment_tx_fee = chan.context.next_local_commit_tx_fee_msat(&chan.funding, htlc_candidate, None );
13492
+ let commitment_tx_fee = chan.context.next_local_commit_tx_fee_msat(&chan.funding, Some( htlc_candidate), 0 );
13493
13493
assert_eq!(commitment_tx_fee, commitment_tx_fee_1_htlc);
13494
13494
13495
13495
// If swapped: this HTLC would be counted as non-dust when it shouldn't be.
13496
13496
let dust_htlc_amt_below_success = ((253 * htlc_success_tx_weight(chan.funding.get_channel_type()) / 1000) + chan.context.holder_dust_limit_satoshis - 1) * 1000;
13497
13497
let htlc_candidate = HTLCCandidate::new(dust_htlc_amt_below_success, HTLCInitiator::RemoteOffered);
13498
- let commitment_tx_fee = chan.context.next_local_commit_tx_fee_msat(&chan.funding, htlc_candidate, None );
13498
+ let commitment_tx_fee = chan.context.next_local_commit_tx_fee_msat(&chan.funding, Some( htlc_candidate), 0 );
13499
13499
assert_eq!(commitment_tx_fee, commitment_tx_fee_0_htlcs);
13500
13500
13501
13501
chan.funding.channel_transaction_parameters.is_outbound_from_holder = false;
13502
13502
13503
13503
// If swapped: this HTLC would be counted as non-dust when it shouldn't be.
13504
13504
let dust_htlc_amt_above_timeout = ((253 * htlc_timeout_tx_weight(chan.funding.get_channel_type()) / 1000) + chan.context.counterparty_dust_limit_satoshis + 1) * 1000;
13505
13505
let htlc_candidate = HTLCCandidate::new(dust_htlc_amt_above_timeout, HTLCInitiator::LocalOffered);
13506
- let commitment_tx_fee = chan.context.next_remote_commit_tx_fee_msat(&chan.funding, Some(htlc_candidate), None );
13506
+ let commitment_tx_fee = chan.context.next_remote_commit_tx_fee_msat(&chan.funding, Some(htlc_candidate), 0 );
13507
13507
assert_eq!(commitment_tx_fee, commitment_tx_fee_0_htlcs);
13508
13508
13509
13509
// If swapped: this HTLC would be counted as dust when it shouldn't be.
13510
13510
let htlc_amt_below_success = ((253 * htlc_success_tx_weight(chan.funding.get_channel_type()) / 1000) + chan.context.counterparty_dust_limit_satoshis - 1) * 1000;
13511
13511
let htlc_candidate = HTLCCandidate::new(htlc_amt_below_success, HTLCInitiator::RemoteOffered);
13512
- let commitment_tx_fee = chan.context.next_remote_commit_tx_fee_msat(&chan.funding, Some(htlc_candidate), None );
13512
+ let commitment_tx_fee = chan.context.next_remote_commit_tx_fee_msat(&chan.funding, Some(htlc_candidate), 0 );
13513
13513
assert_eq!(commitment_tx_fee, commitment_tx_fee_1_htlc);
13514
13514
}
13515
13515
0 commit comments