@@ -4411,84 +4411,70 @@ where
44114411
44124412 #[rustfmt::skip]
44134413 fn can_accept_incoming_htlc<L: Deref>(
4414- &self, funding: &FundingScope, msg: &msgs::UpdateAddHTLC,
4414+ &self, funding: &FundingScope,
44154415 dust_exposure_limiting_feerate: Option<u32>, logger: &L,
44164416 ) -> Result<(), LocalHTLCFailureReason>
44174417 where
44184418 L::Target: Logger,
44194419 {
4420- let htlc_stats = self.get_pending_htlc_stats(funding, None, dust_exposure_limiting_feerate);
4420+ // `Some(())` is for the fee spike buffer we keep for the remote if the channel is not zero fee. This deviates from the spec because the fee spike buffer requirement
4421+ // doesn't exist on the receiver's side, only on the sender's. Note that with anchor
4422+ // outputs we are no longer as sensitive to fee spikes, so we need to account for them.
4423+ //
4424+ // A `None` `HTLCCandidate` is used as in this case because we're already accounting for
4425+ // the incoming HTLC as it has been fully committed by both sides.
4426+ let fee_spike_buffer_htlc = if funding.get_channel_type().supports_anchor_zero_fee_commitments() {
4427+ 0
4428+ } else {
4429+ 1
4430+ };
4431+ let next_commitment_htlcs = self.next_commitment_htlcs(None);
4432+ let value_to_self_msat = self.get_next_commitment_value_to_self_msat(funding);
4433+ let next_commitment_stats = SpecTxBuilder {}.get_builder_stats(funding.is_outbound(), funding.get_value_satoshis(), value_to_self_msat, &next_commitment_htlcs, fee_spike_buffer_htlc, self.feerate_per_kw, dust_exposure_limiting_feerate, funding.get_channel_type(), self.holder_dust_limit_satoshis, self.counterparty_dust_limit_satoshis);
4434+
44214435 let max_dust_htlc_exposure_msat = self.get_max_dust_htlc_exposure_msat(dust_exposure_limiting_feerate);
4422- let on_counterparty_tx_dust_htlc_exposure_msat = htlc_stats.on_counterparty_tx_dust_exposure_msat;
4423- if on_counterparty_tx_dust_htlc_exposure_msat > max_dust_htlc_exposure_msat {
4436+ if next_commitment_stats.on_counterparty_tx_dust_exposure_msat > max_dust_htlc_exposure_msat {
44244437 // Note that the total dust exposure includes both the dust HTLCs and the excess mining fees of the counterparty commitment transaction
44254438 log_info!(logger, "Cannot accept value that would put our total dust exposure at {} over the limit {} on counterparty commitment tx",
4426- on_counterparty_tx_dust_htlc_exposure_msat , max_dust_htlc_exposure_msat);
4439+ next_commitment_stats.on_counterparty_tx_dust_exposure_msat , max_dust_htlc_exposure_msat);
44274440 return Err(LocalHTLCFailureReason::DustLimitCounterparty)
44284441 }
4429- let dust_buffer_feerate = self.get_dust_buffer_feerate(None);
4430- let (htlc_success_tx_fee_sat, _) = second_stage_tx_fees_sat(
4431- &funding.get_channel_type(), dust_buffer_feerate,
4432- );
4433- let exposure_dust_limit_success_sats = htlc_success_tx_fee_sat + self.holder_dust_limit_satoshis;
4434- if msg.amount_msat / 1000 < exposure_dust_limit_success_sats {
4435- let on_holder_tx_dust_htlc_exposure_msat = htlc_stats.on_holder_tx_dust_exposure_msat;
4436- if on_holder_tx_dust_htlc_exposure_msat > max_dust_htlc_exposure_msat {
4437- log_info!(logger, "Cannot accept value that would put our exposure to dust HTLCs at {} over the limit {} on holder commitment tx",
4438- on_holder_tx_dust_htlc_exposure_msat, max_dust_htlc_exposure_msat);
4439- return Err(LocalHTLCFailureReason::DustLimitHolder)
4440- }
4442+ if next_commitment_stats.on_holder_tx_dust_exposure_msat > max_dust_htlc_exposure_msat {
4443+ // Note: We now always check holder dust exposure, whereas we previously would only
4444+ // do it if the incoming HTLC was dust on our own commitment transaction
4445+ log_info!(logger, "Cannot accept value that would put our exposure to dust HTLCs at {} over the limit {} on holder commitment tx",
4446+ next_commitment_stats.on_holder_tx_dust_exposure_msat, max_dust_htlc_exposure_msat);
4447+ return Err(LocalHTLCFailureReason::DustLimitHolder)
44414448 }
44424449
44434450 if !funding.is_outbound() {
4444- let removed_outbound_total_msat: u64 = self.pending_outbound_htlcs
4445- .iter()
4446- .filter_map(|htlc| {
4447- matches!(
4448- htlc.state,
4449- OutboundHTLCState::AwaitingRemoteRevokeToRemove(OutboundHTLCOutcome::Success(_, _))
4450- | OutboundHTLCState::AwaitingRemovedRemoteRevoke(OutboundHTLCOutcome::Success(_, _))
4451- )
4452- .then_some(htlc.amount_msat)
4453- })
4454- .sum();
4455- let pending_value_to_self_msat =
4456- funding.value_to_self_msat + htlc_stats.pending_inbound_htlcs_value_msat - removed_outbound_total_msat;
4457- let pending_remote_value_msat =
4458- funding.get_value_satoshis() * 1000 - pending_value_to_self_msat;
4459- // Subtract any non-HTLC outputs from the local and remote balances
4460- let (_, remote_balance_before_fee_msat) = SpecTxBuilder {}.subtract_non_htlc_outputs(
4461- funding.is_outbound(),
4462- pending_value_to_self_msat,
4463- pending_remote_value_msat,
4464- funding.get_channel_type()
4465- );
4466-
4467- // `Some(())` is for the fee spike buffer we keep for the remote if the channel is
4468- // not zero fee. This deviates from the spec because the fee spike buffer requirement
4469- // doesn't exist on the receiver's side, only on the sender's. Note that with anchor
4470- // outputs we are no longer as sensitive to fee spikes, so we need to account for them.
4471- //
4472- // A `None` `HTLCCandidate` is used as in this case because we're already accounting for
4473- // the incoming HTLC as it has been fully committed by both sides.
4474- let fee_spike_buffer_htlc = if funding.get_channel_type().supports_anchor_zero_fee_commitments() {
4475- None
4476- } else {
4477- Some(())
4478- };
4479-
4480- let mut remote_fee_cost_incl_stuck_buffer_msat = self.next_remote_commit_tx_fee_msat(
4481- funding, None, fee_spike_buffer_htlc,
4482- );
4451+ let mut remote_fee_cost_incl_stuck_buffer_msat = next_commitment_stats.counterparty_commit_tx_fee_sat * 1000;
44834452 if !funding.get_channel_type().supports_anchors_zero_fee_htlc_tx() {
44844453 remote_fee_cost_incl_stuck_buffer_msat *= FEE_SPIKE_BUFFER_FEE_INCREASE_MULTIPLE;
44854454 }
4455+ let remote_balance_before_fee_msat = next_commitment_stats.counterparty_balance_msat.unwrap_or(0);
44864456 if remote_balance_before_fee_msat.saturating_sub(funding.holder_selected_channel_reserve_satoshis * 1000) < remote_fee_cost_incl_stuck_buffer_msat {
44874457 log_info!(logger, "Attempting to fail HTLC due to fee spike buffer violation in channel {}. Rebalancing is required.", &self.channel_id());
44884458 return Err(LocalHTLCFailureReason::FeeSpikeBuffer);
44894459 }
44904460 }
44914461
4462+ #[cfg(any(test, fuzzing))]
4463+ {
4464+ let next_commitment_stats = if fee_spike_buffer_htlc == 1 {
4465+ SpecTxBuilder {}.get_builder_stats(funding.is_outbound(), funding.get_value_satoshis(), value_to_self_msat, &next_commitment_htlcs, 0, self.feerate_per_kw, dust_exposure_limiting_feerate, funding.get_channel_type(), self.holder_dust_limit_satoshis, self.counterparty_dust_limit_satoshis)
4466+ } else {
4467+ next_commitment_stats
4468+ };
4469+ let mut predicted_htlcs = next_commitment_htlcs;
4470+ predicted_htlcs.sort_unstable();
4471+ *funding.next_remote_fee.lock().unwrap() = PredictedNextFee {
4472+ predicted_feerate: self.feerate_per_kw,
4473+ predicted_htlcs,
4474+ predicted_fee_sat: next_commitment_stats.counterparty_commit_tx_fee_sat,
4475+ };
4476+ }
4477+
44924478 Ok(())
44934479 }
44944480
@@ -9451,7 +9437,7 @@ where
94519437 /// this function determines whether to fail the HTLC, or forward / claim it.
94529438 #[rustfmt::skip]
94539439 pub fn can_accept_incoming_htlc<F: Deref, L: Deref>(
9454- &self, msg: &msgs::UpdateAddHTLC, fee_estimator: &LowerBoundedFeeEstimator<F>, logger: L
9440+ &self, fee_estimator: &LowerBoundedFeeEstimator<F>, logger: L
94559441 ) -> Result<(), LocalHTLCFailureReason>
94569442 where
94579443 F::Target: FeeEstimator,
@@ -9467,7 +9453,7 @@ where
94679453
94689454 core::iter::once(&self.funding)
94699455 .chain(self.pending_funding.iter())
9470- .try_for_each(|funding| self.context.can_accept_incoming_htlc(funding, msg, dust_exposure_limiting_feerate, &logger))
9456+ .try_for_each(|funding| self.context.can_accept_incoming_htlc(funding, dust_exposure_limiting_feerate, &logger))
94719457 }
94729458
94739459 pub fn get_cur_holder_commitment_transaction_number(&self) -> u64 {
0 commit comments