Skip to content

(3/3) Add Failure Reason to HTLCHandlingFailed #3700

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 6 commits into
base: main
Choose a base branch
from

Conversation

carlaKC
Copy link
Contributor

@carlaKC carlaKC commented Apr 2, 2025

This PR surfaces a failure reason in HTLCHandlingFailed events. Opening up early to add some context to the prefactor PR #3601.

The heart of the PR is in d35d35f, and it could probably be reduced to just this commit. I've made some quite opinionated renaming / deprecation decisions in the other commits which aren't required for this change, but I think make for a more readable API overall - happy to drop them if it ain't broke, don't fix it applies.

Fixes: #3561
Fixes: #3541

@ldk-reviews-bot
Copy link

ldk-reviews-bot commented Apr 2, 2025

👋 I see @wpaulino was un-assigned.
If you'd like another reviewer assignemnt, please click here.

@carlaKC carlaKC changed the title Add Failure Reason to HTLCHandlingFailed (3/3) Add Failure Reason to HTLCHandlingFailed Apr 2, 2025
@carlaKC carlaKC force-pushed the 3541-api-changes branch 2 times, most recently from d049301 to 6138779 Compare April 4, 2025 20:36
Copy link

codecov bot commented Apr 11, 2025

Codecov Report

Attention: Patch coverage is 86.67546% with 101 lines in your changes missing coverage. Please review.

Project coverage is 89.09%. Comparing base (83e9e80) to head (2d39ef8).

Files with missing lines Patch % Lines
lightning/src/events/mod.rs 8.33% 33 Missing ⚠️
lightning/src/ln/onion_payment.rs 69.49% 16 Missing and 2 partials ⚠️
lightning/src/ln/onion_utils.rs 90.16% 18 Missing ⚠️
lightning/src/ln/channelmanager.rs 90.44% 16 Missing and 1 partial ⚠️
lightning/src/ln/channel.rs 77.55% 9 Missing and 2 partials ⚠️
lightning-liquidity/src/lsps2/service.rs 0.00% 2 Missing ⚠️
lightning/src/ln/functional_test_utils.rs 90.00% 0 Missing and 1 partial ⚠️
lightning/src/ln/monitor_tests.rs 83.33% 1 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main    #3700      +/-   ##
==========================================
- Coverage   89.12%   89.09%   -0.04%     
==========================================
  Files         156      156              
  Lines      123514   123670     +156     
  Branches   123514   123670     +156     
==========================================
+ Hits       110086   110186     +100     
- Misses      10749    10799      +50     
- Partials     2679     2685       +6     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@valentinewallace
Copy link
Contributor

Needs rebase 🥳

carlaKC added 6 commits April 16, 2025 11:21
HTLCDestination currently contains a combination of information about
the type of HTLC we handled to fail (a payment, a forward etc) and
error information for a select set of cases (unknown next peer, for
example).

In preparation for a refactor that will split the failure reason out
into its own enum, this commit renames HTLCDestination to
HTLCHandlingType.
Rename variant to be more specific to the current context - a
FailedPayment could be a payment that we failed to dispatch or one
that we rejected on receive.
Standardize naming within the HTLCHandlingType struct to present more
consistent API terminology.
This variant of HTLCHandlingType contains infromation about the
failure cause along with its type - as an UnknownNextPeer is just an
InvalidForward that has the failure type UnknownNextPeer.

This commit deprecates the variant's use, while still writing it to
disk to allow the option to downgrade.
This struct doesn't just contain a failure reason, it has all the data
that's used to construct our failure.
@carlaKC carlaKC marked this pull request as ready for review April 17, 2025 19:24
@joostjager joostjager requested review from joostjager and removed request for wpaulino April 17, 2025 19:53
@@ -502,7 +502,7 @@ pub enum HTLCHandlingType {
/// * The counterparty node modified the HTLC in transit,
/// * A probing attack where an intermediary node is trying to detect if we are the ultimate
/// recipient for a payment.
FailedPayment {
ReceiveFailed {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In the context of HTLCHandlingType, this would communicate that receiving the htlc failed. Previously a reference to payment was in the name, but I think that was a layering violation?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This represents all HTLCs that were intended for our node as the final node, but were rejected.

I think that Payment is a bad name here because PaymentFailed could refer to a payment you sent or one you received (it was unclear to me when I first encountered this struct). Receive is less ambiguous.

@@ -471,7 +471,7 @@ impl_writeable_tlv_based_enum_upgradable!(ClosureReason,
pub enum HTLCHandlingType {
/// We tried forwarding to a channel but failed to do so. An example of such an instance is when
/// there is insufficient capacity in our outbound channel.
NextHopChannel {
ForwardFailed {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Indeed, it shouldn't be underestimated how much naming helps with understanding code.

@@ -525,6 +525,31 @@ impl_writeable_tlv_based_enum_upgradable!(HTLCHandlingType,
},
);

/// The reason for HTLC failures in [`Event::HTLCHandlingFailed`].
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum HTLCHandlingFailureReason {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This one does remind me of HTLCFailReasonRepr. Isn't there more in that struct that might be useful to expose here such as the failure data or the hold time?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Definitely, this is essentially an external facing version of HTLCFailReasonRepr.

I don't think that we'll ever want to surface the encrypted data blob on the API, which is my main reason for not surfacing HTLCFailReasonRepr.

We're also not going to have tons and tons of fields that we need to translate from one to the other so I think it's nice to have a clean/readable api-facing struct.

@@ -466,9 +466,9 @@ impl_writeable_tlv_based_enum_upgradable!(ClosureReason,
},
);

/// Intended destination of a failed HTLC as indicated in [`Event::HTLCHandlingFailed`].
/// The type of HTLC that is being handled in [`Event::HTLCHandlingFailed`].
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"the type of htlc that is being handled", but isn't it more the outcome of the htlc forward, not saying much about the htlc itself? In particular ForwardFailed doesn't have much to do with the htlc?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"the type of htlc that is being handled", but isn't it more the outcome of the htlc forward, not saying much about the htlc itself?

Would "the handling action taken" be better? Aiming to represent what we were supposed to do to the HTLC we were handed (forward it/ receive it / we don't know because it's invalid).

Open to better naming/wording if you have it, but I do think that outcome is more associated with settle/fail so not a good fit here.

ForwardFailed doesn't have much to do with the htlc?

Do you mean InvalidForward?

@@ -480,12 +480,16 @@ pub enum HTLCHandlingType {
channel_id: ChannelId,
},
/// Scenario where we are unsure of the next node to forward the HTLC to.
///
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

typo in commit msg 'infromation'

let downgradable_type = match (handling_type, handling_failure) {
(HTLCHandlingType::InvalidForward { requested_forward_scid },
Some(HTLCHandlingFailureReason::Local { reason }))
if *reason == LocalHTLCFailureReason::UnknownNextPeer =>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I believe you can get rid of the inner if

let downgradable_type = match (handling_type, handling_failure) {
	(
		HTLCHandlingType::InvalidForward { requested_forward_scid },
		Some(HTLCHandlingFailureReason::Local {
			reason: LocalHTLCFailureReason::UnknownNextPeer,
		}),
	) => HTLCHandlingType::UnknownNextHop {
		requested_forward_scid: *requested_forward_scid,
	},
	_ => handling_type.clone(),
};

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice 🧹

// where we have a legacy event
match event {
Event::HTLCHandlingFailed { ref handling_type, .. } => {
if let HTLCHandlingType::UnknownNextHop { requested_forward_scid } = handling_type {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Similar alternative:

match event {
	Event::HTLCHandlingFailed { handling_type: HTLCHandlingType::UnknownNextHop { requested_forward_scid }, .. } => {
		event = Event::HTLCHandlingFailed {
			prev_channel_id,
			handling_type: HTLCHandlingType::InvalidForward {
				requested_forward_scid: requested_forward_scid,
			},
			handling_failure: Some(LocalHTLCFailureReason::UnknownNextPeer.into()),
		};
	}
	_ => panic!("HTLCHandlingFailed wrong type"),
}

@@ -480,12 +480,16 @@ pub enum HTLCHandlingType {
channel_id: ChannelId,
},
/// Scenario where we are unsure of the next node to forward the HTLC to.
///
/// Deprecated: will only be used in versions before LDK v0.2.0.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I still see one occurrence of HTLCHandlingType::UnknownNextHop in a macro in process_pending_htlc_forwards

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks!

#[derive(Clone)] // See Channel::revoke_and_ack for why, tl;dr: Rust bug
#[cfg_attr(test, derive(PartialEq))]
pub(super) struct HTLCFailReason(HTLCFailReasonRepr);
pub(super) struct HTLCFailurePayload(HTLCFailReasonRepr);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Embedded inside there is still a reason? Payload with a reason repr 🤔

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Rename the internal struct as well?

Open to other naming suggestions here, aim is to differentiate this from the HTLCHandlingFailureReason a bit.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Give HTLCHandlingFailed a reason of some kind Add a reason enum to HTLCDestination in some variants
4 participants