Skip to content

Commit 872337e

Browse files
committed
Check pending funding in can_accept_incoming_htlc
If there are any pending splices when an accepting an incoming HTLC, the HTLC needs to be validated against each pending FundingScope. Otherwise, once the splice is locked, the HTLC could have been failed when it should have been forwarded / claimed, or vice versa, under the promoted FundingScope.
1 parent a4e0de3 commit 872337e

File tree

1 file changed

+24
-10
lines changed

1 file changed

+24
-10
lines changed

lightning/src/ln/channel.rs

Lines changed: 24 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -8138,7 +8138,21 @@ impl<SP: Deref> FundedChannel<SP> where
81388138
}
81398139

81408140
let dust_exposure_limiting_feerate = self.context.get_dust_exposure_limiting_feerate(&fee_estimator);
8141-
let htlc_stats = self.context.get_pending_htlc_stats(&self.funding, None, dust_exposure_limiting_feerate);
8141+
8142+
core::iter::once(&self.funding)
8143+
.chain(self.pending_funding.iter())
8144+
.map(|funding| self.can_accept_incoming_htlc_for_funding(funding, msg, dust_exposure_limiting_feerate, &logger))
8145+
.collect::<Result<(), LocalHTLCFailureReason>>()
8146+
}
8147+
8148+
fn can_accept_incoming_htlc_for_funding<L: Deref>(
8149+
&self, funding: &FundingScope, msg: &msgs::UpdateAddHTLC,
8150+
dust_exposure_limiting_feerate: u32, logger: &L,
8151+
) -> Result<(), LocalHTLCFailureReason>
8152+
where
8153+
L::Target: Logger,
8154+
{
8155+
let htlc_stats = self.context.get_pending_htlc_stats(funding, None, dust_exposure_limiting_feerate);
81428156
let max_dust_htlc_exposure_msat = self.context.get_max_dust_htlc_exposure_msat(dust_exposure_limiting_feerate);
81438157
let on_counterparty_tx_dust_htlc_exposure_msat = htlc_stats.on_counterparty_tx_dust_exposure_msat;
81448158
if on_counterparty_tx_dust_htlc_exposure_msat > max_dust_htlc_exposure_msat {
@@ -8147,11 +8161,11 @@ impl<SP: Deref> FundedChannel<SP> where
81478161
on_counterparty_tx_dust_htlc_exposure_msat, max_dust_htlc_exposure_msat);
81488162
return Err(LocalHTLCFailureReason::DustLimitCounterparty)
81498163
}
8150-
let htlc_success_dust_limit = if self.funding.get_channel_type().supports_anchors_zero_fee_htlc_tx() {
8164+
let htlc_success_dust_limit = if funding.get_channel_type().supports_anchors_zero_fee_htlc_tx() {
81518165
0
81528166
} else {
81538167
let dust_buffer_feerate = self.context.get_dust_buffer_feerate(None) as u64;
8154-
dust_buffer_feerate * htlc_success_tx_weight(self.funding.get_channel_type()) / 1000
8168+
dust_buffer_feerate * htlc_success_tx_weight(funding.get_channel_type()) / 1000
81558169
};
81568170
let exposure_dust_limit_success_sats = htlc_success_dust_limit + self.context.holder_dust_limit_satoshis;
81578171
if msg.amount_msat / 1000 < exposure_dust_limit_success_sats {
@@ -8163,7 +8177,7 @@ impl<SP: Deref> FundedChannel<SP> where
81638177
}
81648178
}
81658179

8166-
let anchor_outputs_value_msat = if self.funding.get_channel_type().supports_anchors_zero_fee_htlc_tx() {
8180+
let anchor_outputs_value_msat = if funding.get_channel_type().supports_anchors_zero_fee_htlc_tx() {
81678181
ANCHOR_OUTPUT_VALUE_SATOSHI * 2 * 1000
81688182
} else {
81698183
0
@@ -8179,23 +8193,23 @@ impl<SP: Deref> FundedChannel<SP> where
81798193
}
81808194

81818195
let pending_value_to_self_msat =
8182-
self.funding.value_to_self_msat + htlc_stats.pending_inbound_htlcs_value_msat - removed_outbound_total_msat;
8196+
funding.value_to_self_msat + htlc_stats.pending_inbound_htlcs_value_msat - removed_outbound_total_msat;
81838197
let pending_remote_value_msat =
8184-
self.funding.get_value_satoshis() * 1000 - pending_value_to_self_msat;
8198+
funding.get_value_satoshis() * 1000 - pending_value_to_self_msat;
81858199

8186-
if !self.funding.is_outbound() {
8200+
if !funding.is_outbound() {
81878201
// `Some(())` is for the fee spike buffer we keep for the remote. This deviates from
81888202
// the spec because the fee spike buffer requirement doesn't exist on the receiver's
81898203
// side, only on the sender's. Note that with anchor outputs we are no longer as
81908204
// sensitive to fee spikes, so we need to account for them.
81918205
//
81928206
// A `None` `HTLCCandidate` is used as in this case because we're already accounting for
81938207
// the incoming HTLC as it has been fully committed by both sides.
8194-
let mut remote_fee_cost_incl_stuck_buffer_msat = self.context.next_remote_commit_tx_fee_msat(&self.funding, None, Some(()));
8195-
if !self.funding.get_channel_type().supports_anchors_zero_fee_htlc_tx() {
8208+
let mut remote_fee_cost_incl_stuck_buffer_msat = self.context.next_remote_commit_tx_fee_msat(funding, None, Some(()));
8209+
if !funding.get_channel_type().supports_anchors_zero_fee_htlc_tx() {
81968210
remote_fee_cost_incl_stuck_buffer_msat *= FEE_SPIKE_BUFFER_FEE_INCREASE_MULTIPLE;
81978211
}
8198-
if pending_remote_value_msat.saturating_sub(self.funding.holder_selected_channel_reserve_satoshis * 1000).saturating_sub(anchor_outputs_value_msat) < remote_fee_cost_incl_stuck_buffer_msat {
8212+
if pending_remote_value_msat.saturating_sub(funding.holder_selected_channel_reserve_satoshis * 1000).saturating_sub(anchor_outputs_value_msat) < remote_fee_cost_incl_stuck_buffer_msat {
81998213
log_info!(logger, "Attempting to fail HTLC due to fee spike buffer violation in channel {}. Rebalancing is required.", &self.context.channel_id());
82008214
return Err(LocalHTLCFailureReason::FeeSpikeBuffer);
82018215
}

0 commit comments

Comments
 (0)