Skip to content

Conversation

a-mpch
Copy link
Contributor

@a-mpch a-mpch commented Aug 2, 2025

This PR is part of 1/N PRs in order to split up #3976

This commit checks amount and CLTV of the trampoline to the outer hop. If exceeds limitations we fail the forward using a InboundHTLCErr with specified local reason.

@ldk-reviews-bot
Copy link

ldk-reviews-bot commented Aug 2, 2025

👋 Thanks for assigning @valentinewallace as a reviewer!
I'll wait for their review and will help manage the review process.
Once they submit their review, I'll check if a second reviewer would be helpful.

Copy link

codecov bot commented Aug 2, 2025

Codecov Report

❌ Patch coverage is 91.91564% with 46 lines in your changes missing coverage. Please review.
✅ Project coverage is 88.72%. Comparing base (1c36624) to head (cfbade2).
⚠️ Report is 23 commits behind head on main.

Files with missing lines Patch % Lines
lightning/src/ln/onion_payment.rs 59.67% 25 Missing ⚠️
lightning/src/ln/blinded_payment_tests.rs 96.76% 13 Missing and 2 partials ⚠️
lightning/src/ln/onion_utils.rs 86.36% 6 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main    #3983      +/-   ##
==========================================
- Coverage   88.78%   88.72%   -0.06%     
==========================================
  Files         176      176              
  Lines      128139   129234    +1095     
  Branches   128139   129234    +1095     
==========================================
+ Hits       113768   114663     +895     
- Misses      11803    11975     +172     
- Partials     2568     2596      +28     
Flag Coverage Δ
fuzzing 21.91% <0.00%> (-0.01%) ⬇️
tests 88.55% <91.91%> (-0.06%) ⬇️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ 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.

@ldk-reviews-bot
Copy link

🔔 1st Reminder

Hey @tankyleo! This PR has been waiting for your review.
Please take a look when you have a chance. If you're unable to review, please let us know so we can find another reviewer.

Copy link
Contributor

@tankyleo tankyleo left a comment

Choose a reason for hiding this comment

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

This is a more mechanical review as I am not familiar with this part of the codebase :)

@ldk-reviews-bot
Copy link

👋 The first review has been submitted!

Do you think this PR is ready for a second reviewer? If so, click here to assign a second reviewer.

@tankyleo
Copy link
Contributor

tankyleo commented Aug 6, 2025

Also when I remove everything but the test code, the test does not fail - is that intentional ? I have not reviewed the test

@a-mpch
Copy link
Contributor Author

a-mpch commented Aug 6, 2025

thanks @tankyleo !

Also when I remove everything but the test code, the test does not fail - is that intentional ? I have not reviewed the test

Double checked the tests and yes, this happens because when receiving a trampoline it behaves exactly as receiving a non-trampoline payment. Having the same failure scenario.
I figured out that for this PR it's ok to have one test that checks for the CLTV constraint and later when having the capacity of forwarding we can test the constraint when forwarding related to the amt.

I added fixups for each of your comments and rebased in top of main

@a-mpch a-mpch force-pushed the 2025-08-enforce-trampoline-constraint branch from 4deaa3e to d37d6d8 Compare August 6, 2025 20:35
@tankyleo
Copy link
Contributor

tankyleo commented Aug 7, 2025

Also go ahead and squash next time you push, and expand the commit message to describe in detail what you are doing, including in the tests :) Would help me out with reviewing the code too thank you !

@a-mpch a-mpch force-pushed the 2025-08-enforce-trampoline-constraint branch from d37d6d8 to 3515844 Compare August 7, 2025 22:01
@a-mpch
Copy link
Contributor Author

a-mpch commented Aug 7, 2025

@tankyleo Reading the initial PR needed a lot of explanation work 😅, thanks for the detailed review!

All your comments should have been addressed and rebased and squashed.

note that linting CI seems to be a problem on one of the new commits after rebase

@a-mpch a-mpch requested a review from tankyleo August 11, 2025 15:18
Copy link
Contributor

@tankyleo tankyleo left a comment

Choose a reason for hiding this comment

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

Another round of review thank you !

Also proofread the commit message, there are a few mistakes in there :)

@a-mpch a-mpch force-pushed the 2025-08-enforce-trampoline-constraint branch from 3515844 to 5c6f023 Compare August 13, 2025 19:49
Copy link
Contributor

@tankyleo tankyleo left a comment

Choose a reason for hiding this comment

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

Just two last questions, then a couple of drive-by nits again thank you for all the work.

@a-mpch a-mpch force-pushed the 2025-08-enforce-trampoline-constraint branch 2 times, most recently from c41c202 to ccd103f Compare August 14, 2025 19:03
@a-mpch a-mpch requested a review from tankyleo August 14, 2025 19:03
@a-mpch a-mpch force-pushed the 2025-08-enforce-trampoline-constraint branch from ccd103f to 91f5296 Compare August 14, 2025 19:37
@ldk-reviews-bot
Copy link

🔔 1st Reminder

Hey @valentinewallace! This PR has been waiting for your review.
Please take a look when you have a chance. If you're unable to review, please let us know so we can find another reviewer.

@ldk-reviews-bot
Copy link

🔔 2nd Reminder

Hey @valentinewallace! This PR has been waiting for your review.
Please take a look when you have a chance. If you're unable to review, please let us know so we can find another reviewer.

@ldk-reviews-bot
Copy link

🔔 3rd Reminder

Hey @valentinewallace! This PR has been waiting for your review.
Please take a look when you have a chance. If you're unable to review, please let us know so we can find another reviewer.

@ldk-reviews-bot
Copy link

🔔 4th Reminder

Hey @valentinewallace! This PR has been waiting for your review.
Please take a look when you have a chance. If you're unable to review, please let us know so we can find another reviewer.

This simplifies the code and makes it more straightforward to test unblinded
trampoline receives where we need to compute the trampoline session_priv when
manually creating the inner onion. (The trampoline onion needs to be manually
created because LDK does not natively support sending to unblinded trampolines,
just receiving.)
No need to construct unused blinded hop data or hardcode session privs/prng
seeds.
Previously, this test purported to test for a successful and a failing payment
to a single-hop blinded path containing one trampoline node. However, to induce
the failure the test was manually reconstructing the trampoline onion in a
complicated way that encoded the final onion payload as a receive, when for its
purposes it would be simplier for the recipient to just fail the payment
backwards.

In order to not regress in test coverage, the failure method the test was
previously using is re-added in the next commit as a dedicated test.

XXX this new test surfaced a bug that needs to be fixed
This re-adds test coverage for a case that was removed in the previous commit.
Copy link
Contributor

@valentinewallace valentinewallace left a comment

Choose a reason for hiding this comment

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

I feel like a portion of the existing trampoline tests use a lot of internal APIs/hardcoded keys and are a bit messy as a result, when it's generally preferable to use the public API when testing (cc one of the tests flaked when working on the unrelated OffersMessageFlow PR #3639 (comment)). Mainly talking about the tests where we manually construct a replacement onion.

I think some of the tests in this PR double down on this approach, which is understandable but it seems like a good opportunity to instead fix the pre-existing tests and have cleaner tests moving forward if possible.

I looked into refactoring the tests and came up with this branch: https://github.com/valentinewallace/rust-lightning/tree/2025-08-trampoline-test-refactor Would you like to take it over and base this PR on it? One of the test refactors did surface a bug that will need to be fixed.

@a-mpch
Copy link
Contributor Author

a-mpch commented Aug 26, 2025

seems like a correct concern and approach. I'll take a look and base this PR on your branch!

a-mpch and others added 3 commits August 27, 2025 14:41
This commit adds three new local htlc failure error reasons:
`TemporaryTrampolineFailure`, `TrampolineFeeOrExpiryInsufficient`,
and `UnknownNextTrampoline` for trampoline payment forwarding failures.
We add a `check_trampoline_constraints` similar to
`check_blinded_path_constraints` that compares the Trampoline onion's amount
and CLTV values to the limitations imposed by the outer onion.

Also, we add and modify the following tests:
- Modified the unblinded receive to validate when receiving amount less than
expected.
- Modified test with wrong CLTV parameters that now fails with new enforcement
of CLTV limits.
- Add unblinded and blinded receive tests that forces trampoline onion's CLTV to
be greater than the outer onion packet.

Note that there are some TODOs to be fixed in following commits as we need
the full trampoline forwarding feature to effectively test all cases.

Co-authored-by: Arik Sosman <[email protected]>
@a-mpch a-mpch force-pushed the 2025-08-enforce-trampoline-constraint branch from 91f5296 to cfbade2 Compare August 27, 2025 23:41
@a-mpch
Copy link
Contributor Author

a-mpch commented Aug 28, 2025

@valentinewallace I rebased in top of your branch.
I fixed tests on 35a0eb5 adding an edge case for trampoline failures.
Let me know if it looks better!

@@ -2535,6 +2535,6 @@ fn test_trampoline_forward_rejection() {
// Expect UnknownNextPeer error while we are unable to route forwarding Trampoline payments.
let payment_failed_conditions = PaymentFailedConditions::new()
.expected_htlc_error_data(LocalHTLCFailureReason::UnknownNextPeer, &[0; 0]);
expect_payment_failed_conditions(&nodes[0], payment_hash, false, payment_failed_conditions);
Copy link
Contributor

@valentinewallace valentinewallace Aug 28, 2025

Choose a reason for hiding this comment

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

I don't think we should be switching this value to true here, because Carol is the one that failed and she's not the last hop in the path (at least from Alice's perspective)?

Copy link
Contributor Author

@a-mpch a-mpch Aug 28, 2025

Choose a reason for hiding this comment

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

I had the same thought when doing this.
Alice built a route expecting the trampoline to find a path to the end route or to the next trampoline. But she selected a node that does not support trampoline forwarding.
Spec says:

When processing a `trampoline_onion_packet`, a receiving node:

- If it doesn't support `trampoline_routing`:
  - MUST report a route failure to the origin node

We are actually raising InvalidTrampolineForward that has the same error-code that UnknownNextPeer. I didn't find another error code that makes sense.
And UnkownNextTrampoline in spec is also a PERM error 🤔 meaning that if a trampoline raises an error, would make the permanent error on Alice's perspective (?)

Copy link
Contributor

@valentinewallace valentinewallace Sep 10, 2025

Choose a reason for hiding this comment

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

PERM means that that particular node that failed is permanently unable to handle the payment, but that shouldn't stop Alice from rerouting through another node, I believe.

In process_onion_failure we should be able to tell that the failure came from a trampoline node that was not the final node, I think?

Edit: I see this in the spec:

  - if the _final node_ is returning the error:
    - if the PERM bit is set:
      - SHOULD fail the payment.

@a-mpch a-mpch force-pushed the 2025-08-enforce-trampoline-constraint branch from 59dc83f to 30e81a9 Compare September 12, 2025 11:39
Comment on lines +1376 to +1384
// If next hop is from a trampoline and there is only one trampoline hop
// in the trampoline route, means that the trampoline hop is also a
// final non-blinded node.
let is_next_hop_trampoline =
matches!(next_hop, Some((_, (Some(ErrorHop::TrampolineHop(..)), _))));
if is_next_hop_trampoline {
is_from_final_non_blinded_node =
path.blinded_tail.as_ref().map_or(0, |bt| bt.trampoline_hops.len()) == 1
}
Copy link
Contributor

Choose a reason for hiding this comment

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

I looked into why we needed this handling, since it wasn't super clear to me.

Please double check this work, but I believe the reason is that the trampoline recipient is not always encoding their failure packet correctly.

When I delete this code block, one of the test failures I get is test_trampoline_single_hop_receive. It looks like that's because in fail_htlc_backwards, we do not double-wrap the recipient's failure packet with the trampoline layer. In fail_htlc_backwards_internal, which gets called by fail_htlc_backwards, you can see that for phantom payments for example we will encode an additional layer to the onion error packet using the phantom shared secret, but we won't do the same for trampoline payments.

I think this means the trampoline_ss needs to be included in the HTLCPreviousHopData similar to what we do for phantom shared secrets in that method.

Let me know if this sounds right to you!

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I had the same idea but it would depend on the implementation of the recipient. I left my question on the spec related to it as I couldn't find this case on eclair.

I think that adding the double wrap would make sense, but I have doubts as the trampoline wouldn't be an "intermediate", so maybe just need to behave as a common blinded route?

I'll check out and implement as it is done in the phantom case anyway!

Copy link
Contributor

Choose a reason for hiding this comment

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

Right... The recipient is a trampoline node in this case, so my thinking was that the suggested behavior would align with this part of the spec proposal:
https://github.com/lightning/bolts/pull/829/files#diff-c9739cca996bfa9ab52a39280655a99571ad6e17d51ffe2b2436d7fe2f68be80R225-R236
but it should be specified more in the BOLTs as well.

Copy link
Contributor

Choose a reason for hiding this comment

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

We could also split this PR up, so the first stage is just the test refactors + the bugfix.

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.

4 participants