Skip to content

Commit 147072f

Browse files
committed
ln: surface LocalHTLCFailureReason in queue_add_htlc
1 parent de71abf commit 147072f

File tree

3 files changed

+64
-43
lines changed

3 files changed

+64
-43
lines changed

lightning/src/ln/channel.rs

+23-31
Original file line numberDiff line numberDiff line change
@@ -6066,22 +6066,14 @@ impl<SP: Deref> FundedChannel<SP> where
60666066
);
60676067
update_add_count += 1;
60686068
},
6069-
Err(e) => {
6070-
match e {
6071-
ChannelError::Ignore(ref msg) => {
6072-
log_info!(logger, "Failed to send HTLC with payment_hash {} due to {} in channel {}", &payment_hash, msg, &self.context.channel_id());
6073-
// If we fail to send here, then this HTLC should
6074-
// be failed backwards. Failing to send here
6075-
// indicates that this HTLC may keep being put back
6076-
// into the holding cell without ever being
6077-
// successfully forwarded/failed/fulfilled, causing
6078-
// our counterparty to eventually close on us.
6079-
htlcs_to_fail.push((source.clone(), *payment_hash));
6080-
},
6081-
_ => {
6082-
panic!("Got a non-IgnoreError action trying to send holding cell HTLC");
6083-
},
6084-
}
6069+
Err((_, msg)) => {
6070+
log_info!(logger, "Failed to send HTLC with payment_hash {} due to {} in channel {}", &payment_hash, msg, &self.context.channel_id());
6071+
// If we fail to send here, then this HTLC should be failed
6072+
// backwards. Failing to send here indicates that this HTLC may
6073+
// keep being put back into the holding cell without ever being
6074+
// successfully forwarded/failed/fulfilled, causing our
6075+
// counterparty to eventually close on us.
6076+
htlcs_to_fail.push((source.clone(), *payment_hash));
60856077
}
60866078
}
60876079
None
@@ -8746,22 +8738,19 @@ impl<SP: Deref> FundedChannel<SP> where
87468738
/// Queues up an outbound HTLC to send by placing it in the holding cell. You should call
87478739
/// [`Self::maybe_free_holding_cell_htlcs`] in order to actually generate and send the
87488740
/// commitment update.
8749-
///
8750-
/// `Err`s will only be [`ChannelError::Ignore`].
87518741
pub fn queue_add_htlc<F: Deref, L: Deref>(
87528742
&mut self, amount_msat: u64, payment_hash: PaymentHash, cltv_expiry: u32, source: HTLCSource,
87538743
onion_routing_packet: msgs::OnionPacket, skimmed_fee_msat: Option<u64>,
87548744
blinding_point: Option<PublicKey>, fee_estimator: &LowerBoundedFeeEstimator<F>, logger: &L
8755-
) -> Result<(), ChannelError>
8745+
) -> Result<(), (LocalHTLCFailureReason, String)>
87568746
where F::Target: FeeEstimator, L::Target: Logger
87578747
{
87588748
self
87598749
.send_htlc(amount_msat, payment_hash, cltv_expiry, source, onion_routing_packet, true,
87608750
skimmed_fee_msat, blinding_point, fee_estimator, logger)
87618751
.map(|msg_opt| assert!(msg_opt.is_none(), "We forced holding cell?"))
87628752
.map_err(|err| {
8763-
if let ChannelError::Ignore(_) = err { /* fine */ }
8764-
else { debug_assert!(false, "Queueing cannot trigger channel failure"); }
8753+
debug_assert!(err.0.is_temporary(), "Queuing HTLC should return temporary error");
87658754
err
87668755
})
87678756
}
@@ -8781,38 +8770,40 @@ impl<SP: Deref> FundedChannel<SP> where
87818770
/// You MUST call [`Self::send_commitment_no_state_update`] prior to calling any other methods
87828771
/// on this [`FundedChannel`] if `force_holding_cell` is false.
87838772
///
8784-
/// `Err`s will only be [`ChannelError::Ignore`].
8773+
/// `Err`'s will always be temporary channel failures.
87858774
fn send_htlc<F: Deref, L: Deref>(
87868775
&mut self, amount_msat: u64, payment_hash: PaymentHash, cltv_expiry: u32, source: HTLCSource,
87878776
onion_routing_packet: msgs::OnionPacket, mut force_holding_cell: bool,
87888777
skimmed_fee_msat: Option<u64>, blinding_point: Option<PublicKey>,
87898778
fee_estimator: &LowerBoundedFeeEstimator<F>, logger: &L
8790-
) -> Result<Option<msgs::UpdateAddHTLC>, ChannelError>
8779+
) -> Result<Option<msgs::UpdateAddHTLC>, (LocalHTLCFailureReason, String)>
87918780
where F::Target: FeeEstimator, L::Target: Logger
87928781
{
87938782
if !matches!(self.context.channel_state, ChannelState::ChannelReady(_)) ||
87948783
self.context.channel_state.is_local_shutdown_sent() ||
87958784
self.context.channel_state.is_remote_shutdown_sent()
87968785
{
8797-
return Err(ChannelError::Ignore("Cannot send HTLC until channel is fully established and we haven't started shutting down".to_owned()));
8786+
return Err((LocalHTLCFailureReason::ChannelNotReady,
8787+
"Cannot send HTLC until channel is fully established and we haven't started shutting down".to_owned()));
87988788
}
87998789
let channel_total_msat = self.funding.get_value_satoshis() * 1000;
88008790
if amount_msat > channel_total_msat {
8801-
return Err(ChannelError::Ignore(format!("Cannot send amount {}, because it is more than the total value of the channel {}", amount_msat, channel_total_msat)));
8791+
return Err((LocalHTLCFailureReason::AmountExceedsCapacity,
8792+
format!("Cannot send amount {}, because it is more than the total value of the channel {}", amount_msat, channel_total_msat)));
88028793
}
88038794

88048795
if amount_msat == 0 {
8805-
return Err(ChannelError::Ignore("Cannot send 0-msat HTLC".to_owned()));
8796+
return Err((LocalHTLCFailureReason::ZeroAmount, "Cannot send 0-msat HTLC".to_owned()));
88068797
}
88078798

88088799
let available_balances = self.get_available_balances(fee_estimator);
88098800
if amount_msat < available_balances.next_outbound_htlc_minimum_msat {
8810-
return Err(ChannelError::Ignore(format!("Cannot send less than our next-HTLC minimum - {} msat",
8801+
return Err((LocalHTLCFailureReason::HTLCMinimum, format!("Cannot send less than our next-HTLC minimum - {} msat",
88118802
available_balances.next_outbound_htlc_minimum_msat)));
88128803
}
88138804

88148805
if amount_msat > available_balances.next_outbound_htlc_limit_msat {
8815-
return Err(ChannelError::Ignore(format!("Cannot send more than our next-HTLC maximum - {} msat",
8806+
return Err((LocalHTLCFailureReason::HTLCMaximum, format!("Cannot send more than our next-HTLC maximum - {} msat",
88168807
available_balances.next_outbound_htlc_limit_msat)));
88178808
}
88188809

@@ -8823,7 +8814,8 @@ impl<SP: Deref> FundedChannel<SP> where
88238814
// disconnected during the time the previous hop was doing the commitment dance we may
88248815
// end up getting here after the forwarding delay. In any case, returning an
88258816
// IgnoreError will get ChannelManager to do the right thing and fail backwards now.
8826-
return Err(ChannelError::Ignore("Cannot send an HTLC while disconnected from channel counterparty".to_owned()));
8817+
return Err((LocalHTLCFailureReason::PeerOffline,
8818+
"Cannot send an HTLC while disconnected from channel counterparty".to_owned()));
88278819
}
88288820

88298821
let need_holding_cell = !self.context.channel_state.can_generate_new_commitment();
@@ -9112,8 +9104,8 @@ impl<SP: Deref> FundedChannel<SP> where
91129104
{
91139105
let send_res = self.send_htlc(amount_msat, payment_hash, cltv_expiry, source,
91149106
onion_routing_packet, false, skimmed_fee_msat, None, fee_estimator, logger);
9115-
if let Err(e) = &send_res { if let ChannelError::Ignore(_) = e {} else { debug_assert!(false, "Sending cannot trigger channel failure"); } }
9116-
match send_res? {
9107+
// All [`LocalHTLCFailureReason`] errors are temporary, so they are [`ChannelError::Ignore`].
9108+
match send_res.map_err(|(_, msg)| ChannelError::Ignore(msg))? {
91179109
Some(_) => {
91189110
let monitor_update = self.build_commitment_no_status_check(logger);
91199111
self.monitor_updating_paused(false, true, false, Vec::new(), Vec::new(), Vec::new());

lightning/src/ln/channelmanager.rs

+2-7
Original file line numberDiff line numberDiff line change
@@ -6103,22 +6103,17 @@ where
61036103
};
61046104
log_trace!(logger, "Forwarding HTLC from SCID {} with payment_hash {} and next hop SCID {} over {} channel {} with corresponding peer {}",
61056105
prev_short_channel_id, &payment_hash, short_chan_id, channel_description, optimal_channel.context.channel_id(), &counterparty_node_id);
6106-
if let Err(e) = optimal_channel.queue_add_htlc(outgoing_amt_msat,
6106+
if let Err((reason, msg)) = optimal_channel.queue_add_htlc(outgoing_amt_msat,
61076107
payment_hash, outgoing_cltv_value, htlc_source.clone(),
61086108
onion_packet.clone(), skimmed_fee_msat, next_blinding_point, &self.fee_estimator,
61096109
&&logger)
61106110
{
6111-
if let ChannelError::Ignore(msg) = e {
6112-
log_trace!(logger, "Failed to forward HTLC with payment_hash {} to peer {}: {}", &payment_hash, &counterparty_node_id, msg);
6113-
} else {
6114-
panic!("Stated return value requirements in send_htlc() were not met");
6115-
}
6111+
log_trace!(logger, "Failed to forward HTLC with payment_hash {} to peer {}: {}", &payment_hash, &counterparty_node_id, msg);
61166112

61176113
if let Some(chan) = peer_state.channel_by_id
61186114
.get_mut(&forward_chan_id)
61196115
.and_then(Channel::as_funded_mut)
61206116
{
6121-
let reason = LocalHTLCFailureReason::TemporaryChannelFailure;
61226117
let data = self.get_htlc_inbound_temp_fail_data(reason);
61236118
failed_forwards.push((htlc_source, payment_hash,
61246119
HTLCFailReason::reason(reason, data),

lightning/src/ln/onion_utils.rs

+39-5
Original file line numberDiff line numberDiff line change
@@ -1599,7 +1599,26 @@ pub enum LocalHTLCFailureReason {
15991599
/// The HTLC was failed back because its expiry height was reached and funds were timed out
16001600
/// on chain.
16011601
OnChainTimeout,
1602-
/// UnknownFailureCode represents BOLT04 failure codes that we are not familiar with. We will
1602+
/// The HTLC was failed because its amount is greater than the capacity of the channel.
1603+
AmountExceedsCapacity,
1604+
/// The HTLC was failed because zero amount HTLCs are not allowed.
1605+
ZeroAmount,
1606+
/// The HTLC was failed because its amount is less than the smallest HTLC that the channel
1607+
/// can currently accept.
1608+
///
1609+
/// This may occur because the HTLC is smaller than the counterparty's advertised minimum
1610+
/// accepted HTLC size, or if we have reached our maximum total dust HTLC exposure.
1611+
HTLCMinimum,
1612+
/// The HTLC was failed because its amount is more than then largest HTLC that the channel
1613+
/// can currently accept.
1614+
///
1615+
/// This may occur because the outbound channel has insufficient liquidity to forward the HTLC,
1616+
/// we have reached the counterparty's in-flight limits, or the HTLC exceeds our advertised
1617+
/// maximum accepted HTLC size.
1618+
HTLCMaximum,
1619+
/// The HTLC was failed because our remote peer is offline.
1620+
PeerOffline,
1621+
/// UnknownFailureCode represents BOLT04 failure codes that we are not familiar with. We will
16031622
/// encounter this if:
16041623
/// - A peer sends us a new failure code that LDK has not yet been upgraded to understand.
16051624
/// - We read a deprecated failure code from disk that LDK no longer uses.
@@ -1625,8 +1644,13 @@ impl LocalHTLCFailureReason {
16251644
| Self::DustLimitHolder
16261645
| Self::DustLimitCounterparty
16271646
| Self::FeeSpikeBuffer
1628-
| Self::ChannelNotReady => UPDATE | 7,
1629-
Self::PermanentChannelFailure | Self::OnChainTimeout | Self::ChannelClosed => PERM | 8,
1647+
| Self::ChannelNotReady
1648+
| Self::AmountExceedsCapacity
1649+
| Self::ZeroAmount
1650+
| Self::HTLCMinimum
1651+
| Self::HTLCMaximum
1652+
| Self::PeerOffline => UPDATE | 7,
1653+
Self::PermanentChannelFailure | Self::ChannelClosed | Self::OnChainTimeout => PERM | 8,
16301654
Self::RequiredChannelFeature => PERM | 9,
16311655
Self::UnknownNextPeer
16321656
| Self::PrivateChannelForward
@@ -1752,7 +1776,12 @@ impl_writeable_tlv_based_enum!(LocalHTLCFailureReason,
17521776
(73, ChannelClosed) => {},
17531777
(75, UnknownFailureCode) => {
17541778
(0, code, required),
1755-
}
1779+
},
1780+
(77, AmountExceedsCapacity) => {},
1781+
(79, ZeroAmount) => {},
1782+
(81, HTLCMinimum) => {},
1783+
(83, HTLCMaximum) => {},
1784+
(85, PeerOffline) => {},
17561785
);
17571786

17581787
#[derive(Clone)] // See Channel::revoke_and_ack for why, tl;dr: Rust bug
@@ -1848,7 +1877,12 @@ impl HTLCFailReason {
18481877
| LocalHTLCFailureReason::DustLimitHolder
18491878
| LocalHTLCFailureReason::DustLimitCounterparty
18501879
| LocalHTLCFailureReason::FeeSpikeBuffer
1851-
| LocalHTLCFailureReason::ChannelNotReady => {
1880+
| LocalHTLCFailureReason::ChannelNotReady
1881+
| LocalHTLCFailureReason::AmountExceedsCapacity
1882+
| LocalHTLCFailureReason::ZeroAmount
1883+
| LocalHTLCFailureReason::HTLCMinimum
1884+
| LocalHTLCFailureReason::HTLCMaximum
1885+
| LocalHTLCFailureReason::PeerOffline => {
18521886
debug_assert_eq!(
18531887
data.len() - 2,
18541888
u16::from_be_bytes(data[0..2].try_into().unwrap()) as usize

0 commit comments

Comments
 (0)