Skip to content

Commit 0f6234c

Browse files
committed
Check that the funding remote can afford the new fee on update_fee
We used to do this on receiving `commitment_signed`, but with the newly introduced stats methods on `ChannelContext`, we can now perform this check on receiving the `update_fee`.
1 parent c5a1d73 commit 0f6234c

File tree

2 files changed

+37
-260
lines changed

2 files changed

+37
-260
lines changed

lightning/src/ln/channel.rs

Lines changed: 34 additions & 144 deletions
Original file line numberDiff line numberDiff line change
@@ -293,24 +293,6 @@ struct InboundHTLCOutput {
293293
state: InboundHTLCState,
294294
}
295295

296-
impl InboundHTLCOutput {
297-
fn is_dust(
298-
&self, local: bool, feerate_per_kw: u32, broadcaster_dust_limit_sat: u64,
299-
features: &ChannelTypeFeatures,
300-
) -> bool {
301-
let (htlc_success_tx_fee_sat, htlc_timeout_tx_fee_sat) =
302-
second_stage_tx_fees_sat(features, feerate_per_kw);
303-
304-
let htlc_tx_fee_sat = if !local {
305-
// This is an offered HTLC.
306-
htlc_timeout_tx_fee_sat
307-
} else {
308-
htlc_success_tx_fee_sat
309-
};
310-
self.amount_msat / 1000 < broadcaster_dust_limit_sat + htlc_tx_fee_sat
311-
}
312-
}
313-
314296
#[cfg_attr(test, derive(Clone, Debug, PartialEq))]
315297
enum OutboundHTLCState {
316298
/// Added by us and included in a commitment_signed (if we were AwaitingRemoteRevoke when we
@@ -436,24 +418,6 @@ struct OutboundHTLCOutput {
436418
send_timestamp: Option<Duration>,
437419
}
438420

439-
impl OutboundHTLCOutput {
440-
fn is_dust(
441-
&self, local: bool, feerate_per_kw: u32, broadcaster_dust_limit_sat: u64,
442-
features: &ChannelTypeFeatures,
443-
) -> bool {
444-
let (htlc_success_tx_fee_sat, htlc_timeout_tx_fee_sat) =
445-
second_stage_tx_fees_sat(features, feerate_per_kw);
446-
447-
let htlc_tx_fee_sat = if local {
448-
// This is an offered HTLC.
449-
htlc_timeout_tx_fee_sat
450-
} else {
451-
htlc_success_tx_fee_sat
452-
};
453-
self.amount_msat / 1000 < broadcaster_dust_limit_sat + htlc_tx_fee_sat
454-
}
455-
}
456-
457421
/// See AwaitingRemoteRevoke ChannelState for more info
458422
#[cfg_attr(test, derive(Clone, Debug, PartialEq))]
459423
enum HTLCUpdateAwaitingACK {
@@ -1126,7 +1090,6 @@ struct HTLCStats {
11261090
/// A struct gathering data on a commitment, either local or remote.
11271091
struct CommitmentData<'a> {
11281092
tx: CommitmentTransaction,
1129-
stats: CommitmentStats,
11301093
htlcs_included: Vec<(HTLCOutputInCommitment, Option<&'a HTLCSource>)>, // the list of HTLCs (dust HTLCs *included*) which were not ignored when building the transaction
11311094
outbound_htlc_preimages: Vec<PaymentPreimage>, // preimages for successful offered HTLCs since last commitment
11321095
inbound_htlc_preimages: Vec<PaymentPreimage>, // preimages for successful received HTLCs since last commitment
@@ -4553,6 +4516,18 @@ where
45534516
"Balance after HTLCs and anchors exhausted on local commitment",
45544517
))
45554518
})?;
4519+
4520+
next_local_commitment_stats
4521+
.get_holder_counterparty_balances_incl_fee_msat()
4522+
.and_then(|(_, counterparty_balance_incl_fee_msat)| {
4523+
counterparty_balance_incl_fee_msat
4524+
.checked_sub(funding.holder_selected_channel_reserve_satoshis * 1000)
4525+
.ok_or(())
4526+
})
4527+
.map_err(|()| {
4528+
ChannelError::close("Funding remote cannot afford proposed new fee".to_owned())
4529+
})?;
4530+
45564531
let next_remote_commitment_stats = self
45574532
.get_next_remote_commitment_stats(
45584533
funding,
@@ -4620,26 +4595,6 @@ where
46204595
bitcoin_tx.txid
46214596
};
46224597

4623-
// If our counterparty updated the channel fee in this commitment transaction, check that
4624-
// they can actually afford the new fee now.
4625-
let update_fee = if let Some((_, update_state)) = self.pending_update_fee {
4626-
update_state == FeeUpdateState::RemoteAnnounced
4627-
} else { false };
4628-
if update_fee {
4629-
debug_assert!(!funding.is_outbound());
4630-
let counterparty_reserve_we_require_msat = funding.holder_selected_channel_reserve_satoshis * 1000;
4631-
if commitment_data.stats.remote_balance_before_fee_msat < commitment_data.stats.commit_tx_fee_sat * 1000 + counterparty_reserve_we_require_msat {
4632-
return Err(ChannelError::close("Funding remote cannot afford proposed new fee".to_owned()));
4633-
}
4634-
}
4635-
#[cfg(any(test, fuzzing))]
4636-
{
4637-
let PredictedNextFee { predicted_feerate, predicted_nondust_htlc_count, predicted_fee_sat } = *funding.next_local_fee.lock().unwrap();
4638-
if predicted_feerate == commitment_data.tx.feerate_per_kw() && predicted_nondust_htlc_count == commitment_data.tx.nondust_htlcs().len() {
4639-
assert_eq!(predicted_fee_sat, commitment_data.stats.commit_tx_fee_sat);
4640-
}
4641-
}
4642-
46434598
if msg.htlc_signatures.len() != commitment_data.tx.nondust_htlcs().len() {
46444599
return Err(ChannelError::close(format!("Got wrong number of HTLC signatures ({}) from remote. It must be {}", msg.htlc_signatures.len(), commitment_data.tx.nondust_htlcs().len())));
46454600
}
@@ -4874,83 +4829,6 @@ where
48744829
feerate_per_kw
48754830
}
48764831

4877-
/// Builds stats on a potential commitment transaction build, without actually building the
4878-
/// commitment transaction. See `build_commitment_transaction` for further docs.
4879-
#[inline]
4880-
#[rustfmt::skip]
4881-
fn build_commitment_stats(&self, funding: &FundingScope, local: bool, generated_by_local: bool, feerate_per_kw: Option<u32>, fee_buffer_nondust_htlcs: Option<usize>) -> CommitmentStats {
4882-
let broadcaster_dust_limit_sat = if local { self.holder_dust_limit_satoshis } else { self.counterparty_dust_limit_satoshis };
4883-
let mut nondust_htlc_count = 0;
4884-
let mut remote_htlc_total_msat = 0;
4885-
let mut local_htlc_total_msat = 0;
4886-
let mut value_to_self_claimed_msat = 0;
4887-
let mut value_to_remote_claimed_msat = 0;
4888-
4889-
let feerate_per_kw = feerate_per_kw.unwrap_or_else(|| self.get_commitment_feerate(funding, generated_by_local));
4890-
4891-
for htlc in self.pending_inbound_htlcs.iter() {
4892-
if htlc.state.included_in_commitment(generated_by_local) {
4893-
if !htlc.is_dust(local, feerate_per_kw, broadcaster_dust_limit_sat, funding.get_channel_type()) {
4894-
nondust_htlc_count += 1;
4895-
}
4896-
remote_htlc_total_msat += htlc.amount_msat;
4897-
} else {
4898-
if htlc.state.preimage().is_some() {
4899-
value_to_self_claimed_msat += htlc.amount_msat;
4900-
}
4901-
}
4902-
};
4903-
4904-
for htlc in self.pending_outbound_htlcs.iter() {
4905-
if htlc.state.included_in_commitment(generated_by_local) {
4906-
if !htlc.is_dust(local, feerate_per_kw, broadcaster_dust_limit_sat, funding.get_channel_type()) {
4907-
nondust_htlc_count += 1;
4908-
}
4909-
local_htlc_total_msat += htlc.amount_msat;
4910-
} else {
4911-
if htlc.state.preimage().is_some() {
4912-
value_to_remote_claimed_msat += htlc.amount_msat;
4913-
}
4914-
}
4915-
};
4916-
4917-
// # Panics
4918-
//
4919-
// After all HTLC claims have been accounted for, the local balance MUST remain greater than or equal to 0.
4920-
4921-
let mut value_to_self_msat = (funding.value_to_self_msat + value_to_self_claimed_msat).checked_sub(value_to_remote_claimed_msat).unwrap();
4922-
4923-
let mut value_to_remote_msat = (funding.get_value_satoshis() * 1000).checked_sub(value_to_self_msat).unwrap();
4924-
value_to_self_msat = value_to_self_msat.checked_sub(local_htlc_total_msat).unwrap();
4925-
value_to_remote_msat = value_to_remote_msat.checked_sub(remote_htlc_total_msat).unwrap();
4926-
4927-
#[cfg(debug_assertions)]
4928-
{
4929-
// Make sure that the to_self/to_remote is always either past the appropriate
4930-
// channel_reserve *or* it is making progress towards it.
4931-
let mut broadcaster_max_commitment_tx_output = if generated_by_local {
4932-
funding.holder_max_commitment_tx_output.lock().unwrap()
4933-
} else {
4934-
funding.counterparty_max_commitment_tx_output.lock().unwrap()
4935-
};
4936-
debug_assert!(broadcaster_max_commitment_tx_output.0 <= value_to_self_msat || value_to_self_msat / 1000 >= funding.counterparty_selected_channel_reserve_satoshis.unwrap());
4937-
broadcaster_max_commitment_tx_output.0 = cmp::max(broadcaster_max_commitment_tx_output.0, value_to_self_msat);
4938-
debug_assert!(broadcaster_max_commitment_tx_output.1 <= value_to_remote_msat || value_to_remote_msat / 1000 >= funding.holder_selected_channel_reserve_satoshis);
4939-
broadcaster_max_commitment_tx_output.1 = cmp::max(broadcaster_max_commitment_tx_output.1, value_to_remote_msat);
4940-
}
4941-
4942-
let commit_tx_fee_sat = SpecTxBuilder {}.commit_tx_fee_sat(feerate_per_kw, nondust_htlc_count + fee_buffer_nondust_htlcs.unwrap_or(0), funding.get_channel_type());
4943-
// Subtract any non-HTLC outputs from the local and remote balances
4944-
let (local_balance_before_fee_msat, remote_balance_before_fee_msat) = SpecTxBuilder {}.subtract_non_htlc_outputs(
4945-
funding.is_outbound(),
4946-
value_to_self_msat,
4947-
value_to_remote_msat,
4948-
funding.get_channel_type(),
4949-
);
4950-
4951-
CommitmentStats { commit_tx_fee_sat, local_balance_before_fee_msat, remote_balance_before_fee_msat }
4952-
}
4953-
49544832
/// Transaction nomenclature is somewhat confusing here as there are many different cases - a
49554833
/// transaction is referred to as "a's transaction" implying that a will be able to broadcast
49564834
/// the transaction. Thus, b will generally be sending a signature over such a transaction to
@@ -5051,7 +4929,28 @@ where
50514929
broadcaster_dust_limit_sat,
50524930
logger,
50534931
);
5054-
debug_assert_eq!(stats, self.build_commitment_stats(funding, local, generated_by_local, None, None), "Caught an inconsistency between `TxBuilder::build_commitment_transaction` and the rest of the `TxBuilder` methods");
4932+
#[cfg(any(test, fuzzing))]
4933+
{
4934+
let PredictedNextFee { predicted_feerate, predicted_nondust_htlc_count, predicted_fee_sat } = if local { *funding.next_local_fee.lock().unwrap() } else { *funding.next_remote_fee.lock().unwrap() };
4935+
if predicted_feerate == tx.feerate_per_kw() && predicted_nondust_htlc_count == tx.nondust_htlcs().len() {
4936+
assert_eq!(predicted_fee_sat, stats.commit_tx_fee_sat);
4937+
}
4938+
}
4939+
#[cfg(debug_assertions)]
4940+
{
4941+
// Make sure that the to_self/to_remote is always either past the appropriate
4942+
// channel_reserve *or* it is making progress towards it.
4943+
let mut broadcaster_max_commitment_tx_output = if generated_by_local {
4944+
funding.holder_max_commitment_tx_output.lock().unwrap()
4945+
} else {
4946+
funding.counterparty_max_commitment_tx_output.lock().unwrap()
4947+
};
4948+
debug_assert!(broadcaster_max_commitment_tx_output.0 <= stats.local_balance_before_fee_msat || stats.local_balance_before_fee_msat / 1000 >= funding.counterparty_selected_channel_reserve_satoshis.unwrap());
4949+
broadcaster_max_commitment_tx_output.0 = cmp::max(broadcaster_max_commitment_tx_output.0, stats.local_balance_before_fee_msat);
4950+
debug_assert!(broadcaster_max_commitment_tx_output.1 <= stats.remote_balance_before_fee_msat || stats.remote_balance_before_fee_msat / 1000 >= funding.holder_selected_channel_reserve_satoshis);
4951+
broadcaster_max_commitment_tx_output.1 = cmp::max(broadcaster_max_commitment_tx_output.1, stats.remote_balance_before_fee_msat);
4952+
}
4953+
50554954

50564955
// This populates the HTLC-source table with the indices from the HTLCs in the commitment
50574956
// transaction.
@@ -5086,7 +4985,6 @@ where
50864985

50874986
CommitmentData {
50884987
tx,
5089-
stats,
50904988
htlcs_included,
50914989
inbound_htlc_preimages,
50924990
outbound_htlc_preimages,
@@ -12123,14 +12021,6 @@ where
1212312021
);
1212412022
let counterparty_commitment_tx = commitment_data.tx;
1212512023

12126-
#[cfg(any(test, fuzzing))]
12127-
{
12128-
let PredictedNextFee { predicted_feerate, predicted_nondust_htlc_count, predicted_fee_sat } = *funding.next_remote_fee.lock().unwrap();
12129-
if predicted_feerate == counterparty_commitment_tx.feerate_per_kw() && predicted_nondust_htlc_count == counterparty_commitment_tx.nondust_htlcs().len() {
12130-
assert_eq!(predicted_fee_sat, commitment_data.stats.commit_tx_fee_sat);
12131-
}
12132-
}
12133-
1213412024
(commitment_data.htlcs_included, counterparty_commitment_tx)
1213512025
}
1213612026

0 commit comments

Comments
 (0)