@@ -42,6 +42,8 @@ use std;
42
42
use std::default::Default;
43
43
use std::{cmp,mem,fmt};
44
44
use std::ops::Deref;
45
+ #[cfg(any(test, feature = "fuzztarget"))]
46
+ use std::sync::Mutex;
45
47
use bitcoin::hashes::hex::ToHex;
46
48
47
49
#[cfg(test)]
@@ -407,6 +409,24 @@ pub(super) struct Channel<ChanSigner: ChannelKeys> {
407
409
commitment_secrets: CounterpartyCommitmentSecrets,
408
410
409
411
network_sync: UpdateStatus,
412
+
413
+ // We save these values so we can make sure `next_local_commit_tx_fee_msat` and
414
+ // `next_remote_commit_tx_fee_msat` properly predict what the next commitment transaction fee will
415
+ // be, by comparing the cached values to the fee of the tranaction generated by
416
+ // `build_commitment_transaction`.
417
+ #[cfg(any(test, feature = "fuzztarget"))]
418
+ next_local_commitment_tx_fee_info_cached: Mutex<Option<CommitmentTxInfoCached>>,
419
+ #[cfg(any(test, feature = "fuzztarget"))]
420
+ next_remote_commitment_tx_fee_info_cached: Mutex<Option<CommitmentTxInfoCached>>,
421
+ }
422
+
423
+ #[cfg(any(test, feature = "fuzztarget"))]
424
+ struct CommitmentTxInfoCached {
425
+ fee: u64,
426
+ total_pending_htlcs: usize,
427
+ next_holder_htlc_id: u64,
428
+ next_counterparty_htlc_id: u64,
429
+ feerate: u32,
410
430
}
411
431
412
432
pub const OUR_MAX_HTLCS: u16 = 50; //TODO
@@ -578,6 +598,11 @@ impl<ChanSigner: ChannelKeys> Channel<ChanSigner> {
578
598
commitment_secrets: CounterpartyCommitmentSecrets::new(),
579
599
580
600
network_sync: UpdateStatus::Fresh,
601
+
602
+ #[cfg(any(test, feature = "fuzztarget"))]
603
+ next_local_commitment_tx_fee_info_cached: Mutex::new(None),
604
+ #[cfg(any(test, feature = "fuzztarget"))]
605
+ next_remote_commitment_tx_fee_info_cached: Mutex::new(None),
581
606
})
582
607
}
583
608
@@ -811,6 +836,11 @@ impl<ChanSigner: ChannelKeys> Channel<ChanSigner> {
811
836
commitment_secrets: CounterpartyCommitmentSecrets::new(),
812
837
813
838
network_sync: UpdateStatus::Fresh,
839
+
840
+ #[cfg(any(test, feature = "fuzztarget"))]
841
+ next_local_commitment_tx_fee_info_cached: Mutex::new(None),
842
+ #[cfg(any(test, feature = "fuzztarget"))]
843
+ next_remote_commitment_tx_fee_info_cached: Mutex::new(None),
814
844
};
815
845
816
846
Ok(chan)
@@ -1768,7 +1798,32 @@ impl<ChanSigner: ChannelKeys> Channel<ChanSigner> {
1768
1798
}
1769
1799
}
1770
1800
1771
- self.commit_tx_fee_msat(included_htlcs + addl_htlcs)
1801
+ let num_htlcs = included_htlcs + addl_htlcs;
1802
+ let res = self.commit_tx_fee_msat(num_htlcs);
1803
+ #[cfg(any(test, feature = "fuzztarget"))]
1804
+ {
1805
+ let mut fee = res;
1806
+ if fee_spike_buffer_htlc.is_some() {
1807
+ fee = self.commit_tx_fee_msat(num_htlcs - 1);
1808
+ }
1809
+ let total_pending_htlcs = self.pending_inbound_htlcs.len() + self.pending_outbound_htlcs.len()
1810
+ + self.holding_cell_htlc_updates.len();
1811
+ let commitment_tx_info = CommitmentTxInfoCached {
1812
+ fee,
1813
+ total_pending_htlcs,
1814
+ next_holder_htlc_id: match htlc.origin {
1815
+ HTLCInitiator::LocalOffered => self.next_holder_htlc_id + 1,
1816
+ HTLCInitiator::RemoteOffered => self.next_holder_htlc_id,
1817
+ },
1818
+ next_counterparty_htlc_id: match htlc.origin {
1819
+ HTLCInitiator::LocalOffered => self.next_counterparty_htlc_id,
1820
+ HTLCInitiator::RemoteOffered => self.next_counterparty_htlc_id + 1,
1821
+ },
1822
+ feerate: self.feerate_per_kw,
1823
+ };
1824
+ *self.next_local_commitment_tx_fee_info_cached.lock().unwrap() = Some(commitment_tx_info);
1825
+ }
1826
+ res
1772
1827
}
1773
1828
1774
1829
// Get the commitment tx fee for the remote's next commitment transaction based on the number of
@@ -1816,11 +1871,36 @@ impl<ChanSigner: ChannelKeys> Channel<ChanSigner> {
1816
1871
match htlc.state {
1817
1872
OutboundHTLCState::Committed => included_htlcs += 1,
1818
1873
OutboundHTLCState::RemoteRemoved {..} => included_htlcs += 1,
1874
+ OutboundHTLCState::LocalAnnounced { .. } => included_htlcs += 1,
1819
1875
_ => {},
1820
1876
}
1821
1877
}
1822
1878
1823
- self.commit_tx_fee_msat(included_htlcs + addl_htlcs)
1879
+ let num_htlcs = included_htlcs + addl_htlcs;
1880
+ let res = self.commit_tx_fee_msat(num_htlcs);
1881
+ #[cfg(any(test, feature = "fuzztarget"))]
1882
+ {
1883
+ let mut fee = res;
1884
+ if fee_spike_buffer_htlc.is_some() {
1885
+ fee = self.commit_tx_fee_msat(num_htlcs - 1);
1886
+ }
1887
+ let total_pending_htlcs = self.pending_inbound_htlcs.len() + self.pending_outbound_htlcs.len();
1888
+ let commitment_tx_info = CommitmentTxInfoCached {
1889
+ fee,
1890
+ total_pending_htlcs,
1891
+ next_holder_htlc_id: match htlc.origin {
1892
+ HTLCInitiator::LocalOffered => self.next_holder_htlc_id + 1,
1893
+ HTLCInitiator::RemoteOffered => self.next_holder_htlc_id,
1894
+ },
1895
+ next_counterparty_htlc_id: match htlc.origin {
1896
+ HTLCInitiator::LocalOffered => self.next_counterparty_htlc_id,
1897
+ HTLCInitiator::RemoteOffered => self.next_counterparty_htlc_id + 1,
1898
+ },
1899
+ feerate: self.feerate_per_kw,
1900
+ };
1901
+ *self.next_remote_commitment_tx_fee_info_cached.lock().unwrap() = Some(commitment_tx_info);
1902
+ }
1903
+ res
1824
1904
}
1825
1905
1826
1906
pub fn update_add_htlc<F, L: Deref>(&mut self, msg: &msgs::UpdateAddHTLC, mut pending_forward_status: PendingHTLCStatus, create_pending_htlc_status: F, logger: &L) -> Result<(), ChannelError>
@@ -2057,15 +2137,31 @@ impl<ChanSigner: ChannelKeys> Channel<ChanSigner> {
2057
2137
(commitment_tx.1, htlcs_cloned, commitment_tx.0, commitment_txid)
2058
2138
};
2059
2139
2140
+ let total_fee = feerate_per_kw as u64 * (COMMITMENT_TX_BASE_WEIGHT + (num_htlcs as u64) * COMMITMENT_TX_WEIGHT_PER_HTLC) / 1000;
2060
2141
//If channel fee was updated by funder confirm funder can afford the new fee rate when applied to the current local commitment transaction
2061
2142
if update_fee {
2062
- let total_fee = feerate_per_kw as u64 * (COMMITMENT_TX_BASE_WEIGHT + (num_htlcs as u64) * COMMITMENT_TX_WEIGHT_PER_HTLC) / 1000;
2063
-
2064
2143
let counterparty_reserve_we_require = Channel::<ChanSigner>::get_holder_selected_channel_reserve_satoshis(self.channel_value_satoshis);
2065
2144
if self.channel_value_satoshis - self.value_to_self_msat / 1000 < total_fee + counterparty_reserve_we_require {
2066
2145
return Err((None, ChannelError::Close("Funding remote cannot afford proposed new fee".to_owned())));
2067
2146
}
2068
2147
}
2148
+ #[cfg(any(test, feature = "fuzztarget"))]
2149
+ {
2150
+ if self.is_outbound() {
2151
+ let projected_commit_tx_info = self.next_local_commitment_tx_fee_info_cached.lock().unwrap().take();
2152
+ *self.next_remote_commitment_tx_fee_info_cached.lock().unwrap() = None;
2153
+ if let Some(info) = projected_commit_tx_info {
2154
+ let total_pending_htlcs = self.pending_inbound_htlcs.len() + self.pending_outbound_htlcs.len()
2155
+ + self.holding_cell_htlc_updates.len();
2156
+ if info.total_pending_htlcs == total_pending_htlcs
2157
+ && info.next_holder_htlc_id == self.next_holder_htlc_id
2158
+ && info.next_counterparty_htlc_id == self.next_counterparty_htlc_id
2159
+ && info.feerate == self.feerate_per_kw {
2160
+ assert_eq!(total_fee, info.fee / 1000);
2161
+ }
2162
+ }
2163
+ }
2164
+ }
2069
2165
2070
2166
if msg.htlc_signatures.len() != num_htlcs {
2071
2167
return Err((None, ChannelError::Close(format!("Got wrong number of HTLC signatures ({}) from remote. It must be {}", msg.htlc_signatures.len(), num_htlcs))));
@@ -2331,6 +2427,12 @@ impl<ChanSigner: ChannelKeys> Channel<ChanSigner> {
2331
2427
return Err(ChannelError::Close("Received an unexpected revoke_and_ack".to_owned()));
2332
2428
}
2333
2429
2430
+ #[cfg(any(test, feature = "fuzztarget"))]
2431
+ {
2432
+ *self.next_local_commitment_tx_fee_info_cached.lock().unwrap() = None;
2433
+ *self.next_remote_commitment_tx_fee_info_cached.lock().unwrap() = None;
2434
+ }
2435
+
2334
2436
self.commitment_secrets.provide_secret(self.cur_counterparty_commitment_transaction_number + 1, msg.per_commitment_secret)
2335
2437
.map_err(|_| ChannelError::Close("Previous secrets did not match new one".to_owned()))?;
2336
2438
self.latest_monitor_update_id += 1;
@@ -3961,6 +4063,24 @@ impl<ChanSigner: ChannelKeys> Channel<ChanSigner> {
3961
4063
let counterparty_commitment_txid = counterparty_commitment_tx.0.trust().txid();
3962
4064
let (signature, htlc_signatures);
3963
4065
4066
+ #[cfg(any(test, feature = "fuzztarget"))]
4067
+ {
4068
+ if !self.is_outbound() {
4069
+ let projected_commit_tx_info = self.next_remote_commitment_tx_fee_info_cached.lock().unwrap().take();
4070
+ *self.next_local_commitment_tx_fee_info_cached.lock().unwrap() = None;
4071
+ if let Some(info) = projected_commit_tx_info {
4072
+ let total_pending_htlcs = self.pending_inbound_htlcs.len() + self.pending_outbound_htlcs.len();
4073
+ if info.total_pending_htlcs == total_pending_htlcs
4074
+ && info.next_holder_htlc_id == self.next_holder_htlc_id
4075
+ && info.next_counterparty_htlc_id == self.next_counterparty_htlc_id
4076
+ && info.feerate == self.feerate_per_kw {
4077
+ let actual_fee = self.commit_tx_fee_msat(counterparty_commitment_tx.1);
4078
+ assert_eq!(actual_fee, info.fee);
4079
+ }
4080
+ }
4081
+ }
4082
+ }
4083
+
3964
4084
{
3965
4085
let mut htlcs = Vec::with_capacity(counterparty_commitment_tx.2.len());
3966
4086
for &(ref htlc, _) in counterparty_commitment_tx.2.iter() {
@@ -4551,6 +4671,11 @@ impl<'a, ChanSigner: ChannelKeys, K: Deref> ReadableArgs<&'a K> for Channel<Chan
4551
4671
commitment_secrets,
4552
4672
4553
4673
network_sync: UpdateStatus::Fresh,
4674
+
4675
+ #[cfg(any(test, feature = "fuzztarget"))]
4676
+ next_local_commitment_tx_fee_info_cached: Mutex::new(None),
4677
+ #[cfg(any(test, feature = "fuzztarget"))]
4678
+ next_remote_commitment_tx_fee_info_cached: Mutex::new(None),
4554
4679
})
4555
4680
}
4556
4681
}
0 commit comments