') + ')', 'gi'); if (regex.test(text)) { found = true; var frag = document.createDocumentFragment(); var parts = text.split(regex); parts.forEach(function(part, i) { if (i % 2 === 0) { frag.appendChild(document.createTextNode(part)); } else { var span = document.createElement('span'); span.className = 'userscript-highlight'; span.textContent = part; frag.appendChild(span); } }); node.parentNode.replaceChild(frag, node); } }); } else if (node.nodeType === 1 && node.childNodes) { // element var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT']; if (!skipTags.includes(node.tagName)) { Array.from(node.childNodes).forEach(highlight); } } } highlight(document.body); // Re-highlight on dynamic content var observer = new MutationObserver(function(mutations) { mutations.forEach(function(m) { m.addedNodes.forEach(function(node) { if (node.nodeType === 1 || node.nodeType === 3) highlight(node); }); }); }); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ', 'i'); if (__m === '*' || __re.test(location.href)) { // Strip utm_, fbclid, gclid, etc. from all links on page (function() { var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content', 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid', 'ref', 'ref_src', 'source', 'medium', 'campaign']; function cleanUrl(url) { try { var u = new URL(url, window.location.origin); var changed = false; trackingParams.forEach(function(p) { if (u.searchParams.has(p)) { u.searchParams.delete(p); changed = true; } }); return changed ? u.toString() : url; } catch (e) { return url; } } function cleanLinks() { document.querySelectorAll('a[href]').forEach(function(a) { var clean = cleanUrl(a.href); if (clean !== a.href) a.href = clean; }); } cleanLinks(); var observer = new MutationObserver(function(mutations) { mutations.forEach(function(m) { m.addedNodes.forEach(function(node) { if (node.nodeType === 1) { if (node.tagName === 'A') cleanLinks(); node.querySelectorAll('a[href]').forEach(function(a) { var clean = cleanUrl(a.href); if (clean !== a.href) a.href = clean; }); } }); }); }); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + ', 'i'); if (__m === '*' || __re.test(location.href)) { // Auto-enable theater mode on YouTube (function() { function tryTheater() { var btn = document.querySelector('button[aria-label="Theater mode"], ytd-player #player button[title="Theater mode"]'); if (btn && !btn.classList.contains('activated')) { btn.click(); } } // Try immediately tryTheater(); // Try after navigation (SPA) var lastUrl = location.href; setInterval(function() { if (location.href !== lastUrl) { lastUrl = location.href; setTimeout(tryTheater, 500); } }, 1000); // Also try on player load var observer = new MutationObserver(tryTheater); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ', 'i'); if (__m === '*' || __re.test(location.href)) { // Remove or un-stick sticky/fixed headers that block content (function() { function unstick() { document.querySelectorAll('header, nav, [role="banner"], .header, .navbar, .sticky, .fixed-top, [style*="position: fixed"], [style*="position:sticky"]').forEach(function(el) { if (el.style.position === 'fixed' || el.style.position === 'sticky' || getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') { el.style.position = 'static'; el.style.top = 'auto'; el.style.zIndex = 'auto'; } }); } unstick(); var observer = new MutationObserver(unstick); observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] }); })(); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); })(); Enforce Trampoline Constraints (replacement) by carlaKC · Pull Request #4226 · lightningdevkit/rust-lightning · GitHub
Skip to content

Enforce Trampoline Constraints (replacement) - #4226

Merged
carlaKC merged 5 commits into
lightningdevkit:mainfrom
carlaKC:3983-trampoline-constraints
Dec 1, 2025
Merged

Enforce Trampoline Constraints (replacement)#4226
carlaKC merged 5 commits into
lightningdevkit:mainfrom
carlaKC:3983-trampoline-constraints

Conversation

@carlaKC

Copy link
Copy Markdown
Contributor

This PR replaces #3983, adding validation of trampoline onions (as compared to the outer onion). It makes some quite significant changes to the tests in the original PR to consolidate blinded and unblinded tests for success/failure scenarios into a single helper (apologies to reviewers who've already looked at the tests, but I think this DRYs it up quite nicely).

While we're here, it also moves rustfmt::skip to a per-function level on blinded_payment_tests.rs and formats the existing test helper that we're modifying in a pre-factor so that the new code can be formatted.

@ldk-reviews-bot

ldk-reviews-bot commented Nov 17, 2025

Copy link
Copy Markdown

👋 Thanks for assigning @tankyleo 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.

Comment threadlightning/src/ln/onion_payment.rs Outdated
}),
onion_utils::Hop::TrampolineForward { next_trampoline_hop_data, next_trampoline_hop_hmac, new_trampoline_packet_bytes, trampoline_shared_secret, .. } => {
onion_utils::Hop::TrampolineForward { ref outer_hop_data, next_trampoline_hop_data, next_trampoline_hop_hmac, new_trampoline_packet_bytes, trampoline_shared_secret, .. } => {
// TODO: return reason as forward issue, not as receiving issue when forwarding is ready.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

I'm not quite clear on what this todo means, still catching up on some context - @a-mpch could you help me out?

@carlaKCcarlaKC changed the title 3983 trampoline constraintsEnforce Trampoline Constraints (replacement)Nov 17, 2025
@carlaKC

Copy link
Copy Markdown
ContributorAuthor

Assigning reviewers who looked at the original PR - please free yourself if not appropriate!

@codecov

codecovBot commented Nov 17, 2025

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 92.33129% with 25 lines in your changes missing coverage. Please review.
✅ Project coverage is 89.32%. Comparing base (6d9c676) to head (785c781).
⚠️ Report is 17 commits behind head on main.

Files with missing linesPatch %Lines
lightning/src/ln/onion_payment.rs70.00%15 Missing ⚠️
lightning/src/ln/onion_utils.rs0.00%6 Missing ⚠️
lightning/src/ln/blinded_payment_tests.rs98.47%3 Missing and 1 partial ⚠️
Additional details and impacted files
@@ Coverage Diff @@## main #4226 +/- ##
==========================================
- Coverage 89.32% 89.32% -0.01% 
==========================================
Files 180 180 Lines 138641 138916 +275 Branches 138641 138916 +275 ==========================================
+ Hits 123844 124088 +244 - Misses 12174 12205 +31 
Partials 2623 2623 
FlagCoverage Δ
fuzzing34.97% <0.00%> (-1.01%)⬇️
tests88.69% <92.33%> (+<0.01%)⬆️

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.

@carlaKC

Copy link
Copy Markdown
ContributorAuthor

One thing to note about the tests here: we've currently only got coverage for blinded receives checking the constraints (this is what the original PR had). We could also add coverage for blinded forwards in the failure case (can't do for success because we just fail the forwards rn), which would make codecov a bit happier.

I think this is worth doing, but it would mean adding a bit more code to the mega test helper - interested on hearing thoughts on how readable others find it before adding another layer to an already quite dense test! Can also easily be a small follow. up.

@valentinewallace

valentinewallace commented Nov 18, 2025

Copy link
Copy Markdown
Contributor

Needs rebase :(

I did find the new testing not ideal from a readability PoV at first glance, going to take a closer look in a bit but let me know if you see any obvious ways to improve things. It may be that the nature of what we're testing makes it hard to improve things though.

Comment threadlightning/src/ln/blinded_payment_tests.rs
}

// Creates a replacement onion that is used to produce scenarios that we don't support, specifically
// unblinded receives and invalid payloads.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Here and a few other places, I thought we did support unblinded trampoline receives but didn't support unblinded trampoline sends. At least I can't see where we reject them + it seems like we understand how to decode the payload 👀 may be missing something though

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Badly worded comment - we don't support creating payloads (sends) with unblinded receives, I'll fix!

Comment threadlightning/src/ln/blinded_payment_tests.rs
Comment threadlightning/src/ln/onion_payment.rs Outdated
onion_utils::Hop::TrampolineForward { next_trampoline_hop_data, next_trampoline_hop_hmac, new_trampoline_packet_bytes, trampoline_shared_secret, .. } => {
onion_utils::Hop::TrampolineForward { ref outer_hop_data, next_trampoline_hop_data, next_trampoline_hop_hmac, new_trampoline_packet_bytes, trampoline_shared_secret, .. } => {
// TODO: return reason as forward issue, not as receiving issue when forwarding is ready.
check_trampoline_onion_constraints(outer_hop_data, next_trampoline_hop_data.outgoing_cltv_value, next_trampoline_hop_data.amt_to_forward)?;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I'm a bit confused why we're calling this method here. It only returns IncorrectFinal* errors, which seems like it should only be used for receives and not forwards. I might be missing something from the trampoline spec here? Or do we need a new similar method for forwards that will return some of the new errors, like TrampolineFeeOrExpiryInsufficient, if the cltv/forward amount are mismatching between the inner and outer onion?

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

This is the todo I'm not so sure about. It seems to me like the approach in the original PR is to add this validation here (even though it's not in the spec) and then remove it when we add more forwarding logic. cc @a-mpch?

I think that we can remove check_trampoline_onion_constraints on the forwarding branches and get to them in subsequent PRs, but just want to make sure I'm not missing context from the original change.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

We need to check the trampoline constraints in forwarding branches when implementing the forwarding. We can safely remove it and re-added in follow up PRs.

As at this point we don't have implemented this error: https://github.com/lightning/bolts/pull/836/files#diff-ad65f0beaac5cef88f5fd7a8b9ca36cbc5a790f4815b4b50b9ea794a55aaf012R1441

That would be returned here.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Going to go ahead with removing the forwarding check and will re-add when we get to more forwarding logic.

@ldk-reviews-bot

Copy link
Copy Markdown

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

carlaKCand others added 4 commits November 20, 2025 08:47
To allow formatting on new code, move to per-function skips.
Remove skip without fixing up any of the ugly formatting, so that the
diff is a bit more readable in review.
This commit adds three new local htlc failure error reasons:
`TemporaryTrampolineFailure`, `TrampolineFeeOrExpiryInsufficient`,
and `UnknownNextTrampoline` for trampoline payment forwarding failures.
@carlaKC
carlaKCforce-pushed the 3983-trampoline-constraints branch from b43670e to 531cca6CompareNovember 20, 2025 13:50
@carlaKC

Copy link
Copy Markdown
ContributorAuthor

Rebased + addressed review in fixups, removing validation of trampoline forwards because we'll need a different check/error there anyway.

@valentinewallacevalentinewallace left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

LGTM, feel free to squash!

@carlaKC
carlaKCforce-pushed the 3983-trampoline-constraints branch from 136641d to 6b5cd30CompareNovember 20, 2025 16:40
@ldk-reviews-bot

Copy link
Copy Markdown

🔔 2nd 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.

@ldk-reviews-bot

Copy link
Copy Markdown

🔔 3rd 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.

tankyleo
tankyleo previously approved these changes Nov 25, 2025

@tankyleotankyleo left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Just two nits, thanks for your patience, took the time to read up on blinded paths + trampoline so I can review future PRs :)

Comment threadlightning/src/ln/blinded_payment_tests.rs Outdated
Comment threadlightning/src/ln/msgs.rs Outdated
Tests are added to cover validation of blinded and unblinded trampoline
payloads against their outer onion. These are consolidated with our
existing coverage for successful receives.
Co-authored-by: Arik Sosman <git@arik.io>
Co-authored-by: Maurice Poirrier <mpch@hey.com>
@carlaKC

Copy link
Copy Markdown
ContributorAuthor

Addressed last two nits directly on commit, diff here.

@ldk-reviews-bot

Copy link
Copy Markdown

🔔 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
Copy Markdown

🔔 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
Copy Markdown

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

@valentinewallacevalentinewallace left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Looks good, one comment that I think should be addressed but feel free to land and save for follow-up

) {
Ok((amt, cltv)) => (amt, cltv),
Err(()) => {
return encode_relay_error("Trampoline blinded forward amt or CLTV values exceeded the outer onion's",

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

nit: I think this change could've been a bit better suited to a separate commit, also this error message is a bit weird since there isn't an explicit forward amount/cltv for blinded trampoline forwards

(40, HTLCMaximum),
(41, PeerOffline),
(42, ChannelBalanceOverdrawn)
(42, ChannelBalanceOverdrawn),

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Sorry I just noticed this, on line 1778 we have a macro that says "Error codes that represent BOLT04 error codes must be included here", which looks like it should include these new errors

@carlaKC
carlaKC merged commit 3e186bc into lightningdevkit:mainDec 1, 2025
26 checks passed
@carlaKCcarlaKC mentioned this pull request Dec 1, 2025
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

5 participants

@carlaKC@ldk-reviews-bot@valentinewallace@a-mpch@tankyleo