@@ -2062,6 +2062,10 @@ pub(super) struct FundingScope {
20622062 next_local_commitment_tx_fee_info_cached: Mutex<Option<CommitmentTxInfoCached>>,
20632063 #[cfg(any(test, fuzzing))]
20642064 next_remote_commitment_tx_fee_info_cached: Mutex<Option<CommitmentTxInfoCached>>,
2065+ #[cfg(any(test, fuzzing))]
2066+ next_local_fee: Mutex<PredictedNextFee>,
2067+ #[cfg(any(test, fuzzing))]
2068+ next_remote_fee: Mutex<PredictedNextFee>,
20652069
20662070 pub(super) channel_transaction_parameters: ChannelTransactionParameters,
20672071
@@ -2138,6 +2142,10 @@ impl Readable for FundingScope {
21382142 next_local_commitment_tx_fee_info_cached: Mutex::new(None),
21392143 #[cfg(any(test, fuzzing))]
21402144 next_remote_commitment_tx_fee_info_cached: Mutex::new(None),
2145+ #[cfg(any(test, fuzzing))]
2146+ next_local_fee: Mutex::new(PredictedNextFee::default()),
2147+ #[cfg(any(test, fuzzing))]
2148+ next_remote_fee: Mutex::new(PredictedNextFee::default()),
21412149 })
21422150 }
21432151}
@@ -2314,6 +2322,10 @@ impl FundingScope {
23142322 next_local_commitment_tx_fee_info_cached: Mutex::new(None),
23152323 #[cfg(any(test, fuzzing))]
23162324 next_remote_commitment_tx_fee_info_cached: Mutex::new(None),
2325+ #[cfg(any(test, fuzzing))]
2326+ next_local_fee: Mutex::new(PredictedNextFee::default()),
2327+ #[cfg(any(test, fuzzing))]
2328+ next_remote_fee: Mutex::new(PredictedNextFee::default()),
23172329 funding_tx_confirmation_height: 0,
23182330 funding_tx_confirmed_in: None,
23192331 minimum_depth_override: None,
@@ -3197,6 +3209,10 @@ where
31973209 next_local_commitment_tx_fee_info_cached: Mutex::new(None),
31983210 #[cfg(any(test, fuzzing))]
31993211 next_remote_commitment_tx_fee_info_cached: Mutex::new(None),
3212+ #[cfg(any(test, fuzzing))]
3213+ next_local_fee: Mutex::new(PredictedNextFee::default()),
3214+ #[cfg(any(test, fuzzing))]
3215+ next_remote_fee: Mutex::new(PredictedNextFee::default()),
32003216
32013217 channel_transaction_parameters: ChannelTransactionParameters {
32023218 holder_pubkeys: pubkeys,
@@ -3437,6 +3453,10 @@ where
34373453 next_local_commitment_tx_fee_info_cached: Mutex::new(None),
34383454 #[cfg(any(test, fuzzing))]
34393455 next_remote_commitment_tx_fee_info_cached: Mutex::new(None),
3456+ #[cfg(any(test, fuzzing))]
3457+ next_local_fee: Mutex::new(PredictedNextFee::default()),
3458+ #[cfg(any(test, fuzzing))]
3459+ next_remote_fee: Mutex::new(PredictedNextFee::default()),
34403460
34413461 channel_transaction_parameters: ChannelTransactionParameters {
34423462 holder_pubkeys: pubkeys,
@@ -4216,7 +4236,8 @@ where
42164236 include_counterparty_unknown_htlcs,
42174237 );
42184238 let next_value_to_self_msat = self.get_next_commitment_value_to_self_msat(true, funding);
4219- SpecTxBuilder {}.get_next_commitment_stats(
4239+
4240+ let ret = SpecTxBuilder {}.get_next_commitment_stats(
42204241 true,
42214242 funding.is_outbound(),
42224243 funding.get_value_satoshis(),
@@ -4227,7 +4248,38 @@ where
42274248 dust_exposure_limiting_feerate,
42284249 self.holder_dust_limit_satoshis,
42294250 funding.get_channel_type(),
4230- )
4251+ );
4252+
4253+ #[cfg(any(test, fuzzing))]
4254+ {
4255+ if addl_nondust_htlc_count == 0 {
4256+ *funding.next_local_fee.lock().unwrap() = PredictedNextFee {
4257+ predicted_feerate: feerate_per_kw,
4258+ predicted_nondust_htlc_count: ret.nondust_htlc_count,
4259+ predicted_fee_sat: ret.commit_tx_fee_sat,
4260+ };
4261+ } else {
4262+ let predicted_stats = SpecTxBuilder {}.get_next_commitment_stats(
4263+ true,
4264+ funding.is_outbound(),
4265+ funding.get_value_satoshis(),
4266+ next_value_to_self_msat,
4267+ &next_commitment_htlcs,
4268+ 0,
4269+ feerate_per_kw,
4270+ dust_exposure_limiting_feerate,
4271+ self.holder_dust_limit_satoshis,
4272+ funding.get_channel_type(),
4273+ );
4274+ *funding.next_local_fee.lock().unwrap() = PredictedNextFee {
4275+ predicted_feerate: feerate_per_kw,
4276+ predicted_nondust_htlc_count: predicted_stats.nondust_htlc_count,
4277+ predicted_fee_sat: predicted_stats.commit_tx_fee_sat,
4278+ };
4279+ }
4280+ }
4281+
4282+ ret
42314283 }
42324284
42334285 fn get_next_remote_commitment_stats(
@@ -4241,7 +4293,8 @@ where
42414293 include_counterparty_unknown_htlcs,
42424294 );
42434295 let next_value_to_self_msat = self.get_next_commitment_value_to_self_msat(false, funding);
4244- SpecTxBuilder {}.get_next_commitment_stats(
4296+
4297+ let ret = SpecTxBuilder {}.get_next_commitment_stats(
42454298 false,
42464299 funding.is_outbound(),
42474300 funding.get_value_satoshis(),
@@ -4252,7 +4305,38 @@ where
42524305 dust_exposure_limiting_feerate,
42534306 self.counterparty_dust_limit_satoshis,
42544307 funding.get_channel_type(),
4255- )
4308+ );
4309+
4310+ #[cfg(any(test, fuzzing))]
4311+ {
4312+ if addl_nondust_htlc_count == 0 {
4313+ *funding.next_remote_fee.lock().unwrap() = PredictedNextFee {
4314+ predicted_feerate: feerate_per_kw,
4315+ predicted_nondust_htlc_count: ret.nondust_htlc_count,
4316+ predicted_fee_sat: ret.commit_tx_fee_sat,
4317+ };
4318+ } else {
4319+ let predicted_stats = SpecTxBuilder {}.get_next_commitment_stats(
4320+ false,
4321+ funding.is_outbound(),
4322+ funding.get_value_satoshis(),
4323+ next_value_to_self_msat,
4324+ &next_commitment_htlcs,
4325+ 0,
4326+ feerate_per_kw,
4327+ dust_exposure_limiting_feerate,
4328+ self.counterparty_dust_limit_satoshis,
4329+ funding.get_channel_type(),
4330+ );
4331+ *funding.next_remote_fee.lock().unwrap() = PredictedNextFee {
4332+ predicted_feerate: feerate_per_kw,
4333+ predicted_nondust_htlc_count: predicted_stats.nondust_htlc_count,
4334+ predicted_fee_sat: predicted_stats.commit_tx_fee_sat,
4335+ };
4336+ }
4337+ }
4338+
4339+ ret
42564340 }
42574341
42584342 #[rustfmt::skip]
@@ -4410,6 +4494,10 @@ where
44104494 }
44114495 }
44124496 }
4497+ let PredictedNextFee { predicted_feerate, predicted_nondust_htlc_count, predicted_fee_sat } = *funding.next_local_fee.lock().unwrap();
4498+ if predicted_feerate == commitment_data.tx.feerate_per_kw() && predicted_nondust_htlc_count == commitment_data.tx.nondust_htlcs().len() {
4499+ assert_eq!(predicted_fee_sat, commitment_data.stats.commit_tx_fee_sat);
4500+ }
44134501 }
44144502
44154503 if msg.htlc_signatures.len() != commitment_data.tx.nondust_htlcs().len() {
@@ -6216,6 +6304,14 @@ struct CommitmentTxInfoCached {
62166304 feerate: u32,
62176305}
62186306
6307+ #[cfg(any(test, fuzzing))]
6308+ #[derive(Clone, Copy, Default)]
6309+ struct PredictedNextFee {
6310+ predicted_feerate: u32,
6311+ predicted_nondust_htlc_count: usize,
6312+ predicted_fee_sat: u64,
6313+ }
6314+
62196315/// Contents of a wire message that fails an HTLC backwards. Useful for [`FundedChannel::fail_htlc`] to
62206316/// fail with either [`msgs::UpdateFailMalformedHTLC`] or [`msgs::UpdateFailHTLC`] as needed.
62216317trait FailHTLCContents {
@@ -11386,6 +11482,10 @@ where
1138611482 }
1138711483 }
1138811484 }
11485+ let PredictedNextFee { predicted_feerate, predicted_nondust_htlc_count, predicted_fee_sat } = *funding.next_remote_fee.lock().unwrap();
11486+ if predicted_feerate == counterparty_commitment_tx.feerate_per_kw() && predicted_nondust_htlc_count == counterparty_commitment_tx.nondust_htlcs().len() {
11487+ assert_eq!(predicted_fee_sat, commitment_data.stats.commit_tx_fee_sat);
11488+ }
1138911489 }
1139011490
1139111491 (commitment_data.htlcs_included, counterparty_commitment_tx)
@@ -14032,6 +14132,10 @@ where
1403214132 next_local_commitment_tx_fee_info_cached: Mutex::new(None),
1403314133 #[cfg(any(test, fuzzing))]
1403414134 next_remote_commitment_tx_fee_info_cached: Mutex::new(None),
14135+ #[cfg(any(test, fuzzing))]
14136+ next_local_fee: Mutex::new(PredictedNextFee::default()),
14137+ #[cfg(any(test, fuzzing))]
14138+ next_remote_fee: Mutex::new(PredictedNextFee::default()),
1403514139
1403614140 channel_transaction_parameters: channel_parameters,
1403714141 funding_transaction,
@@ -16092,7 +16196,7 @@ mod tests {
1609216196 fn get_pre_and_post(
1609316197 pre_channel_value: u64, our_funding_contribution: i64, their_funding_contribution: i64,
1609416198 ) -> (u64, u64) {
16095- use crate::ln::channel::FundingScope;
16199+ use crate::ln::channel::{ FundingScope, PredictedNextFee} ;
1609616200
1609716201 let funding = FundingScope {
1609816202 value_to_self_msat: 0,
@@ -16109,6 +16213,11 @@ mod tests {
1610916213 #[cfg(any(test, fuzzing))]
1611016214 next_remote_commitment_tx_fee_info_cached: Mutex::new(None),
1611116215
16216+ #[cfg(any(test, fuzzing))]
16217+ next_local_fee: Mutex::new(PredictedNextFee::default()),
16218+ #[cfg(any(test, fuzzing))]
16219+ next_remote_fee: Mutex::new(PredictedNextFee::default()),
16220+
1611216221 channel_transaction_parameters: ChannelTransactionParameters::test_dummy(
1611316222 pre_channel_value,
1611416223 ),
0 commit comments