Skip to content

Commit 26326ea

Browse files
committed
lightning: surface failure reason for HTLCDestination::NextHopChannel
1 parent 1edae58 commit 26326ea

File tree

2 files changed

+73
-32
lines changed

2 files changed

+73
-32
lines changed

lightning/src/events/mod.rs

+30
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ use crate::blinded_path::payment::{Bolt12OfferContext, Bolt12RefundContext, Paym
2323
use crate::chain::transaction;
2424
use crate::ln::channelmanager::{InterceptId, PaymentId, RecipientOnionFields};
2525
use crate::ln::channel::FUNDING_CONF_DEADLINE_BLOCKS;
26+
use crate::ln::onion_utils::{LocalHTLCFailureReason, HTLCFailureDetails};
2627
use crate::types::features::ChannelTypeFeatures;
2728
use crate::ln::msgs;
2829
use crate::ln::types::ChannelId;
@@ -465,6 +466,31 @@ impl_writeable_tlv_based_enum_upgradable!(ClosureReason,
465466
},
466467
);
467468

469+
/// The reason for HTLC failures in [`HTLCDestination`].
470+
#[derive(Clone, Debug, PartialEq, Eq)]
471+
pub enum HTLCDestinationFailure {
472+
/// The forwarded HTLC was failed back by the downstream node with an encrypted error reason.
473+
Downstream,
474+
/// The HTLC was failed locally by our node.
475+
Local{
476+
/// The reason that our node chose to fail the HTLC.
477+
reason: HTLCFailureDetails
478+
},
479+
}
480+
481+
impl From<LocalHTLCFailureReason> for HTLCDestinationFailure {
482+
fn from(reason: LocalHTLCFailureReason) -> Self {
483+
Self::Local { reason: reason.into() }
484+
}
485+
}
486+
487+
impl_writeable_tlv_based_enum!(HTLCDestinationFailure,
488+
(0, Downstream) => {},
489+
(1, Local) => {
490+
(0, reason, required),
491+
},
492+
);
493+
468494
/// Intended destination of a failed HTLC as indicated in [`Event::HTLCHandlingFailed`].
469495
#[derive(Clone, Debug, PartialEq, Eq)]
470496
pub enum HTLCDestination {
@@ -477,6 +503,9 @@ pub enum HTLCDestination {
477503
node_id: Option<PublicKey>,
478504
/// The outgoing `channel_id` between us and the next node.
479505
channel_id: ChannelId,
506+
/// The reason that the HTLC forward was failed. For backwards compatibility, this field is
507+
/// marked as optional, versions prior to 0.1.1 will set this value to None.
508+
reason: Option<HTLCDestinationFailure>,
480509
},
481510
/// Scenario where we are unsure of the next node to forward the HTLC to.
482511
UnknownNextHop {
@@ -510,6 +539,7 @@ pub enum HTLCDestination {
510539
impl_writeable_tlv_based_enum_upgradable!(HTLCDestination,
511540
(0, NextHopChannel) => {
512541
(0, node_id, required),
542+
(1, reason, option),
513543
(2, channel_id, required),
514544
},
515545
(1, InvalidForward) => {

lightning/src/ln/channelmanager.rs

+43-32
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ use crate::chain::{Confirm, ChannelMonitorUpdateStatus, Watch, BestBlock};
4444
use crate::chain::chaininterface::{BroadcasterInterface, ConfirmationTarget, FeeEstimator, LowerBoundedFeeEstimator};
4545
use crate::chain::channelmonitor::{Balance, ChannelMonitor, ChannelMonitorUpdate, WithChannelMonitor, ChannelMonitorUpdateStep, HTLC_FAIL_BACK_BUFFER, MAX_BLOCKS_FOR_CONF, CLTV_CLAIM_BUFFER, LATENCY_GRACE_PERIOD_BLOCKS, ANTI_REORG_DELAY, MonitorEvent};
4646
use crate::chain::transaction::{OutPoint, TransactionData};
47-
use crate::events::{self, Event, EventHandler, EventsProvider, InboundChannelFunds, ClosureReason, HTLCDestination, PaymentFailureReason, ReplayEvent};
47+
use crate::events::{self, Event, EventHandler, EventsProvider, InboundChannelFunds, ClosureReason, HTLCDestination, PaymentFailureReason, ReplayEvent, HTLCDestinationFailure};
4848
// Since this struct is returned in `list_channels` methods, expose it here in case users want to
4949
// construct one themselves.
5050
use crate::ln::inbound_payment;
@@ -3292,7 +3292,7 @@ macro_rules! handle_monitor_update_completion {
32923292
}
32933293
$self.finalize_claims(updates.finalized_claimed_htlcs);
32943294
for failure in updates.failed_htlcs.drain(..) {
3295-
let receiver = HTLCDestination::NextHopChannel { node_id: Some(counterparty_node_id), channel_id };
3295+
let receiver = HTLCDestination::NextHopChannel { node_id: Some(counterparty_node_id), channel_id, reason: Some(HTLCDestinationFailure::Downstream) };
32963296
$self.fail_htlc_backwards_internal(&failure.0, &failure.1, &failure.2, receiver);
32973297
}
32983298
} }
@@ -3910,8 +3910,9 @@ where
39103910
}
39113911

39123912
for htlc_source in failed_htlcs.drain(..) {
3913-
let reason = HTLCFailReason::from_failure_code(0x4000 | 8);
3914-
let receiver = HTLCDestination::NextHopChannel { node_id: Some(*counterparty_node_id), channel_id: *channel_id };
3913+
let details = LocalHTLCFailureReason::ChannelClosed;
3914+
let reason = HTLCFailReason::from_failure_code(details.failure_code());
3915+
let receiver = HTLCDestination::NextHopChannel { node_id: Some(*counterparty_node_id), channel_id: *channel_id, reason: Some(details.into()) };
39153916
self.fail_htlc_backwards_internal(&htlc_source.0, &htlc_source.1, &reason, receiver);
39163917
}
39173918

@@ -4033,8 +4034,9 @@ where
40334034
shutdown_res.closure_reason, shutdown_res.dropped_outbound_htlcs.len());
40344035
for htlc_source in shutdown_res.dropped_outbound_htlcs.drain(..) {
40354036
let (source, payment_hash, counterparty_node_id, channel_id) = htlc_source;
4036-
let reason = HTLCFailReason::from_failure_code(0x4000 | 8);
4037-
let receiver = HTLCDestination::NextHopChannel { node_id: Some(counterparty_node_id), channel_id };
4037+
let details = LocalHTLCFailureReason::ChannelClosed;
4038+
let reason = HTLCFailReason::from_failure_code(details.failure_code());
4039+
let receiver = HTLCDestination::NextHopChannel { node_id: Some(counterparty_node_id), channel_id, reason: Some(details.into()) };
40384040
self.fail_htlc_backwards_internal(&source, &payment_hash, &reason, receiver);
40394041
}
40404042
if let Some((_, funding_txo, _channel_id, monitor_update)) = shutdown_res.monitor_update {
@@ -5754,13 +5756,14 @@ where
57545756
let mut decode_update_add_htlcs = new_hash_map();
57555757
mem::swap(&mut decode_update_add_htlcs, &mut self.decode_update_add_htlcs.lock().unwrap());
57565758

5757-
let get_failed_htlc_destination = |outgoing_scid_opt: Option<u64>, payment_hash: PaymentHash| {
5759+
let get_failed_htlc_destination = |outgoing_scid_opt: Option<u64>, payment_hash: PaymentHash, reason: HTLCFailureDetails| {
57585760
if let Some(outgoing_scid) = outgoing_scid_opt {
57595761
match self.short_to_chan_info.read().unwrap().get(&outgoing_scid) {
57605762
Some((outgoing_counterparty_node_id, outgoing_channel_id)) =>
57615763
HTLCDestination::NextHopChannel {
57625764
node_id: Some(*outgoing_counterparty_node_id),
57635765
channel_id: *outgoing_channel_id,
5766+
reason: Some(HTLCDestinationFailure::Local { reason }),
57645767
},
57655768
None => HTLCDestination::UnknownNextHop {
57665769
requested_forward_scid: outgoing_scid,
@@ -5822,10 +5825,10 @@ where
58225825
Some(Ok(_)) => {},
58235826
Some(Err((err, reason))) => {
58245827
let htlc_fail = self.htlc_failure_from_update_add_err(
5825-
&update_add_htlc, &incoming_counterparty_node_id, err, reason,
5828+
&update_add_htlc, &incoming_counterparty_node_id, err, reason.clone(),
58265829
is_intro_node_blinded_forward, &shared_secret,
58275830
);
5828-
let htlc_destination = get_failed_htlc_destination(outgoing_scid_opt, update_add_htlc.payment_hash);
5831+
let htlc_destination = get_failed_htlc_destination(outgoing_scid_opt, update_add_htlc.payment_hash, reason);
58295832
htlc_fails.push((htlc_fail, htlc_destination));
58305833
continue;
58315834
},
@@ -5839,10 +5842,10 @@ where
58395842
&update_add_htlc, next_packet_details
58405843
) {
58415844
let htlc_fail = self.htlc_failure_from_update_add_err(
5842-
&update_add_htlc, &incoming_counterparty_node_id, err, reason,
5845+
&update_add_htlc, &incoming_counterparty_node_id, err, reason.clone(),
58435846
is_intro_node_blinded_forward, &shared_secret,
58445847
);
5845-
let htlc_destination = get_failed_htlc_destination(outgoing_scid_opt, update_add_htlc.payment_hash);
5848+
let htlc_destination = get_failed_htlc_destination(outgoing_scid_opt, update_add_htlc.payment_hash, reason);
58465849
htlc_fails.push((htlc_fail, htlc_destination));
58475850
continue;
58485851
}
@@ -5854,7 +5857,7 @@ where
58545857
) {
58555858
Ok(info) => htlc_forwards.push((info, update_add_htlc.htlc_id)),
58565859
Err(inbound_err) => {
5857-
let htlc_destination = get_failed_htlc_destination(outgoing_scid_opt, update_add_htlc.payment_hash);
5860+
let htlc_destination = get_failed_htlc_destination(outgoing_scid_opt, update_add_htlc.payment_hash, inbound_err.reason.clone());
58585861
htlc_fails.push((self.construct_pending_htlc_fail_msg(&update_add_htlc, &incoming_counterparty_node_id, shared_secret, inbound_err), htlc_destination));
58595862
},
58605863
}
@@ -6128,11 +6131,11 @@ where
61286131
.get_mut(&forward_chan_id)
61296132
.and_then(Channel::as_funded_mut)
61306133
{
6131-
let failure_code = 0x1000|7;
6132-
let data = self.get_htlc_inbound_temp_fail_data(failure_code);
6134+
let details = LocalHTLCFailureReason::ChannelNotReady;
6135+
let data = self.get_htlc_inbound_temp_fail_data(details.failure_code());
61336136
failed_forwards.push((htlc_source, payment_hash,
6134-
HTLCFailReason::reason(failure_code, data),
6135-
HTLCDestination::NextHopChannel { node_id: Some(chan.context.get_counterparty_node_id()), channel_id: forward_chan_id }
6137+
HTLCFailReason::reason(details.failure_code(), data),
6138+
HTLCDestination::NextHopChannel { node_id: Some(chan.context.get_counterparty_node_id()), channel_id: forward_chan_id, reason: Some(details.into()) }
61366139
));
61376140
} else {
61386141
forwarding_channel_not_found!(core::iter::once(forward_info).chain(draining_pending_forwards));
@@ -6977,17 +6980,21 @@ where
69776980
} else {
69786981
// We shouldn't be trying to fail holding cell HTLCs on an unfunded channel.
69796982
debug_assert!(false);
6980-
((0x4000|10).into(), Vec::new())
6983+
(LocalHTLCFailureReason::ChannelNotReady.into(), Vec::new())
69816984
}
69826985
},
6983-
hash_map::Entry::Vacant(_) => ((0x4000|10).into(), Vec::new())
6986+
hash_map::Entry::Vacant(_) => (LocalHTLCFailureReason::UnknownNextPeer.into(), Vec::new())
69846987
}
6985-
} else { ((0x4000|10).into(), Vec::new()) }
6988+
} else { (LocalHTLCFailureReason::UnknownNextPeer.into(), Vec::new()) }
69866989
};
69876990

69886991
for (htlc_src, payment_hash) in htlcs_to_fail.drain(..) {
6989-
let reason = HTLCFailReason::reason(failure_reason.failure_code(), onion_failure_data.clone());
6990-
let receiver = HTLCDestination::NextHopChannel { node_id: Some(counterparty_node_id.clone()), channel_id };
6992+
let reason = HTLCFailReason::reason(failure_reason.clone().failure_code(), onion_failure_data.clone());
6993+
let receiver = HTLCDestination::NextHopChannel {
6994+
node_id: Some(counterparty_node_id.clone()),
6995+
channel_id,
6996+
reason: Some(HTLCDestinationFailure::Local{ reason: failure_reason.clone().into() }),
6997+
};
69916998
self.fail_htlc_backwards_internal(&htlc_src, &payment_hash, &reason, receiver);
69926999
}
69937000
}
@@ -8772,8 +8779,9 @@ This indicates a bug inside LDK. Please report this error at https://github.com/
87728779
}
87738780
}
87748781
for htlc_source in dropped_htlcs.drain(..) {
8775-
let receiver = HTLCDestination::NextHopChannel { node_id: Some(counterparty_node_id.clone()), channel_id: msg.channel_id };
8776-
let reason = HTLCFailReason::from_failure_code(0x4000 | 8);
8782+
let details = LocalHTLCFailureReason::ShutdownSent;
8783+
let reason = HTLCFailReason::from_failure_code(details.failure_code());
8784+
let receiver = HTLCDestination::NextHopChannel { node_id: Some(counterparty_node_id.clone()), channel_id: msg.channel_id, reason: Some(details.into()) };
87778785
self.fail_htlc_backwards_internal(&htlc_source.0, &htlc_source.1, &reason, receiver);
87788786
}
87798787
if let Some(shutdown_res) = finish_shutdown {
@@ -9598,8 +9606,9 @@ This indicates a bug inside LDK. Please report this error at https://github.com/
95989606
);
95999607
} else {
96009608
log_trace!(logger, "Failing HTLC with hash {} from our monitor", &htlc_update.payment_hash);
9601-
let receiver = HTLCDestination::NextHopChannel { node_id: Some(counterparty_node_id), channel_id };
9602-
let reason = HTLCFailReason::from_failure_code(0x4000 | 8);
9609+
let details = LocalHTLCFailureReason::ChannelClosed;
9610+
let reason = HTLCFailReason::from_failure_code(details.failure_code());
9611+
let receiver = HTLCDestination::NextHopChannel { node_id: Some(counterparty_node_id), channel_id, reason: Some(details.into())};
96039612
self.fail_htlc_backwards_internal(&htlc_update.source, &htlc_update.payment_hash, &reason, receiver);
96049613
}
96059614
},
@@ -11689,10 +11698,10 @@ where
1168911698
let res = f(funded_channel);
1169011699
if let Ok((channel_ready_opt, mut timed_out_pending_htlcs, announcement_sigs)) = res {
1169111700
for (source, payment_hash) in timed_out_pending_htlcs.drain(..) {
11692-
let failure_code = 0x1000|14; /* expiry_too_soon */
11693-
let data = self.get_htlc_inbound_temp_fail_data(failure_code);
11694-
timed_out_htlcs.push((source, payment_hash, HTLCFailReason::reason(failure_code, data),
11695-
HTLCDestination::NextHopChannel { node_id: Some(funded_channel.context.get_counterparty_node_id()), channel_id: funded_channel.context.channel_id() }));
11701+
let details = LocalHTLCFailureReason::ExpiryTooSoon;
11702+
let data = self.get_htlc_inbound_temp_fail_data(details.failure_code());
11703+
timed_out_htlcs.push((source, payment_hash, HTLCFailReason::reason(details.failure_code(), data),
11704+
HTLCDestination::NextHopChannel { node_id: Some(funded_channel.context.get_counterparty_node_id()), channel_id: funded_channel.context.channel_id(), reason: Some(details.into()) }));
1169611705
}
1169711706
let logger = WithChannelContext::from(&self.logger, &funded_channel.context, None);
1169811707
if let Some(channel_ready) = channel_ready_opt {
@@ -11814,8 +11823,9 @@ where
1181411823
let mut htlc_msat_height_data = htlc.value.to_be_bytes().to_vec();
1181511824
htlc_msat_height_data.extend_from_slice(&height.to_be_bytes());
1181611825

11826+
let details = LocalHTLCFailureReason::FailBackBuffer;
1181711827
timed_out_htlcs.push((HTLCSource::PreviousHopData(htlc.prev_hop.clone()), payment_hash.clone(),
11818-
HTLCFailReason::reason(0x4000 | 15, htlc_msat_height_data),
11828+
HTLCFailReason::reason(details.failure_code(), htlc_msat_height_data),
1181911829
HTLCDestination::FailedPayment { payment_hash: payment_hash.clone() }));
1182011830
false
1182111831
} else { true }
@@ -14917,8 +14927,9 @@ where
1491714927

1491814928
for htlc_source in failed_htlcs.drain(..) {
1491914929
let (source, payment_hash, counterparty_node_id, channel_id) = htlc_source;
14920-
let receiver = HTLCDestination::NextHopChannel { node_id: Some(counterparty_node_id), channel_id };
14921-
let reason = HTLCFailReason::from_failure_code(0x4000 | 8);
14930+
let details = LocalHTLCFailureReason::ChannelClosed;
14931+
let reason = HTLCFailReason::from_failure_code(details.failure_code());
14932+
let receiver = HTLCDestination::NextHopChannel { node_id: Some(counterparty_node_id), channel_id, reason: Some(details.into()) };
1492214933
channel_manager.fail_htlc_backwards_internal(&source, &payment_hash, &reason, receiver);
1492314934
}
1492414935

0 commit comments

Comments
 (0)