Skip to content

Commit 1079753

Browse files
Ensure build_commitment_tx and next_local/remote_tx_fee agree on the fee
1 parent 3d4735c commit 1079753

File tree

1 file changed

+129
-4
lines changed

1 file changed

+129
-4
lines changed

lightning/src/ln/channel.rs

Lines changed: 129 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,8 @@ use std;
4242
use std::default::Default;
4343
use std::{cmp,mem,fmt};
4444
use std::ops::Deref;
45+
#[cfg(any(test, feature = "fuzztarget"))]
46+
use std::sync::Mutex;
4547
use bitcoin::hashes::hex::ToHex;
4648

4749
#[cfg(test)]
@@ -407,6 +409,24 @@ pub(super) struct Channel<ChanSigner: ChannelKeys> {
407409
commitment_secrets: CounterpartyCommitmentSecrets,
408410

409411
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,
410430
}
411431

412432
pub const OUR_MAX_HTLCS: u16 = 50; //TODO
@@ -578,6 +598,11 @@ impl<ChanSigner: ChannelKeys> Channel<ChanSigner> {
578598
commitment_secrets: CounterpartyCommitmentSecrets::new(),
579599

580600
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),
581606
})
582607
}
583608

@@ -811,6 +836,11 @@ impl<ChanSigner: ChannelKeys> Channel<ChanSigner> {
811836
commitment_secrets: CounterpartyCommitmentSecrets::new(),
812837

813838
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),
814844
};
815845

816846
Ok(chan)
@@ -1768,7 +1798,32 @@ impl<ChanSigner: ChannelKeys> Channel<ChanSigner> {
17681798
}
17691799
}
17701800

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
17721827
}
17731828

17741829
// 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> {
18161871
match htlc.state {
18171872
OutboundHTLCState::Committed => included_htlcs += 1,
18181873
OutboundHTLCState::RemoteRemoved {..} => included_htlcs += 1,
1874+
OutboundHTLCState::LocalAnnounced { .. } => included_htlcs += 1,
18191875
_ => {},
18201876
}
18211877
}
18221878

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
18241904
}
18251905

18261906
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> {
20572137
(commitment_tx.1, htlcs_cloned, commitment_tx.0, commitment_txid)
20582138
};
20592139

2140+
let total_fee = feerate_per_kw as u64 * (COMMITMENT_TX_BASE_WEIGHT + (num_htlcs as u64) * COMMITMENT_TX_WEIGHT_PER_HTLC) / 1000;
20602141
//If channel fee was updated by funder confirm funder can afford the new fee rate when applied to the current local commitment transaction
20612142
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-
20642143
let counterparty_reserve_we_require = Channel::<ChanSigner>::get_holder_selected_channel_reserve_satoshis(self.channel_value_satoshis);
20652144
if self.channel_value_satoshis - self.value_to_self_msat / 1000 < total_fee + counterparty_reserve_we_require {
20662145
return Err((None, ChannelError::Close("Funding remote cannot afford proposed new fee".to_owned())));
20672146
}
20682147
}
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+
}
20692165

20702166
if msg.htlc_signatures.len() != num_htlcs {
20712167
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> {
23312427
return Err(ChannelError::Close("Received an unexpected revoke_and_ack".to_owned()));
23322428
}
23332429

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+
23342436
self.commitment_secrets.provide_secret(self.cur_counterparty_commitment_transaction_number + 1, msg.per_commitment_secret)
23352437
.map_err(|_| ChannelError::Close("Previous secrets did not match new one".to_owned()))?;
23362438
self.latest_monitor_update_id += 1;
@@ -3961,6 +4063,24 @@ impl<ChanSigner: ChannelKeys> Channel<ChanSigner> {
39614063
let counterparty_commitment_txid = counterparty_commitment_tx.0.trust().txid();
39624064
let (signature, htlc_signatures);
39634065

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+
39644084
{
39654085
let mut htlcs = Vec::with_capacity(counterparty_commitment_tx.2.len());
39664086
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
45514671
commitment_secrets,
45524672

45534673
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),
45544679
})
45554680
}
45564681
}

0 commit comments

Comments
 (0)