Skip to content

Commit f9c56c3

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 9d54620 commit f9c56c3

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
@@ -8134,7 +8134,21 @@ impl<SP: Deref> FundedChannel<SP> where
81348134
}
81358135

81368136
let dust_exposure_limiting_feerate = self.context.get_dust_exposure_limiting_feerate(&fee_estimator);
8137-
let htlc_stats = self.context.get_pending_htlc_stats(&self.funding, None, dust_exposure_limiting_feerate);
8137+
8138+
core::iter::once(&self.funding)
8139+
.chain(self.pending_funding.iter())
8140+
.map(|funding| self.can_accept_incoming_htlc_for_funding(funding, msg, dust_exposure_limiting_feerate, &logger))
8141+
.collect::<Result<(), LocalHTLCFailureReason>>()
8142+
}
8143+
8144+
fn can_accept_incoming_htlc_for_funding<L: Deref>(
8145+
&self, funding: &FundingScope, msg: &msgs::UpdateAddHTLC,
8146+
dust_exposure_limiting_feerate: u32, logger: &L,
8147+
) -> Result<(), LocalHTLCFailureReason>
8148+
where
8149+
L::Target: Logger,
8150+
{
8151+
let htlc_stats = self.context.get_pending_htlc_stats(funding, None, dust_exposure_limiting_feerate);
81388152
let max_dust_htlc_exposure_msat = self.context.get_max_dust_htlc_exposure_msat(dust_exposure_limiting_feerate);
81398153
let on_counterparty_tx_dust_htlc_exposure_msat = htlc_stats.on_counterparty_tx_dust_exposure_msat;
81408154
if on_counterparty_tx_dust_htlc_exposure_msat > max_dust_htlc_exposure_msat {
@@ -8143,11 +8157,11 @@ impl<SP: Deref> FundedChannel<SP> where
81438157
on_counterparty_tx_dust_htlc_exposure_msat, max_dust_htlc_exposure_msat);
81448158
return Err(LocalHTLCFailureReason::DustLimitCounterparty)
81458159
}
8146-
let htlc_success_dust_limit = if self.funding.get_channel_type().supports_anchors_zero_fee_htlc_tx() {
8160+
let htlc_success_dust_limit = if funding.get_channel_type().supports_anchors_zero_fee_htlc_tx() {
81478161
0
81488162
} else {
81498163
let dust_buffer_feerate = self.context.get_dust_buffer_feerate(None) as u64;
8150-
dust_buffer_feerate * htlc_success_tx_weight(self.funding.get_channel_type()) / 1000
8164+
dust_buffer_feerate * htlc_success_tx_weight(funding.get_channel_type()) / 1000
81518165
};
81528166
let exposure_dust_limit_success_sats = htlc_success_dust_limit + self.context.holder_dust_limit_satoshis;
81538167
if msg.amount_msat / 1000 < exposure_dust_limit_success_sats {
@@ -8159,7 +8173,7 @@ impl<SP: Deref> FundedChannel<SP> where
81598173
}
81608174
}
81618175

8162-
let anchor_outputs_value_msat = if self.funding.get_channel_type().supports_anchors_zero_fee_htlc_tx() {
8176+
let anchor_outputs_value_msat = if funding.get_channel_type().supports_anchors_zero_fee_htlc_tx() {
81638177
ANCHOR_OUTPUT_VALUE_SATOSHI * 2 * 1000
81648178
} else {
81658179
0
@@ -8175,23 +8189,23 @@ impl<SP: Deref> FundedChannel<SP> where
81758189
}
81768190

81778191
let pending_value_to_self_msat =
8178-
self.funding.value_to_self_msat + htlc_stats.pending_inbound_htlcs_value_msat - removed_outbound_total_msat;
8192+
funding.value_to_self_msat + htlc_stats.pending_inbound_htlcs_value_msat - removed_outbound_total_msat;
81798193
let pending_remote_value_msat =
8180-
self.funding.get_value_satoshis() * 1000 - pending_value_to_self_msat;
8194+
funding.get_value_satoshis() * 1000 - pending_value_to_self_msat;
81818195

8182-
if !self.funding.is_outbound() {
8196+
if !funding.is_outbound() {
81838197
// `Some(())` is for the fee spike buffer we keep for the remote. This deviates from
81848198
// the spec because the fee spike buffer requirement doesn't exist on the receiver's
81858199
// side, only on the sender's. Note that with anchor outputs we are no longer as
81868200
// sensitive to fee spikes, so we need to account for them.
81878201
//
81888202
// A `None` `HTLCCandidate` is used as in this case because we're already accounting for
81898203
// the incoming HTLC as it has been fully committed by both sides.
8190-
let mut remote_fee_cost_incl_stuck_buffer_msat = self.context.next_remote_commit_tx_fee_msat(&self.funding, None, Some(()));
8191-
if !self.funding.get_channel_type().supports_anchors_zero_fee_htlc_tx() {
8204+
let mut remote_fee_cost_incl_stuck_buffer_msat = self.context.next_remote_commit_tx_fee_msat(funding, None, Some(()));
8205+
if !funding.get_channel_type().supports_anchors_zero_fee_htlc_tx() {
81928206
remote_fee_cost_incl_stuck_buffer_msat *= FEE_SPIKE_BUFFER_FEE_INCREASE_MULTIPLE;
81938207
}
8194-
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 {
8208+
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 {
81958209
log_info!(logger, "Attempting to fail HTLC due to fee spike buffer violation in channel {}. Rebalancing is required.", &self.context.channel_id());
81968210
return Err(LocalHTLCFailureReason::FeeSpikeBuffer);
81978211
}

0 commit comments

Comments
 (0)