@@ -1579,6 +1579,15 @@ pub(super) struct FundingScope {
1579
1579
#[cfg(debug_assertions)]
1580
1580
/// Max to_local and to_remote outputs in a remote-generated commitment transaction
1581
1581
counterparty_max_commitment_tx_output: Mutex<(u64, u64)>,
1582
+
1583
+ // We save these values so we can make sure `next_local_commit_tx_fee_msat` and
1584
+ // `next_remote_commit_tx_fee_msat` properly predict what the next commitment transaction fee will
1585
+ // be, by comparing the cached values to the fee of the transaction generated by
1586
+ // `build_commitment_transaction`.
1587
+ #[cfg(any(test, fuzzing))]
1588
+ next_local_commitment_tx_fee_info_cached: Mutex<Option<CommitmentTxInfoCached>>,
1589
+ #[cfg(any(test, fuzzing))]
1590
+ next_remote_commitment_tx_fee_info_cached: Mutex<Option<CommitmentTxInfoCached>>,
1582
1591
}
1583
1592
1584
1593
impl FundingScope {
@@ -1823,15 +1832,6 @@ pub(super) struct ChannelContext<SP: Deref> where SP::Target: SignerProvider {
1823
1832
/// This can be used to rebroadcast the channel_announcement message later.
1824
1833
announcement_sigs: Option<(Signature, Signature)>,
1825
1834
1826
- // We save these values so we can make sure `next_local_commit_tx_fee_msat` and
1827
- // `next_remote_commit_tx_fee_msat` properly predict what the next commitment transaction fee will
1828
- // be, by comparing the cached values to the fee of the tranaction generated by
1829
- // `build_commitment_transaction`.
1830
- #[cfg(any(test, fuzzing))]
1831
- next_local_commitment_tx_fee_info_cached: Mutex<Option<CommitmentTxInfoCached>>,
1832
- #[cfg(any(test, fuzzing))]
1833
- next_remote_commitment_tx_fee_info_cached: Mutex<Option<CommitmentTxInfoCached>>,
1834
-
1835
1835
/// lnd has a long-standing bug where, upon reconnection, if the channel is not yet confirmed
1836
1836
/// they will not send a channel_reestablish until the channel locks in. Then, they will send a
1837
1837
/// channel_ready *before* sending the channel_reestablish (which is clearly a violation of
@@ -2470,6 +2470,11 @@ impl<SP: Deref> ChannelContext<SP> where SP::Target: SignerProvider {
2470
2470
holder_max_commitment_tx_output: Mutex::new((value_to_self_msat, (channel_value_satoshis * 1000 - msg_push_msat).saturating_sub(value_to_self_msat))),
2471
2471
#[cfg(debug_assertions)]
2472
2472
counterparty_max_commitment_tx_output: Mutex::new((value_to_self_msat, (channel_value_satoshis * 1000 - msg_push_msat).saturating_sub(value_to_self_msat))),
2473
+
2474
+ #[cfg(any(test, fuzzing))]
2475
+ next_local_commitment_tx_fee_info_cached: Mutex::new(None),
2476
+ #[cfg(any(test, fuzzing))]
2477
+ next_remote_commitment_tx_fee_info_cached: Mutex::new(None),
2473
2478
};
2474
2479
let channel_context = ChannelContext {
2475
2480
user_id,
@@ -2578,11 +2583,6 @@ impl<SP: Deref> ChannelContext<SP> where SP::Target: SignerProvider {
2578
2583
2579
2584
announcement_sigs: None,
2580
2585
2581
- #[cfg(any(test, fuzzing))]
2582
- next_local_commitment_tx_fee_info_cached: Mutex::new(None),
2583
- #[cfg(any(test, fuzzing))]
2584
- next_remote_commitment_tx_fee_info_cached: Mutex::new(None),
2585
-
2586
2586
workaround_lnd_bug_4006: None,
2587
2587
sent_message_awaiting_response: None,
2588
2588
@@ -2705,6 +2705,11 @@ impl<SP: Deref> ChannelContext<SP> where SP::Target: SignerProvider {
2705
2705
holder_max_commitment_tx_output: Mutex::new((channel_value_satoshis * 1000 - push_msat, push_msat)),
2706
2706
#[cfg(debug_assertions)]
2707
2707
counterparty_max_commitment_tx_output: Mutex::new((channel_value_satoshis * 1000 - push_msat, push_msat)),
2708
+
2709
+ #[cfg(any(test, fuzzing))]
2710
+ next_local_commitment_tx_fee_info_cached: Mutex::new(None),
2711
+ #[cfg(any(test, fuzzing))]
2712
+ next_remote_commitment_tx_fee_info_cached: Mutex::new(None),
2708
2713
};
2709
2714
let channel_context = Self {
2710
2715
user_id,
@@ -2810,11 +2815,6 @@ impl<SP: Deref> ChannelContext<SP> where SP::Target: SignerProvider {
2810
2815
2811
2816
announcement_sigs: None,
2812
2817
2813
- #[cfg(any(test, fuzzing))]
2814
- next_local_commitment_tx_fee_info_cached: Mutex::new(None),
2815
- #[cfg(any(test, fuzzing))]
2816
- next_remote_commitment_tx_fee_info_cached: Mutex::new(None),
2817
-
2818
2818
workaround_lnd_bug_4006: None,
2819
2819
sent_message_awaiting_response: None,
2820
2820
@@ -3868,9 +3868,17 @@ impl<SP: Deref> ChannelContext<SP> where SP::Target: SignerProvider {
3868
3868
}
3869
3869
3870
3870
let htlc_above_dust = HTLCCandidate::new(real_dust_limit_timeout_sat * 1000, HTLCInitiator::LocalOffered);
3871
- let mut max_reserved_commit_tx_fee_msat = context.next_local_commit_tx_fee_msat(htlc_above_dust, Some(()));
3871
+ let mut max_reserved_commit_tx_fee_msat = context.next_local_commit_tx_fee_msat(
3872
+ #[cfg(any(test, fuzzing))]
3873
+ &funding,
3874
+ htlc_above_dust, Some(()),
3875
+ );
3872
3876
let htlc_dust = HTLCCandidate::new(real_dust_limit_timeout_sat * 1000 - 1, HTLCInitiator::LocalOffered);
3873
- let mut min_reserved_commit_tx_fee_msat = context.next_local_commit_tx_fee_msat(htlc_dust, Some(()));
3877
+ let mut min_reserved_commit_tx_fee_msat = context.next_local_commit_tx_fee_msat(
3878
+ #[cfg(any(test, fuzzing))]
3879
+ &funding,
3880
+ htlc_dust, Some(()),
3881
+ );
3874
3882
if !context.get_channel_type().supports_anchors_zero_fee_htlc_tx() {
3875
3883
max_reserved_commit_tx_fee_msat *= FEE_SPIKE_BUFFER_FEE_INCREASE_MULTIPLE;
3876
3884
min_reserved_commit_tx_fee_msat *= FEE_SPIKE_BUFFER_FEE_INCREASE_MULTIPLE;
@@ -3899,7 +3907,11 @@ impl<SP: Deref> ChannelContext<SP> where SP::Target: SignerProvider {
3899
3907
}
3900
3908
3901
3909
let htlc_above_dust = HTLCCandidate::new(real_dust_limit_success_sat * 1000, HTLCInitiator::LocalOffered);
3902
- let max_reserved_commit_tx_fee_msat = context.next_remote_commit_tx_fee_msat(Some(htlc_above_dust), None);
3910
+ let max_reserved_commit_tx_fee_msat = context.next_remote_commit_tx_fee_msat(
3911
+ #[cfg(any(test, fuzzing))]
3912
+ &funding,
3913
+ Some(htlc_above_dust), None,
3914
+ );
3903
3915
3904
3916
let holder_selected_chan_reserve_msat = funding.holder_selected_channel_reserve_satoshis * 1000;
3905
3917
let remote_balance_msat = (funding.channel_value_satoshis * 1000 - funding.value_to_self_msat)
@@ -3996,7 +4008,12 @@ impl<SP: Deref> ChannelContext<SP> where SP::Target: SignerProvider {
3996
4008
/// second allows for creating a buffer to ensure a further HTLC can always be accepted/added.
3997
4009
///
3998
4010
/// Dust HTLCs are excluded.
3999
- fn next_local_commit_tx_fee_msat(&self, htlc: HTLCCandidate, fee_spike_buffer_htlc: Option<()>) -> u64 {
4011
+ fn next_local_commit_tx_fee_msat(
4012
+ &self,
4013
+ #[cfg(any(test, fuzzing))]
4014
+ funding: &FundingScope,
4015
+ htlc: HTLCCandidate, fee_spike_buffer_htlc: Option<()>,
4016
+ ) -> u64 {
4000
4017
let context = &self;
4001
4018
assert!(context.is_outbound());
4002
4019
@@ -4085,7 +4102,7 @@ impl<SP: Deref> ChannelContext<SP> where SP::Target: SignerProvider {
4085
4102
},
4086
4103
feerate: context.feerate_per_kw,
4087
4104
};
4088
- *context .next_local_commitment_tx_fee_info_cached.lock().unwrap() = Some(commitment_tx_info);
4105
+ *funding .next_local_commitment_tx_fee_info_cached.lock().unwrap() = Some(commitment_tx_info);
4089
4106
}
4090
4107
res
4091
4108
}
@@ -4100,7 +4117,12 @@ impl<SP: Deref> ChannelContext<SP> where SP::Target: SignerProvider {
4100
4117
/// second allows for creating a buffer to ensure a further HTLC can always be accepted/added.
4101
4118
///
4102
4119
/// Dust HTLCs are excluded.
4103
- fn next_remote_commit_tx_fee_msat(&self, htlc: Option<HTLCCandidate>, fee_spike_buffer_htlc: Option<()>) -> u64 {
4120
+ fn next_remote_commit_tx_fee_msat(
4121
+ &self,
4122
+ #[cfg(any(test, fuzzing))]
4123
+ funding: &FundingScope,
4124
+ htlc: Option<HTLCCandidate>, fee_spike_buffer_htlc: Option<()>,
4125
+ ) -> u64 {
4104
4126
debug_assert!(htlc.is_some() || fee_spike_buffer_htlc.is_some(), "At least one of the options must be set");
4105
4127
4106
4128
let context = &self;
@@ -4179,7 +4201,7 @@ impl<SP: Deref> ChannelContext<SP> where SP::Target: SignerProvider {
4179
4201
},
4180
4202
feerate: context.feerate_per_kw,
4181
4203
};
4182
- *context .next_remote_commitment_tx_fee_info_cached.lock().unwrap() = Some(commitment_tx_info);
4204
+ *funding .next_remote_commitment_tx_fee_info_cached.lock().unwrap() = Some(commitment_tx_info);
4183
4205
}
4184
4206
res
4185
4207
}
@@ -5199,7 +5221,11 @@ impl<SP: Deref> FundedChannel<SP> where
5199
5221
{
5200
5222
let remote_commit_tx_fee_msat = if self.context.is_outbound() { 0 } else {
5201
5223
let htlc_candidate = HTLCCandidate::new(msg.amount_msat, HTLCInitiator::RemoteOffered);
5202
- self.context.next_remote_commit_tx_fee_msat(Some(htlc_candidate), None) // Don't include the extra fee spike buffer HTLC in calculations
5224
+ self.context.next_remote_commit_tx_fee_msat(
5225
+ #[cfg(any(test, fuzzing))]
5226
+ &self.funding,
5227
+ Some(htlc_candidate), None, // Don't include the extra fee spike buffer HTLC in calculations
5228
+ )
5203
5229
};
5204
5230
let anchor_outputs_value_msat = if !self.context.is_outbound() && self.context.get_channel_type().supports_anchors_zero_fee_htlc_tx() {
5205
5231
ANCHOR_OUTPUT_VALUE_SATOSHI * 2 * 1000
@@ -5222,7 +5248,11 @@ impl<SP: Deref> FundedChannel<SP> where
5222
5248
if self.context.is_outbound() {
5223
5249
// Check that they won't violate our local required channel reserve by adding this HTLC.
5224
5250
let htlc_candidate = HTLCCandidate::new(msg.amount_msat, HTLCInitiator::RemoteOffered);
5225
- let local_commit_tx_fee_msat = self.context.next_local_commit_tx_fee_msat(htlc_candidate, None);
5251
+ let local_commit_tx_fee_msat = self.context.next_local_commit_tx_fee_msat(
5252
+ #[cfg(any(test, fuzzing))]
5253
+ &self.funding,
5254
+ htlc_candidate, None,
5255
+ );
5226
5256
if self.funding.value_to_self_msat < self.funding.counterparty_selected_channel_reserve_satoshis.unwrap() * 1000 + local_commit_tx_fee_msat + anchor_outputs_value_msat {
5227
5257
return Err(ChannelError::close("Cannot accept HTLC that would put our balance under counterparty-announced channel reserve value".to_owned()));
5228
5258
}
@@ -5400,8 +5430,8 @@ impl<SP: Deref> FundedChannel<SP> where
5400
5430
#[cfg(any(test, fuzzing))]
5401
5431
{
5402
5432
if self.context.is_outbound() {
5403
- let projected_commit_tx_info = self.context .next_local_commitment_tx_fee_info_cached.lock().unwrap().take();
5404
- *self.context .next_remote_commitment_tx_fee_info_cached.lock().unwrap() = None;
5433
+ let projected_commit_tx_info = self.funding .next_local_commitment_tx_fee_info_cached.lock().unwrap().take();
5434
+ *self.funding .next_remote_commitment_tx_fee_info_cached.lock().unwrap() = None;
5405
5435
if let Some(info) = projected_commit_tx_info {
5406
5436
let total_pending_htlcs = self.context.pending_inbound_htlcs.len() + self.context.pending_outbound_htlcs.len()
5407
5437
+ self.context.holding_cell_htlc_updates.len();
@@ -5770,8 +5800,8 @@ impl<SP: Deref> FundedChannel<SP> where
5770
5800
5771
5801
#[cfg(any(test, fuzzing))]
5772
5802
{
5773
- *self.context .next_local_commitment_tx_fee_info_cached.lock().unwrap() = None;
5774
- *self.context .next_remote_commitment_tx_fee_info_cached.lock().unwrap() = None;
5803
+ *self.funding .next_local_commitment_tx_fee_info_cached.lock().unwrap() = None;
5804
+ *self.funding .next_remote_commitment_tx_fee_info_cached.lock().unwrap() = None;
5775
5805
}
5776
5806
5777
5807
match &self.context.holder_signer {
@@ -7411,7 +7441,11 @@ impl<SP: Deref> FundedChannel<SP> where
7411
7441
//
7412
7442
// A `None` `HTLCCandidate` is used as in this case because we're already accounting for
7413
7443
// the incoming HTLC as it has been fully committed by both sides.
7414
- let mut remote_fee_cost_incl_stuck_buffer_msat = self.context.next_remote_commit_tx_fee_msat(None, Some(()));
7444
+ let mut remote_fee_cost_incl_stuck_buffer_msat = self.context.next_remote_commit_tx_fee_msat(
7445
+ #[cfg(any(test, fuzzing))]
7446
+ &self.funding,
7447
+ None, Some(()),
7448
+ );
7415
7449
if !self.context.get_channel_type().supports_anchors_zero_fee_htlc_tx() {
7416
7450
remote_fee_cost_incl_stuck_buffer_msat *= FEE_SPIKE_BUFFER_FEE_INCREASE_MULTIPLE;
7417
7451
}
@@ -8353,8 +8387,8 @@ impl<SP: Deref> FundedChannel<SP> where
8353
8387
#[cfg(any(test, fuzzing))]
8354
8388
{
8355
8389
if !self.context.is_outbound() {
8356
- let projected_commit_tx_info = self.context .next_remote_commitment_tx_fee_info_cached.lock().unwrap().take();
8357
- *self.context .next_local_commitment_tx_fee_info_cached.lock().unwrap() = None;
8390
+ let projected_commit_tx_info = self.funding .next_remote_commitment_tx_fee_info_cached.lock().unwrap().take();
8391
+ *self.funding .next_local_commitment_tx_fee_info_cached.lock().unwrap() = None;
8358
8392
if let Some(info) = projected_commit_tx_info {
8359
8393
let total_pending_htlcs = self.context.pending_inbound_htlcs.len() + self.context.pending_outbound_htlcs.len();
8360
8394
if info.total_pending_htlcs == total_pending_htlcs
@@ -10375,6 +10409,11 @@ impl<'a, 'b, 'c, ES: Deref, SP: Deref> ReadableArgs<(&'a ES, &'b SP, u32, &'c Ch
10375
10409
holder_max_commitment_tx_output: Mutex::new((0, 0)),
10376
10410
#[cfg(debug_assertions)]
10377
10411
counterparty_max_commitment_tx_output: Mutex::new((0, 0)),
10412
+
10413
+ #[cfg(any(test, fuzzing))]
10414
+ next_local_commitment_tx_fee_info_cached: Mutex::new(None),
10415
+ #[cfg(any(test, fuzzing))]
10416
+ next_remote_commitment_tx_fee_info_cached: Mutex::new(None),
10378
10417
},
10379
10418
context: ChannelContext {
10380
10419
user_id,
@@ -10470,11 +10509,6 @@ impl<'a, 'b, 'c, ES: Deref, SP: Deref> ReadableArgs<(&'a ES, &'b SP, u32, &'c Ch
10470
10509
10471
10510
announcement_sigs,
10472
10511
10473
- #[cfg(any(test, fuzzing))]
10474
- next_local_commitment_tx_fee_info_cached: Mutex::new(None),
10475
- #[cfg(any(test, fuzzing))]
10476
- next_remote_commitment_tx_fee_info_cached: Mutex::new(None),
10477
-
10478
10512
workaround_lnd_bug_4006: None,
10479
10513
sent_message_awaiting_response: None,
10480
10514
@@ -10744,7 +10778,7 @@ mod tests {
10744
10778
// Make sure when Node A calculates their local commitment transaction, none of the HTLCs pass
10745
10779
// the dust limit check.
10746
10780
let htlc_candidate = HTLCCandidate::new(htlc_amount_msat, HTLCInitiator::LocalOffered);
10747
- let local_commit_tx_fee = node_a_chan.context.next_local_commit_tx_fee_msat(htlc_candidate, None);
10781
+ let local_commit_tx_fee = node_a_chan.context.next_local_commit_tx_fee_msat(&node_a_chan.funding, htlc_candidate, None);
10748
10782
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;
10749
10783
assert_eq!(local_commit_tx_fee, local_commit_fee_0_htlcs);
10750
10784
@@ -10753,7 +10787,7 @@ mod tests {
10753
10787
node_a_chan.context.channel_transaction_parameters.is_outbound_from_holder = false;
10754
10788
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;
10755
10789
let htlc_candidate = HTLCCandidate::new(htlc_amount_msat, HTLCInitiator::LocalOffered);
10756
- let remote_commit_tx_fee = node_a_chan.context.next_remote_commit_tx_fee_msat(Some(htlc_candidate), None);
10790
+ let remote_commit_tx_fee = node_a_chan.context.next_remote_commit_tx_fee_msat(&node_a_chan.funding, Some(htlc_candidate), None);
10757
10791
assert_eq!(remote_commit_tx_fee, remote_commit_fee_3_htlcs);
10758
10792
}
10759
10793
@@ -10781,27 +10815,27 @@ mod tests {
10781
10815
// counted as dust when it shouldn't be.
10782
10816
let htlc_amt_above_timeout = ((253 * htlc_timeout_tx_weight(chan.context.get_channel_type()) / 1000) + chan.context.holder_dust_limit_satoshis + 1) * 1000;
10783
10817
let htlc_candidate = HTLCCandidate::new(htlc_amt_above_timeout, HTLCInitiator::LocalOffered);
10784
- let commitment_tx_fee = chan.context.next_local_commit_tx_fee_msat(htlc_candidate, None);
10818
+ let commitment_tx_fee = chan.context.next_local_commit_tx_fee_msat(&chan.funding, htlc_candidate, None);
10785
10819
assert_eq!(commitment_tx_fee, commitment_tx_fee_1_htlc);
10786
10820
10787
10821
// If swapped: this HTLC would be counted as non-dust when it shouldn't be.
10788
10822
let dust_htlc_amt_below_success = ((253 * htlc_success_tx_weight(chan.context.get_channel_type()) / 1000) + chan.context.holder_dust_limit_satoshis - 1) * 1000;
10789
10823
let htlc_candidate = HTLCCandidate::new(dust_htlc_amt_below_success, HTLCInitiator::RemoteOffered);
10790
- let commitment_tx_fee = chan.context.next_local_commit_tx_fee_msat(htlc_candidate, None);
10824
+ let commitment_tx_fee = chan.context.next_local_commit_tx_fee_msat(&chan.funding, htlc_candidate, None);
10791
10825
assert_eq!(commitment_tx_fee, commitment_tx_fee_0_htlcs);
10792
10826
10793
10827
chan.context.channel_transaction_parameters.is_outbound_from_holder = false;
10794
10828
10795
10829
// If swapped: this HTLC would be counted as non-dust when it shouldn't be.
10796
10830
let dust_htlc_amt_above_timeout = ((253 * htlc_timeout_tx_weight(chan.context.get_channel_type()) / 1000) + chan.context.counterparty_dust_limit_satoshis + 1) * 1000;
10797
10831
let htlc_candidate = HTLCCandidate::new(dust_htlc_amt_above_timeout, HTLCInitiator::LocalOffered);
10798
- let commitment_tx_fee = chan.context.next_remote_commit_tx_fee_msat(Some(htlc_candidate), None);
10832
+ let commitment_tx_fee = chan.context.next_remote_commit_tx_fee_msat(&chan.funding, Some(htlc_candidate), None);
10799
10833
assert_eq!(commitment_tx_fee, commitment_tx_fee_0_htlcs);
10800
10834
10801
10835
// If swapped: this HTLC would be counted as dust when it shouldn't be.
10802
10836
let htlc_amt_below_success = ((253 * htlc_success_tx_weight(chan.context.get_channel_type()) / 1000) + chan.context.counterparty_dust_limit_satoshis - 1) * 1000;
10803
10837
let htlc_candidate = HTLCCandidate::new(htlc_amt_below_success, HTLCInitiator::RemoteOffered);
10804
- let commitment_tx_fee = chan.context.next_remote_commit_tx_fee_msat(Some(htlc_candidate), None);
10838
+ let commitment_tx_fee = chan.context.next_remote_commit_tx_fee_msat(&chan.funding, Some(htlc_candidate), None);
10805
10839
assert_eq!(commitment_tx_fee, commitment_tx_fee_1_htlc);
10806
10840
}
10807
10841
0 commit comments