Skip to content

Commit ef86a3e

Browse files
authored
Merge pull request #1162 from TheBlueMatt/2021-11-fix-accept-chan-checks
Correct initial commitment tx fee affordability checks on open
2 parents 19191b4 + 13e4fd5 commit ef86a3e

File tree

5 files changed

+128
-69
lines changed

5 files changed

+128
-69
lines changed

fuzz/src/full_stack.rs

+2-2
Large diffs are not rendered by default.

lightning/src/ln/channel.rs

+33-23
Original file line numberDiff line numberDiff line change
@@ -406,7 +406,12 @@ pub(crate) const FUNDING_CONF_DEADLINE_BLOCKS: u32 = 2016;
406406
/// size 2. However, if the number of concurrent update_add_htlc is higher, this still
407407
/// leads to a channel force-close. Ultimately, this is an issue coming from the
408408
/// design of LN state machines, allowing asynchronous updates.
409-
const CONCURRENT_INBOUND_HTLC_FEE_BUFFER: u32 = 2;
409+
pub(crate) const CONCURRENT_INBOUND_HTLC_FEE_BUFFER: u32 = 2;
410+
411+
/// When a channel is opened, we check that the funding amount is enough to pay for relevant
412+
/// commitment transaction fees, with at least this many HTLCs present on the commitment
413+
/// transaction (not counting the value of the HTLCs themselves).
414+
pub(crate) const MIN_AFFORDABLE_HTLC_COUNT: usize = 4;
410415

411416
// TODO: We should refactor this to be an Inbound/OutboundChannel until initial setup handshaking
412417
// has been completed, and then turn into a Channel to get compiler-time enforcement of things like
@@ -712,6 +717,12 @@ impl<Signer: Sign> Channel<Signer> {
712717

713718
let feerate = fee_estimator.get_est_sat_per_1000_weight(ConfirmationTarget::Normal);
714719

720+
let value_to_self_msat = channel_value_satoshis * 1000 - push_msat;
721+
let commitment_tx_fee = Self::commit_tx_fee_msat(feerate, MIN_AFFORDABLE_HTLC_COUNT);
722+
if value_to_self_msat < commitment_tx_fee {
723+
return Err(APIError::APIMisuseError{ err: format!("Funding amount ({}) can't even pay fee for initial commitment transaction fee of {}.", value_to_self_msat / 1000, commitment_tx_fee / 1000) });
724+
}
725+
715726
let mut secp_ctx = Secp256k1::new();
716727
secp_ctx.seeded_randomize(&keys_provider.get_secure_random_bytes());
717728

@@ -742,7 +753,7 @@ impl<Signer: Sign> Channel<Signer> {
742753

743754
cur_holder_commitment_transaction_number: INITIAL_COMMITMENT_NUMBER,
744755
cur_counterparty_commitment_transaction_number: INITIAL_COMMITMENT_NUMBER,
745-
value_to_self_msat: channel_value_satoshis * 1000 - push_msat,
756+
value_to_self_msat,
746757

747758
pending_inbound_htlcs: Vec::new(),
748759
pending_outbound_htlcs: Vec::new(),
@@ -957,8 +968,6 @@ impl<Signer: Sign> Channel<Signer> {
957968
// we either accept their preference or the preferences match
958969
local_config.announced_channel = announce;
959970

960-
let background_feerate = fee_estimator.get_est_sat_per_1000_weight(ConfirmationTarget::Background);
961-
962971
let holder_selected_channel_reserve_satoshis = Channel::<Signer>::get_holder_selected_channel_reserve_satoshis(msg.funding_satoshis);
963972
if holder_selected_channel_reserve_satoshis < MIN_CHAN_DUST_LIMIT_SATOSHIS {
964973
return Err(ChannelError::Close(format!("Suitable channel reserve not found. remote_channel_reserve was ({}). dust_limit_satoshis is ({}).", holder_selected_channel_reserve_satoshis, MIN_CHAN_DUST_LIMIT_SATOSHIS)));
@@ -971,17 +980,18 @@ impl<Signer: Sign> Channel<Signer> {
971980
}
972981

973982
// check if the funder's amount for the initial commitment tx is sufficient
974-
// for full fee payment
983+
// for full fee payment plus a few HTLCs to ensure the channel will be useful.
975984
let funders_amount_msat = msg.funding_satoshis * 1000 - msg.push_msat;
976-
let lower_limit = background_feerate as u64 * COMMITMENT_TX_BASE_WEIGHT;
977-
if funders_amount_msat < lower_limit {
978-
return Err(ChannelError::Close(format!("Insufficient funding amount ({}) for initial commitment. Must be at least {}", funders_amount_msat, lower_limit)));
985+
let commitment_tx_fee = Self::commit_tx_fee_msat(msg.feerate_per_kw, MIN_AFFORDABLE_HTLC_COUNT) / 1000;
986+
if funders_amount_msat / 1000 < commitment_tx_fee {
987+
return Err(ChannelError::Close(format!("Funding amount ({} sats) can't even pay fee for initial commitment transaction fee of {} sats.", funders_amount_msat / 1000, commitment_tx_fee)));
979988
}
980989

981-
let to_local_msat = msg.push_msat;
982-
let to_remote_msat = funders_amount_msat - background_feerate as u64 * COMMITMENT_TX_BASE_WEIGHT;
983-
if to_local_msat <= msg.channel_reserve_satoshis * 1000 && to_remote_msat <= holder_selected_channel_reserve_satoshis * 1000 {
984-
return Err(ChannelError::Close("Insufficient funding amount for initial commitment".to_owned()));
990+
let to_remote_satoshis = funders_amount_msat / 1000 - commitment_tx_fee;
991+
// While it's reasonable for us to not meet the channel reserve initially (if they don't
992+
// want to push much to us), our counterparty should always have more than our reserve.
993+
if to_remote_satoshis < holder_selected_channel_reserve_satoshis {
994+
return Err(ChannelError::Close("Insufficient funding amount for initial reserve".to_owned()));
985995
}
986996

987997
let counterparty_shutdown_scriptpubkey = if their_features.supports_upfront_shutdown_script() {
@@ -2115,10 +2125,10 @@ impl<Signer: Sign> Channel<Signer> {
21152125

21162126
// Get the fee cost in MSATS of a commitment tx with a given number of HTLC outputs.
21172127
// Note that num_htlcs should not include dust HTLCs.
2118-
fn commit_tx_fee_msat(&self, num_htlcs: usize) -> u64 {
2128+
fn commit_tx_fee_msat(feerate_per_kw: u32, num_htlcs: usize) -> u64 {
21192129
// Note that we need to divide before multiplying to round properly,
21202130
// since the lowest denomination of bitcoin on-chain is the satoshi.
2121-
(COMMITMENT_TX_BASE_WEIGHT + num_htlcs as u64 * COMMITMENT_TX_WEIGHT_PER_HTLC) * self.feerate_per_kw as u64 / 1000 * 1000
2131+
(COMMITMENT_TX_BASE_WEIGHT + num_htlcs as u64 * COMMITMENT_TX_WEIGHT_PER_HTLC) * feerate_per_kw as u64 / 1000 * 1000
21222132
}
21232133

21242134
// Get the fee cost in SATS of a commitment tx with a given number of HTLC outputs.
@@ -2192,12 +2202,12 @@ impl<Signer: Sign> Channel<Signer> {
21922202
}
21932203

21942204
let num_htlcs = included_htlcs + addl_htlcs;
2195-
let res = self.commit_tx_fee_msat(num_htlcs);
2205+
let res = Self::commit_tx_fee_msat(self.feerate_per_kw, num_htlcs);
21962206
#[cfg(any(test, feature = "fuzztarget"))]
21972207
{
21982208
let mut fee = res;
21992209
if fee_spike_buffer_htlc.is_some() {
2200-
fee = self.commit_tx_fee_msat(num_htlcs - 1);
2210+
fee = Self::commit_tx_fee_msat(self.feerate_per_kw, num_htlcs - 1);
22012211
}
22022212
let total_pending_htlcs = self.pending_inbound_htlcs.len() + self.pending_outbound_htlcs.len()
22032213
+ self.holding_cell_htlc_updates.len();
@@ -2270,12 +2280,12 @@ impl<Signer: Sign> Channel<Signer> {
22702280
}
22712281

22722282
let num_htlcs = included_htlcs + addl_htlcs;
2273-
let res = self.commit_tx_fee_msat(num_htlcs);
2283+
let res = Self::commit_tx_fee_msat(self.feerate_per_kw, num_htlcs);
22742284
#[cfg(any(test, feature = "fuzztarget"))]
22752285
{
22762286
let mut fee = res;
22772287
if fee_spike_buffer_htlc.is_some() {
2278-
fee = self.commit_tx_fee_msat(num_htlcs - 1);
2288+
fee = Self::commit_tx_fee_msat(self.feerate_per_kw, num_htlcs - 1);
22792289
}
22802290
let total_pending_htlcs = self.pending_inbound_htlcs.len() + self.pending_outbound_htlcs.len();
22812291
let commitment_tx_info = CommitmentTxInfoCached {
@@ -4902,7 +4912,7 @@ impl<Signer: Sign> Channel<Signer> {
49024912
&& info.next_holder_htlc_id == self.next_holder_htlc_id
49034913
&& info.next_counterparty_htlc_id == self.next_counterparty_htlc_id
49044914
&& info.feerate == self.feerate_per_kw {
4905-
let actual_fee = self.commit_tx_fee_msat(commitment_stats.num_nondust_htlcs);
4915+
let actual_fee = Self::commit_tx_fee_msat(self.feerate_per_kw, commitment_stats.num_nondust_htlcs);
49064916
assert_eq!(actual_fee, info.fee);
49074917
}
49084918
}
@@ -5932,13 +5942,13 @@ mod tests {
59325942
// the dust limit check.
59335943
let htlc_candidate = HTLCCandidate::new(htlc_amount_msat, HTLCInitiator::LocalOffered);
59345944
let local_commit_tx_fee = node_a_chan.next_local_commit_tx_fee_msat(htlc_candidate, None);
5935-
let local_commit_fee_0_htlcs = node_a_chan.commit_tx_fee_msat(0);
5945+
let local_commit_fee_0_htlcs = Channel::<EnforcingSigner>::commit_tx_fee_msat(node_a_chan.feerate_per_kw, 0);
59365946
assert_eq!(local_commit_tx_fee, local_commit_fee_0_htlcs);
59375947

59385948
// Finally, make sure that when Node A calculates the remote's commitment transaction fees, all
59395949
// of the HTLCs are seen to be above the dust limit.
59405950
node_a_chan.channel_transaction_parameters.is_outbound_from_holder = false;
5941-
let remote_commit_fee_3_htlcs = node_a_chan.commit_tx_fee_msat(3);
5951+
let remote_commit_fee_3_htlcs = Channel::<EnforcingSigner>::commit_tx_fee_msat(node_a_chan.feerate_per_kw, 3);
59425952
let htlc_candidate = HTLCCandidate::new(htlc_amount_msat, HTLCInitiator::LocalOffered);
59435953
let remote_commit_tx_fee = node_a_chan.next_remote_commit_tx_fee_msat(htlc_candidate, None);
59445954
assert_eq!(remote_commit_tx_fee, remote_commit_fee_3_htlcs);
@@ -5960,8 +5970,8 @@ mod tests {
59605970
let config = UserConfig::default();
59615971
let mut chan = Channel::<EnforcingSigner>::new_outbound(&&fee_est, &&keys_provider, node_id, &InitFeatures::known(), 10000000, 100000, 42, &config, 0).unwrap();
59625972

5963-
let commitment_tx_fee_0_htlcs = chan.commit_tx_fee_msat(0);
5964-
let commitment_tx_fee_1_htlc = chan.commit_tx_fee_msat(1);
5973+
let commitment_tx_fee_0_htlcs = Channel::<EnforcingSigner>::commit_tx_fee_msat(chan.feerate_per_kw, 0);
5974+
let commitment_tx_fee_1_htlc = Channel::<EnforcingSigner>::commit_tx_fee_msat(chan.feerate_per_kw, 1);
59655975

59665976
// If HTLC_SUCCESS_TX_WEIGHT and HTLC_TIMEOUT_TX_WEIGHT were swapped: then this HTLC would be
59675977
// counted as dust when it shouldn't be.

0 commit comments

Comments
 (0)