Intercept HTLC forwards for JIT channels - #1835

Merged
TheBlueMatt merged 9 commits into
lightningdevkit:mainfrom
valentinewallace:2022-11-jit-chan-htlc-intercept
Dec 1, 2022
Merged

Intercept HTLC forwards for JIT channels #1835
TheBlueMatt merged 9 commits into
lightningdevkit:mainfrom
valentinewallace:2022-11-jit-chan-htlc-intercept

Conversation

@valentinewallace

@valentinewallacevalentinewallace commented Nov 7, 2022

Copy link
Copy Markdown
Contributor

For context, LSPs need to be able to open 0-conf JIT channels to users upon the first time the user is receiving a payment. To do this, they will put fake route hints in end user invoices that signal to LDK that this is an intercept forward, similar to phantom payments. LDK will then generate an event, giving the LSP the opportunity to open the JIT channel. The LSP can then forward the payment over the newly opened channel, or fail it.

Based on #1840
Supercedes #1601

@valentinewallace
valentinewallaceforce-pushed the 2022-11-jit-chan-htlc-intercept branch 5 times, most recently from beae304 to 90c4d75CompareNovember 7, 2022 18:42
@valentinewallacevalentinewallace mentioned this pull request Nov 7, 2022
@valentinewallace
valentinewallaceforce-pushed the 2022-11-jit-chan-htlc-intercept branch from 8e3a664 to b166af0CompareNovember 7, 2022 22:30
Comment threadlightning/src/ln/channelmanager.rs Outdated
@codecov-commenter

codecov-commenter commented Nov 7, 2022

Copy link
Copy Markdown

Codecov Report

Base: 90.70% // Head: 90.67% // Decreases project coverage by -0.02%⚠️

Coverage data is based on head (a5c5d53) compared to base (440c3ee).
Patch coverage: 84.34% of modified lines in pull request are covered.

❗ Current head a5c5d53 differs from pull request most recent head acff8f6. Consider uploading reports for the commit acff8f6 to get more accurate results

Additional details and impacted files
@@ Coverage Diff @@## main #1835 +/- ##
==========================================
- Coverage 90.70% 90.67% -0.03% 
==========================================
Files 91 91 Lines 48090 48303 +213 Branches 48090 48303 +213 ==========================================
+ Hits 43618 43800 +182 - Misses 4472 4503 +31 
Impacted FilesCoverage Δ
lightning/src/util/config.rs65.90% <0.00%> (-0.76%)⬇️
lightning/src/util/events.rs24.65% <4.16%> (-1.32%)⬇️
lightning/src/ln/channelmanager.rs86.20% <83.70%> (-0.16%)⬇️
lightning/src/ln/payment_tests.rs98.73% <97.74%> (-0.17%)⬇️
lightning/src/util/scid_utils.rs99.31% <100.00%> (+0.10%)⬆️
lightning-block-sync/src/rest.rs62.06% <0.00%> (-1.87%)⬇️
lightning-block-sync/src/rpc.rs74.80% <0.00%> (-1.14%)⬇️
lightning-block-sync/src/poll.rs86.33% <0.00%> (-0.58%)⬇️
lightning-net-tokio/src/lib.rs77.03% <0.00%> (-0.28%)⬇️
lightning-block-sync/src/lib.rs93.33% <0.00%> (-0.27%)⬇️
... and 13 more

Help us with your feedback. Take ten seconds to tell us how you rate us. Have a feature suggestion? Share it here.

☔ View full report at Codecov.
📢 Do you have feedback about the report comment? Let us know in this issue.

Comment threadlightning/src/util/events.rs Outdated
@AnthonyRonning

AnthonyRonning commented Nov 10, 2022

Copy link
Copy Markdown
Contributor

Are there plans for generic HTLC interception at all? Not dependent on the routing hints of someone else's invoice? There can still be logic into determining the type based on SCID but in general all HTLC's could still be intercepted or at least subscribed to based on type.

There are many use cases for generic HTLC interception that shouldn't depend on LDK development, here are a few:

  1. Other approaches to 0 conf JIT channel payments (something double-invoice like instead of routing hint-like)
  2. Escrow (having a router decide to continue routing to destination in order to deliver funds based on a condition)
  3. Whether or not to route payments down certain channels or at all (liquidity management, balance probe protection)
  4. Third party preimages (node not knowing the preimage but waiting for either a third party or a different application handle preimages)
  5. Hodl invoice (not advocating for long running but at least allowing for checks and processes to run for a few seconds)

You could still have SCID logic but I would love to see generic solved for first and then application specific tbh. I think that's worked really well in the LND/CLN ecosystems.

@valentinewallace

Copy link
Copy Markdown
ContributorAuthor

Are there plans for generic HTLC interception at all? Not dependent on the routing hints of someone else's invoice?

Yes, the plan is to swiftly follow up to this PR with adding general forward interception :)

(1), (4), and (5) are already supported via our PaymentReceived event, IIUC. LDK generates this event once all MPP parts arrive. Upon receipt, you can get the preimage and do whatever other desired operations you like, then call claim_funds (per the linked docs).

@valentinewallace
valentinewallaceforce-pushed the 2022-11-jit-chan-htlc-intercept branch from d763bb5 to 099533dCompareNovember 10, 2022 16:55
@valentinewallace

Copy link
Copy Markdown
ContributorAuthor

Had to rebase to get #1844.

@AnthonyRonning

Copy link
Copy Markdown
Contributor

Yes, the plan is to swiftly follow up to this PR with adding general forward interception :)

Awesome! Concept ACK from me then. I browsed through the code and the API usage sounds good to me but probably can't comment on the rest 👍

@ViktorT-11ViktorT-11 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.

First look-through generally looks good :).

Comment threadlightning/src/ln/channelmanager.rs
Comment threadlightning/src/ln/channelmanager.rs Outdated
Comment threadlightning/src/ln/channelmanager.rs
Comment threadlightning/src/ln/channelmanager.rs Outdated
Comment threadlightning/src/ln/channelmanager.rs Outdated

@TheBlueMattTheBlueMatt left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

I think we need a fallback failure on a timer. If the user screws up and loses the intercept event entirely we shouldn't just sit on the HTLC forever and get the channel force-closed.

Comment threadlightning/src/util/events.rs Outdated
Comment threadlightning/src/util/events.rs
Comment threadlightning/src/ln/channelmanager.rs Outdated
Comment threadlightning/src/ln/channelmanager.rs Outdated
Comment threadlightning/src/ln/channelmanager.rs Outdated
Comment threadlightning/src/ln/channelmanager.rs Outdated
Comment threadlightning/src/ln/channelmanager.rs Outdated
@valentinewallace

Copy link
Copy Markdown
ContributorAuthor

Great feedback once again @ViktorTigerstrom! Working on addressing it

@valentinewallace
valentinewallaceforce-pushed the 2022-11-jit-chan-htlc-intercept branch 2 times, most recently from 0759af8 to ee70d50CompareNovember 14, 2022 20:23
@valentinewallace
valentinewallaceforce-pushed the 2022-11-jit-chan-htlc-intercept branch from 72087f8 to 225a22bCompareNovember 28, 2022 20:13

@ViktorT-11ViktorT-11 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.

This looks good to me. Only real feedback I have left is that it would be valuable to include test coverage to ensure that we don't generate the PaymentIntercepted event + populate pending_intercepted_htlcs when accept_intercept_htlcs is set to false.

nodes[1].node.handle_update_add_htlc(&nodes[0].node.get_our_node_id(), &payment_event.msgs[0]);
commitment_signed_dance!(nodes[1], nodes[0], &payment_event.commitment_msg, false, true);

// Check that we generate the PaymentIntercepted event when an intercept forward is detected.

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.

Would be valuable to also have test coverage ensuring that the PaymentIntercepted event isn't generated + pending_intercepted_htlcs isn't populated when accept_intercept_htlcs is false.

@valentinewallacevalentinewallaceNov 28, 2022

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.

Gonna save that for follow-up for the sake of the size of this PR, but you can manually check that the test fails when the config change lines are commented out. FWIW, that would set a new standard of testing rigor for us since i.e. the zero-conf PR didn't/doesn't test its config.

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.

Ok fair enough :)

Comment threadlightning/src/ln/channelmanager.rs
Comment threadlightning/src/ln/channelmanager.rs
Comment threadlightning/src/ln/channelmanager.rs Outdated
_ => unreachable!(),
};
timed_out_htlcs.push((prev_hop_data, htlc.forward_info.payment_hash,
HTLCFailReason::Reason { failure_code: 0x1000 | 14, data: Vec::new() },

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

14 is definitely right here, but its an UPDATE error, so we need to include a channel_update for the outbound channel, which is obviously....unclear? I guess we could deliberately include the wrong channel's update here and use the previous-hop channel, but that's pretty nonsensical. Maybe we just temporary_node_failure?

@TheBlueMatt

Copy link
Copy Markdown
Collaborator

LGTM, I think.

@TheBlueMattTheBlueMatt added this to the 0.0.113 milestone Nov 29, 2022
@ViktorT-11

Copy link
Copy Markdown
Contributor

Looks good to me as well!

@dunxendunxen 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, just a tiny nit and question :)

payment_hash: PaymentHash,
/// How many msats were received on the inbound edge of this HTLC.
inbound_amount_msat: u64,
/// How many msats the payer intended to route to the next node. Depending on the reason you are

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.

new rust style team pls save us

Comment threadlightning/src/util/events.rs Outdated
});

failed_intercept_forwards.push((htlc_source, forward_info.payment_hash,
HTLCFailReason::Reason { failure_code: 0x4000 | 10, data: Vec::new() },

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.

not for this PR, but I've wondered whether we should collect failure code consts somewhere so it's easy to see what it is. I can create an issue if we'd want that, unless I missed some prior reasoning not to.

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.

Yeah, I think that would be nice to have!

/// [`HTLCIntercepted`]: events::Event::HTLCIntercepted
// TODO: when we move to deciding the best outbound channel at forward time, only take
// `next_node_id` and not `next_hop_channel_id`
pub fn forward_intercepted_htlc(&self, intercept_id: InterceptId, next_hop_channel_id: &[u8; 32], _next_node_id: PublicKey, amt_to_forward_msat: u64) -> Result<(), APIError> {

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 a question to check my understanding:

Is this basically the procedure for an LDK user?

  1. Calls ChannelManager::get_intercept_scid
  2. Generates invoice with intercept scid in route hints for end-user
  3. Receives an HTLCIntercepted event when the HTLC is intercepted
  4. At this point the LDK user can create a channel
  5. Then call this method to forward over that JIT channel

@ViktorT-11ViktorT-11Nov 30, 2022

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.

Yes that's my understanding, where the LDK user is the LSP in your example (nodes[1] in the test), and the end-user is nodes[2] in the test. I guess step (2) in your example doesn't necessarily need to be on the LDK user's side, as long as the Intercept scid is passed to the end-user.

@dunxendunxenNov 30, 2022

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.

Ah, I should have read the test.

Yeah I think I phrased that weirdly for (2). End user generates invoice but just shoves the scid they got from the LSP in the route hints.

valentinewallaceand others added 9 commits November 30, 2022 12:43
No htlcs are intercepted yet, that will be added in upcoming commit(s)
Co-authored-by: John Cantrell <johncantrell97@gmail.com>
Co-authored-by: Valentine Wallace <vwallace@protonmail.com>
This is useful for LSPs who wish to create a just-in-time channel for end users
receiving a lightning payment. These fake scids will be encoded into route
hints in end user invoices, and signal to LDK to create an event triggering the
JIT channel, after which the payment will be received.
Co-authored-by: John Cantrell <johncantrell97@gmail.com>
Co-authored-by: Valentine Wallace <vwallace@protonmail.com>
Used in upcoming commit(s) so users can intercept forwarded HTLCs
Co-authored-by: John Cantrell <johncantrell97@gmail.com>
Co-authored-by: Valentine Wallace <vwallace@protonmail.com>
And store the pending intercepted HTLC in pending_intercepted_htlcs
Co-authored-by: John Cantrell <johncantrell97@gmail.com>
Co-authored-by: Valentine Wallace <vwallace@protonmail.com>
See ChannelManager::forward_intercepted_htlc and
ChannelManager::get_intercept_scid for details
Co-authored-by: John Cantrell <johncantrell97@gmail.com>
Co-authored-by: Valentine Wallace <vwallace@protonmail.com>
Co-authored-by: John Cantrell <johncantrell97@gmail.com>
Co-authored-by: Valentine Wallace <vwallace@protonmail.com>
@valentinewallace
valentinewallaceforce-pushed the 2022-11-jit-chan-htlc-intercept branch from a5c5d53 to acff8f6CompareNovember 30, 2022 17:52
@valentinewallace

Copy link
Copy Markdown
ContributorAuthor

Rebased due to conflicts

@ariardariard left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

ACK acff8f6

Reviewed code changes since last diff, and also checked test coverage. Remaining comments are minor.

let next_hop_scid = match self.channel_state.lock().unwrap().by_id.get(next_hop_channel_id) {
Some(chan) => {
if !chan.is_usable() {
return Err(APIError::APIMisuseError {

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

We have APIError::ChannelUnavailable in fact, could be used.

let _persistence_guard = PersistenceNotifierGuard::notify_on_drop(&self.total_consistency_lock, &self.persistence_notifier);

let payment = self.pending_intercepted_htlcs.lock().unwrap().remove(&intercept_id)
.ok_or_else(|| APIError::APIMisuseError {

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Mutating this line does not break intercepted_payment

@TheBlueMattTheBlueMatt left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

LGTM, gonna land to get the conflicts out of the way but please address the two issues @ariard noted and the below one in a followup.

};
connect_block(&nodes[0], &block);
connect_block(&nodes[1], &block);
let block_count = 183; // find_route adds a random CLTV offset, so hardcode rather than summing consts

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

It adds a random value in a range, though, so we should still be able to sum consts. Please change it to summing consts cause otherwise our entire test suite fails any time we change any constant :(

Note that if you use the get_route method it won't add the random value, as well.

Sign up for freeto 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.

8 participants

@valentinewallace@codecov-commenter@AnthonyRonning@TheBlueMatt@ariard@ViktorT-11@dunxen@jkczyz
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all
 blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks");
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Skip to content

Intercept HTLC forwards for JIT channels - #1835

Merged
TheBlueMatt merged 9 commits into
lightningdevkit:mainfrom
valentinewallace:2022-11-jit-chan-htlc-intercept
Dec 1, 2022
Merged

Intercept HTLC forwards for JIT channels #1835
TheBlueMatt merged 9 commits into
lightningdevkit:mainfrom
valentinewallace:2022-11-jit-chan-htlc-intercept

Conversation

@valentinewallace

@valentinewallacevalentinewallace commented Nov 7, 2022

Copy link
Copy Markdown
Contributor

For context, LSPs need to be able to open 0-conf JIT channels to users upon the first time the user is receiving a payment. To do this, they will put fake route hints in end user invoices that signal to LDK that this is an intercept forward, similar to phantom payments. LDK will then generate an event, giving the LSP the opportunity to open the JIT channel. The LSP can then forward the payment over the newly opened channel, or fail it.

Based on #1840
Supercedes #1601

@valentinewallace
valentinewallaceforce-pushed the 2022-11-jit-chan-htlc-intercept branch 5 times, most recently from beae304 to 90c4d75CompareNovember 7, 2022 18:42
@valentinewallacevalentinewallace mentioned this pull request Nov 7, 2022
@valentinewallace
valentinewallaceforce-pushed the 2022-11-jit-chan-htlc-intercept branch from 8e3a664 to b166af0CompareNovember 7, 2022 22:30
Comment threadlightning/src/ln/channelmanager.rs Outdated
@codecov-commenter

codecov-commenter commented Nov 7, 2022

Copy link
Copy Markdown

Codecov Report

Base: 90.70% // Head: 90.67% // Decreases project coverage by -0.02%⚠️

Coverage data is based on head (a5c5d53) compared to base (440c3ee).
Patch coverage: 84.34% of modified lines in pull request are covered.

❗ Current head a5c5d53 differs from pull request most recent head acff8f6. Consider uploading reports for the commit acff8f6 to get more accurate results

Additional details and impacted files
@@ Coverage Diff @@## main #1835 +/- ##
==========================================
- Coverage 90.70% 90.67% -0.03% 
==========================================
Files 91 91 Lines 48090 48303 +213 Branches 48090 48303 +213 ==========================================
+ Hits 43618 43800 +182 - Misses 4472 4503 +31 
Impacted FilesCoverage Δ
lightning/src/util/config.rs65.90% <0.00%> (-0.76%)⬇️
lightning/src/util/events.rs24.65% <4.16%> (-1.32%)⬇️
lightning/src/ln/channelmanager.rs86.20% <83.70%> (-0.16%)⬇️
lightning/src/ln/payment_tests.rs98.73% <97.74%> (-0.17%)⬇️
lightning/src/util/scid_utils.rs99.31% <100.00%> (+0.10%)⬆️
lightning-block-sync/src/rest.rs62.06% <0.00%> (-1.87%)⬇️
lightning-block-sync/src/rpc.rs74.80% <0.00%> (-1.14%)⬇️
lightning-block-sync/src/poll.rs86.33% <0.00%> (-0.58%)⬇️
lightning-net-tokio/src/lib.rs77.03% <0.00%> (-0.28%)⬇️
lightning-block-sync/src/lib.rs93.33% <0.00%> (-0.27%)⬇️
... and 13 more

Help us with your feedback. Take ten seconds to tell us how you rate us. Have a feature suggestion? Share it here.

☔ View full report at Codecov.
📢 Do you have feedback about the report comment? Let us know in this issue.

Comment threadlightning/src/util/events.rs Outdated
@AnthonyRonning

AnthonyRonning commented Nov 10, 2022

Copy link
Copy Markdown
Contributor

Are there plans for generic HTLC interception at all? Not dependent on the routing hints of someone else's invoice? There can still be logic into determining the type based on SCID but in general all HTLC's could still be intercepted or at least subscribed to based on type.

There are many use cases for generic HTLC interception that shouldn't depend on LDK development, here are a few:

  1. Other approaches to 0 conf JIT channel payments (something double-invoice like instead of routing hint-like)
  2. Escrow (having a router decide to continue routing to destination in order to deliver funds based on a condition)
  3. Whether or not to route payments down certain channels or at all (liquidity management, balance probe protection)
  4. Third party preimages (node not knowing the preimage but waiting for either a third party or a different application handle preimages)
  5. Hodl invoice (not advocating for long running but at least allowing for checks and processes to run for a few seconds)

You could still have SCID logic but I would love to see generic solved for first and then application specific tbh. I think that's worked really well in the LND/CLN ecosystems.

@valentinewallace

Copy link
Copy Markdown
ContributorAuthor

Are there plans for generic HTLC interception at all? Not dependent on the routing hints of someone else's invoice?

Yes, the plan is to swiftly follow up to this PR with adding general forward interception :)

(1), (4), and (5) are already supported via our PaymentReceived event, IIUC. LDK generates this event once all MPP parts arrive. Upon receipt, you can get the preimage and do whatever other desired operations you like, then call claim_funds (per the linked docs).

@valentinewallace
valentinewallaceforce-pushed the 2022-11-jit-chan-htlc-intercept branch from d763bb5 to 099533dCompareNovember 10, 2022 16:55
@valentinewallace

Copy link
Copy Markdown
ContributorAuthor

Had to rebase to get #1844.

@AnthonyRonning

Copy link
Copy Markdown
Contributor

Yes, the plan is to swiftly follow up to this PR with adding general forward interception :)

Awesome! Concept ACK from me then. I browsed through the code and the API usage sounds good to me but probably can't comment on the rest 👍

@ViktorT-11ViktorT-11 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.

First look-through generally looks good :).

Comment threadlightning/src/ln/channelmanager.rs
Comment threadlightning/src/ln/channelmanager.rs Outdated
Comment threadlightning/src/ln/channelmanager.rs
Comment threadlightning/src/ln/channelmanager.rs Outdated
Comment threadlightning/src/ln/channelmanager.rs Outdated

@TheBlueMattTheBlueMatt left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

I think we need a fallback failure on a timer. If the user screws up and loses the intercept event entirely we shouldn't just sit on the HTLC forever and get the channel force-closed.

Comment threadlightning/src/util/events.rs Outdated
Comment threadlightning/src/util/events.rs
Comment threadlightning/src/ln/channelmanager.rs Outdated
Comment threadlightning/src/ln/channelmanager.rs Outdated
Comment threadlightning/src/ln/channelmanager.rs Outdated
Comment threadlightning/src/ln/channelmanager.rs Outdated
Comment threadlightning/src/ln/channelmanager.rs Outdated
@valentinewallace

Copy link
Copy Markdown
ContributorAuthor

Great feedback once again @ViktorTigerstrom! Working on addressing it

@valentinewallace
valentinewallaceforce-pushed the 2022-11-jit-chan-htlc-intercept branch 2 times, most recently from 0759af8 to ee70d50CompareNovember 14, 2022 20:23
@valentinewallace
valentinewallaceforce-pushed the 2022-11-jit-chan-htlc-intercept branch from 72087f8 to 225a22bCompareNovember 28, 2022 20:13

@ViktorT-11ViktorT-11 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.

This looks good to me. Only real feedback I have left is that it would be valuable to include test coverage to ensure that we don't generate the PaymentIntercepted event + populate pending_intercepted_htlcs when accept_intercept_htlcs is set to false.

nodes[1].node.handle_update_add_htlc(&nodes[0].node.get_our_node_id(), &payment_event.msgs[0]);
commitment_signed_dance!(nodes[1], nodes[0], &payment_event.commitment_msg, false, true);

// Check that we generate the PaymentIntercepted event when an intercept forward is detected.

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.

Would be valuable to also have test coverage ensuring that the PaymentIntercepted event isn't generated + pending_intercepted_htlcs isn't populated when accept_intercept_htlcs is false.

@valentinewallacevalentinewallaceNov 28, 2022

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.

Gonna save that for follow-up for the sake of the size of this PR, but you can manually check that the test fails when the config change lines are commented out. FWIW, that would set a new standard of testing rigor for us since i.e. the zero-conf PR didn't/doesn't test its config.

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.

Ok fair enough :)

Comment threadlightning/src/ln/channelmanager.rs
Comment threadlightning/src/ln/channelmanager.rs
Comment threadlightning/src/ln/channelmanager.rs Outdated
_ => unreachable!(),
};
timed_out_htlcs.push((prev_hop_data, htlc.forward_info.payment_hash,
HTLCFailReason::Reason { failure_code: 0x1000 | 14, data: Vec::new() },

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

14 is definitely right here, but its an UPDATE error, so we need to include a channel_update for the outbound channel, which is obviously....unclear? I guess we could deliberately include the wrong channel's update here and use the previous-hop channel, but that's pretty nonsensical. Maybe we just temporary_node_failure?

@TheBlueMatt

Copy link
Copy Markdown
Collaborator

LGTM, I think.

@TheBlueMattTheBlueMatt added this to the 0.0.113 milestone Nov 29, 2022
@ViktorT-11

Copy link
Copy Markdown
Contributor

Looks good to me as well!

@dunxendunxen 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, just a tiny nit and question :)

payment_hash: PaymentHash,
/// How many msats were received on the inbound edge of this HTLC.
inbound_amount_msat: u64,
/// How many msats the payer intended to route to the next node. Depending on the reason you are

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.

new rust style team pls save us

Comment threadlightning/src/util/events.rs Outdated
});

failed_intercept_forwards.push((htlc_source, forward_info.payment_hash,
HTLCFailReason::Reason { failure_code: 0x4000 | 10, data: Vec::new() },

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.

not for this PR, but I've wondered whether we should collect failure code consts somewhere so it's easy to see what it is. I can create an issue if we'd want that, unless I missed some prior reasoning not to.

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.

Yeah, I think that would be nice to have!

/// [`HTLCIntercepted`]: events::Event::HTLCIntercepted
// TODO: when we move to deciding the best outbound channel at forward time, only take
// `next_node_id` and not `next_hop_channel_id`
pub fn forward_intercepted_htlc(&self, intercept_id: InterceptId, next_hop_channel_id: &[u8; 32], _next_node_id: PublicKey, amt_to_forward_msat: u64) -> Result<(), APIError> {

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 a question to check my understanding:

Is this basically the procedure for an LDK user?

  1. Calls ChannelManager::get_intercept_scid
  2. Generates invoice with intercept scid in route hints for end-user
  3. Receives an HTLCIntercepted event when the HTLC is intercepted
  4. At this point the LDK user can create a channel
  5. Then call this method to forward over that JIT channel

@ViktorT-11ViktorT-11Nov 30, 2022

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.

Yes that's my understanding, where the LDK user is the LSP in your example (nodes[1] in the test), and the end-user is nodes[2] in the test. I guess step (2) in your example doesn't necessarily need to be on the LDK user's side, as long as the Intercept scid is passed to the end-user.

@dunxendunxenNov 30, 2022

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.

Ah, I should have read the test.

Yeah I think I phrased that weirdly for (2). End user generates invoice but just shoves the scid they got from the LSP in the route hints.

valentinewallaceand others added 9 commits November 30, 2022 12:43
No htlcs are intercepted yet, that will be added in upcoming commit(s)
Co-authored-by: John Cantrell <johncantrell97@gmail.com>
Co-authored-by: Valentine Wallace <vwallace@protonmail.com>
This is useful for LSPs who wish to create a just-in-time channel for end users
receiving a lightning payment. These fake scids will be encoded into route
hints in end user invoices, and signal to LDK to create an event triggering the
JIT channel, after which the payment will be received.
Co-authored-by: John Cantrell <johncantrell97@gmail.com>
Co-authored-by: Valentine Wallace <vwallace@protonmail.com>
Used in upcoming commit(s) so users can intercept forwarded HTLCs
Co-authored-by: John Cantrell <johncantrell97@gmail.com>
Co-authored-by: Valentine Wallace <vwallace@protonmail.com>
And store the pending intercepted HTLC in pending_intercepted_htlcs
Co-authored-by: John Cantrell <johncantrell97@gmail.com>
Co-authored-by: Valentine Wallace <vwallace@protonmail.com>
See ChannelManager::forward_intercepted_htlc and
ChannelManager::get_intercept_scid for details
Co-authored-by: John Cantrell <johncantrell97@gmail.com>
Co-authored-by: Valentine Wallace <vwallace@protonmail.com>
Co-authored-by: John Cantrell <johncantrell97@gmail.com>
Co-authored-by: Valentine Wallace <vwallace@protonmail.com>
@valentinewallace
valentinewallaceforce-pushed the 2022-11-jit-chan-htlc-intercept branch from a5c5d53 to acff8f6CompareNovember 30, 2022 17:52
@valentinewallace

Copy link
Copy Markdown
ContributorAuthor

Rebased due to conflicts

@ariardariard left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

ACK acff8f6

Reviewed code changes since last diff, and also checked test coverage. Remaining comments are minor.

let next_hop_scid = match self.channel_state.lock().unwrap().by_id.get(next_hop_channel_id) {
Some(chan) => {
if !chan.is_usable() {
return Err(APIError::APIMisuseError {

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

We have APIError::ChannelUnavailable in fact, could be used.

let _persistence_guard = PersistenceNotifierGuard::notify_on_drop(&self.total_consistency_lock, &self.persistence_notifier);

let payment = self.pending_intercepted_htlcs.lock().unwrap().remove(&intercept_id)
.ok_or_else(|| APIError::APIMisuseError {

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Mutating this line does not break intercepted_payment

@TheBlueMattTheBlueMatt left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

LGTM, gonna land to get the conflicts out of the way but please address the two issues @ariard noted and the below one in a followup.

};
connect_block(&nodes[0], &block);
connect_block(&nodes[1], &block);
let block_count = 183; // find_route adds a random CLTV offset, so hardcode rather than summing consts

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

It adds a random value in a range, though, so we should still be able to sum consts. Please change it to summing consts cause otherwise our entire test suite fails any time we change any constant :(

Note that if you use the get_route method it won't add the random value, as well.

Sign up for freeto 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.

8 participants

@valentinewallace@codecov-commenter@AnthonyRonning@TheBlueMatt@ariard@ViktorT-11@dunxen@jkczyz
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Intercept HTLC forwards for JIT channels - #1835

Merged
TheBlueMatt merged 9 commits into
lightningdevkit:mainfrom
valentinewallace:2022-11-jit-chan-htlc-intercept
Dec 1, 2022
Merged

Intercept HTLC forwards for JIT channels #1835
TheBlueMatt merged 9 commits into
lightningdevkit:mainfrom
valentinewallace:2022-11-jit-chan-htlc-intercept

Conversation

@valentinewallace

@valentinewallacevalentinewallace commented Nov 7, 2022

Copy link
Copy Markdown
Contributor

For context, LSPs need to be able to open 0-conf JIT channels to users upon the first time the user is receiving a payment. To do this, they will put fake route hints in end user invoices that signal to LDK that this is an intercept forward, similar to phantom payments. LDK will then generate an event, giving the LSP the opportunity to open the JIT channel. The LSP can then forward the payment over the newly opened channel, or fail it.

Based on #1840
Supercedes #1601

@valentinewallace
valentinewallaceforce-pushed the 2022-11-jit-chan-htlc-intercept branch 5 times, most recently from beae304 to 90c4d75CompareNovember 7, 2022 18:42
@valentinewallacevalentinewallace mentioned this pull request Nov 7, 2022
@valentinewallace
valentinewallaceforce-pushed the 2022-11-jit-chan-htlc-intercept branch from 8e3a664 to b166af0CompareNovember 7, 2022 22:30
Comment threadlightning/src/ln/channelmanager.rs Outdated
@codecov-commenter

codecov-commenter commented Nov 7, 2022

Copy link
Copy Markdown

Codecov Report

Base: 90.70% // Head: 90.67% // Decreases project coverage by -0.02%⚠️

Coverage data is based on head (a5c5d53) compared to base (440c3ee).
Patch coverage: 84.34% of modified lines in pull request are covered.

❗ Current head a5c5d53 differs from pull request most recent head acff8f6. Consider uploading reports for the commit acff8f6 to get more accurate results

Additional details and impacted files
@@ Coverage Diff @@## main #1835 +/- ##
==========================================
- Coverage 90.70% 90.67% -0.03% 
==========================================
Files 91 91 Lines 48090 48303 +213 Branches 48090 48303 +213 ==========================================
+ Hits 43618 43800 +182 - Misses 4472 4503 +31 
Impacted FilesCoverage Δ
lightning/src/util/config.rs65.90% <0.00%> (-0.76%)⬇️
lightning/src/util/events.rs24.65% <4.16%> (-1.32%)⬇️
lightning/src/ln/channelmanager.rs86.20% <83.70%> (-0.16%)⬇️
lightning/src/ln/payment_tests.rs98.73% <97.74%> (-0.17%)⬇️
lightning/src/util/scid_utils.rs99.31% <100.00%> (+0.10%)⬆️
lightning-block-sync/src/rest.rs62.06% <0.00%> (-1.87%)⬇️
lightning-block-sync/src/rpc.rs74.80% <0.00%> (-1.14%)⬇️
lightning-block-sync/src/poll.rs86.33% <0.00%> (-0.58%)⬇️
lightning-net-tokio/src/lib.rs77.03% <0.00%> (-0.28%)⬇️
lightning-block-sync/src/lib.rs93.33% <0.00%> (-0.27%)⬇️
... and 13 more

Help us with your feedback. Take ten seconds to tell us how you rate us. Have a feature suggestion? Share it here.

☔ View full report at Codecov.
📢 Do you have feedback about the report comment? Let us know in this issue.

Comment threadlightning/src/util/events.rs Outdated
@AnthonyRonning

AnthonyRonning commented Nov 10, 2022

Copy link
Copy Markdown
Contributor

Are there plans for generic HTLC interception at all? Not dependent on the routing hints of someone else's invoice? There can still be logic into determining the type based on SCID but in general all HTLC's could still be intercepted or at least subscribed to based on type.

There are many use cases for generic HTLC interception that shouldn't depend on LDK development, here are a few:

  1. Other approaches to 0 conf JIT channel payments (something double-invoice like instead of routing hint-like)
  2. Escrow (having a router decide to continue routing to destination in order to deliver funds based on a condition)
  3. Whether or not to route payments down certain channels or at all (liquidity management, balance probe protection)
  4. Third party preimages (node not knowing the preimage but waiting for either a third party or a different application handle preimages)
  5. Hodl invoice (not advocating for long running but at least allowing for checks and processes to run for a few seconds)

You could still have SCID logic but I would love to see generic solved for first and then application specific tbh. I think that's worked really well in the LND/CLN ecosystems.

@valentinewallace

Copy link
Copy Markdown
ContributorAuthor

Are there plans for generic HTLC interception at all? Not dependent on the routing hints of someone else's invoice?

Yes, the plan is to swiftly follow up to this PR with adding general forward interception :)

(1), (4), and (5) are already supported via our PaymentReceived event, IIUC. LDK generates this event once all MPP parts arrive. Upon receipt, you can get the preimage and do whatever other desired operations you like, then call claim_funds (per the linked docs).

@valentinewallace
valentinewallaceforce-pushed the 2022-11-jit-chan-htlc-intercept branch from d763bb5 to 099533dCompareNovember 10, 2022 16:55
@valentinewallace

Copy link
Copy Markdown
ContributorAuthor

Had to rebase to get #1844.

@AnthonyRonning

Copy link
Copy Markdown
Contributor

Yes, the plan is to swiftly follow up to this PR with adding general forward interception :)

Awesome! Concept ACK from me then. I browsed through the code and the API usage sounds good to me but probably can't comment on the rest 👍

@ViktorT-11ViktorT-11 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.

First look-through generally looks good :).

Comment threadlightning/src/ln/channelmanager.rs
Comment threadlightning/src/ln/channelmanager.rs Outdated
Comment threadlightning/src/ln/channelmanager.rs
Comment threadlightning/src/ln/channelmanager.rs Outdated
Comment threadlightning/src/ln/channelmanager.rs Outdated

@TheBlueMattTheBlueMatt left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

I think we need a fallback failure on a timer. If the user screws up and loses the intercept event entirely we shouldn't just sit on the HTLC forever and get the channel force-closed.

Comment threadlightning/src/util/events.rs Outdated
Comment threadlightning/src/util/events.rs
Comment threadlightning/src/ln/channelmanager.rs Outdated
Comment threadlightning/src/ln/channelmanager.rs Outdated
Comment threadlightning/src/ln/channelmanager.rs Outdated
Comment threadlightning/src/ln/channelmanager.rs Outdated
Comment threadlightning/src/ln/channelmanager.rs Outdated
@valentinewallace

Copy link
Copy Markdown
ContributorAuthor

Great feedback once again @ViktorTigerstrom! Working on addressing it

@valentinewallace
valentinewallaceforce-pushed the 2022-11-jit-chan-htlc-intercept branch 2 times, most recently from 0759af8 to ee70d50CompareNovember 14, 2022 20:23
@valentinewallace
valentinewallaceforce-pushed the 2022-11-jit-chan-htlc-intercept branch from 72087f8 to 225a22bCompareNovember 28, 2022 20:13

@ViktorT-11ViktorT-11 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.

This looks good to me. Only real feedback I have left is that it would be valuable to include test coverage to ensure that we don't generate the PaymentIntercepted event + populate pending_intercepted_htlcs when accept_intercept_htlcs is set to false.

nodes[1].node.handle_update_add_htlc(&nodes[0].node.get_our_node_id(), &payment_event.msgs[0]);
commitment_signed_dance!(nodes[1], nodes[0], &payment_event.commitment_msg, false, true);

// Check that we generate the PaymentIntercepted event when an intercept forward is detected.

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.

Would be valuable to also have test coverage ensuring that the PaymentIntercepted event isn't generated + pending_intercepted_htlcs isn't populated when accept_intercept_htlcs is false.

@valentinewallacevalentinewallaceNov 28, 2022

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.

Gonna save that for follow-up for the sake of the size of this PR, but you can manually check that the test fails when the config change lines are commented out. FWIW, that would set a new standard of testing rigor for us since i.e. the zero-conf PR didn't/doesn't test its config.

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.

Ok fair enough :)

Comment threadlightning/src/ln/channelmanager.rs
Comment threadlightning/src/ln/channelmanager.rs
Comment threadlightning/src/ln/channelmanager.rs Outdated
_ => unreachable!(),
};
timed_out_htlcs.push((prev_hop_data, htlc.forward_info.payment_hash,
HTLCFailReason::Reason { failure_code: 0x1000 | 14, data: Vec::new() },

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

14 is definitely right here, but its an UPDATE error, so we need to include a channel_update for the outbound channel, which is obviously....unclear? I guess we could deliberately include the wrong channel's update here and use the previous-hop channel, but that's pretty nonsensical. Maybe we just temporary_node_failure?

@TheBlueMatt

Copy link
Copy Markdown
Collaborator

LGTM, I think.

@TheBlueMattTheBlueMatt added this to the 0.0.113 milestone Nov 29, 2022
@ViktorT-11

Copy link
Copy Markdown
Contributor

Looks good to me as well!

@dunxendunxen 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, just a tiny nit and question :)

payment_hash: PaymentHash,
/// How many msats were received on the inbound edge of this HTLC.
inbound_amount_msat: u64,
/// How many msats the payer intended to route to the next node. Depending on the reason you are

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.

new rust style team pls save us

Comment threadlightning/src/util/events.rs Outdated
});

failed_intercept_forwards.push((htlc_source, forward_info.payment_hash,
HTLCFailReason::Reason { failure_code: 0x4000 | 10, data: Vec::new() },

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.

not for this PR, but I've wondered whether we should collect failure code consts somewhere so it's easy to see what it is. I can create an issue if we'd want that, unless I missed some prior reasoning not to.

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.

Yeah, I think that would be nice to have!

/// [`HTLCIntercepted`]: events::Event::HTLCIntercepted
// TODO: when we move to deciding the best outbound channel at forward time, only take
// `next_node_id` and not `next_hop_channel_id`
pub fn forward_intercepted_htlc(&self, intercept_id: InterceptId, next_hop_channel_id: &[u8; 32], _next_node_id: PublicKey, amt_to_forward_msat: u64) -> Result<(), APIError> {

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 a question to check my understanding:

Is this basically the procedure for an LDK user?

  1. Calls ChannelManager::get_intercept_scid
  2. Generates invoice with intercept scid in route hints for end-user
  3. Receives an HTLCIntercepted event when the HTLC is intercepted
  4. At this point the LDK user can create a channel
  5. Then call this method to forward over that JIT channel

@ViktorT-11ViktorT-11Nov 30, 2022

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.

Yes that's my understanding, where the LDK user is the LSP in your example (nodes[1] in the test), and the end-user is nodes[2] in the test. I guess step (2) in your example doesn't necessarily need to be on the LDK user's side, as long as the Intercept scid is passed to the end-user.

@dunxendunxenNov 30, 2022

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.

Ah, I should have read the test.

Yeah I think I phrased that weirdly for (2). End user generates invoice but just shoves the scid they got from the LSP in the route hints.

valentinewallaceand others added 9 commits November 30, 2022 12:43
No htlcs are intercepted yet, that will be added in upcoming commit(s)
Co-authored-by: John Cantrell <johncantrell97@gmail.com>
Co-authored-by: Valentine Wallace <vwallace@protonmail.com>
This is useful for LSPs who wish to create a just-in-time channel for end users
receiving a lightning payment. These fake scids will be encoded into route
hints in end user invoices, and signal to LDK to create an event triggering the
JIT channel, after which the payment will be received.
Co-authored-by: John Cantrell <johncantrell97@gmail.com>
Co-authored-by: Valentine Wallace <vwallace@protonmail.com>
Used in upcoming commit(s) so users can intercept forwarded HTLCs
Co-authored-by: John Cantrell <johncantrell97@gmail.com>
Co-authored-by: Valentine Wallace <vwallace@protonmail.com>
And store the pending intercepted HTLC in pending_intercepted_htlcs
Co-authored-by: John Cantrell <johncantrell97@gmail.com>
Co-authored-by: Valentine Wallace <vwallace@protonmail.com>
See ChannelManager::forward_intercepted_htlc and
ChannelManager::get_intercept_scid for details
Co-authored-by: John Cantrell <johncantrell97@gmail.com>
Co-authored-by: Valentine Wallace <vwallace@protonmail.com>
Co-authored-by: John Cantrell <johncantrell97@gmail.com>
Co-authored-by: Valentine Wallace <vwallace@protonmail.com>
@valentinewallace
valentinewallaceforce-pushed the 2022-11-jit-chan-htlc-intercept branch from a5c5d53 to acff8f6CompareNovember 30, 2022 17:52
@valentinewallace

Copy link
Copy Markdown
ContributorAuthor

Rebased due to conflicts

@ariardariard left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

ACK acff8f6

Reviewed code changes since last diff, and also checked test coverage. Remaining comments are minor.

let next_hop_scid = match self.channel_state.lock().unwrap().by_id.get(next_hop_channel_id) {
Some(chan) => {
if !chan.is_usable() {
return Err(APIError::APIMisuseError {

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

We have APIError::ChannelUnavailable in fact, could be used.

let _persistence_guard = PersistenceNotifierGuard::notify_on_drop(&self.total_consistency_lock, &self.persistence_notifier);

let payment = self.pending_intercepted_htlcs.lock().unwrap().remove(&intercept_id)
.ok_or_else(|| APIError::APIMisuseError {

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Mutating this line does not break intercepted_payment

@TheBlueMattTheBlueMatt left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

LGTM, gonna land to get the conflicts out of the way but please address the two issues @ariard noted and the below one in a followup.

};
connect_block(&nodes[0], &block);
connect_block(&nodes[1], &block);
let block_count = 183; // find_route adds a random CLTV offset, so hardcode rather than summing consts

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

It adds a random value in a range, though, so we should still be able to sum consts. Please change it to summing consts cause otherwise our entire test suite fails any time we change any constant :(

Note that if you use the get_route method it won't add the random value, as well.

Sign up for freeto 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.

8 participants

@valentinewallace@codecov-commenter@AnthonyRonning@TheBlueMatt@ariard@ViktorT-11@dunxen@jkczyz
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length > 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Intercept HTLC forwards for JIT channels - #1835

Merged
TheBlueMatt merged 9 commits into
lightningdevkit:mainfrom
valentinewallace:2022-11-jit-chan-htlc-intercept
Dec 1, 2022
Merged

Intercept HTLC forwards for JIT channels #1835
TheBlueMatt merged 9 commits into
lightningdevkit:mainfrom
valentinewallace:2022-11-jit-chan-htlc-intercept

Conversation

@valentinewallace

@valentinewallacevalentinewallace commented Nov 7, 2022

Copy link
Copy Markdown
Contributor

For context, LSPs need to be able to open 0-conf JIT channels to users upon the first time the user is receiving a payment. To do this, they will put fake route hints in end user invoices that signal to LDK that this is an intercept forward, similar to phantom payments. LDK will then generate an event, giving the LSP the opportunity to open the JIT channel. The LSP can then forward the payment over the newly opened channel, or fail it.

Based on #1840
Supercedes #1601

@valentinewallace
valentinewallaceforce-pushed the 2022-11-jit-chan-htlc-intercept branch 5 times, most recently from beae304 to 90c4d75CompareNovember 7, 2022 18:42
@valentinewallacevalentinewallace mentioned this pull request Nov 7, 2022
@valentinewallace
valentinewallaceforce-pushed the 2022-11-jit-chan-htlc-intercept branch from 8e3a664 to b166af0CompareNovember 7, 2022 22:30
Comment threadlightning/src/ln/channelmanager.rs Outdated
@codecov-commenter

codecov-commenter commented Nov 7, 2022

Copy link
Copy Markdown

Codecov Report

Base: 90.70% // Head: 90.67% // Decreases project coverage by -0.02%⚠️

Coverage data is based on head (a5c5d53) compared to base (440c3ee).
Patch coverage: 84.34% of modified lines in pull request are covered.

❗ Current head a5c5d53 differs from pull request most recent head acff8f6. Consider uploading reports for the commit acff8f6 to get more accurate results

Additional details and impacted files
@@ Coverage Diff @@## main #1835 +/- ##
==========================================
- Coverage 90.70% 90.67% -0.03% 
==========================================
Files 91 91 Lines 48090 48303 +213 Branches 48090 48303 +213 ==========================================
+ Hits 43618 43800 +182 - Misses 4472 4503 +31 
Impacted FilesCoverage Δ
lightning/src/util/config.rs65.90% <0.00%> (-0.76%)⬇️
lightning/src/util/events.rs24.65% <4.16%> (-1.32%)⬇️
lightning/src/ln/channelmanager.rs86.20% <83.70%> (-0.16%)⬇️
lightning/src/ln/payment_tests.rs98.73% <97.74%> (-0.17%)⬇️
lightning/src/util/scid_utils.rs99.31% <100.00%> (+0.10%)⬆️
lightning-block-sync/src/rest.rs62.06% <0.00%> (-1.87%)⬇️
lightning-block-sync/src/rpc.rs74.80% <0.00%> (-1.14%)⬇️
lightning-block-sync/src/poll.rs86.33% <0.00%> (-0.58%)⬇️
lightning-net-tokio/src/lib.rs77.03% <0.00%> (-0.28%)⬇️
lightning-block-sync/src/lib.rs93.33% <0.00%> (-0.27%)⬇️
... and 13 more

Help us with your feedback. Take ten seconds to tell us how you rate us. Have a feature suggestion? Share it here.

☔ View full report at Codecov.
📢 Do you have feedback about the report comment? Let us know in this issue.

Comment threadlightning/src/util/events.rs Outdated
@AnthonyRonning

AnthonyRonning commented Nov 10, 2022

Copy link
Copy Markdown
Contributor

Are there plans for generic HTLC interception at all? Not dependent on the routing hints of someone else's invoice? There can still be logic into determining the type based on SCID but in general all HTLC's could still be intercepted or at least subscribed to based on type.

There are many use cases for generic HTLC interception that shouldn't depend on LDK development, here are a few:

  1. Other approaches to 0 conf JIT channel payments (something double-invoice like instead of routing hint-like)
  2. Escrow (having a router decide to continue routing to destination in order to deliver funds based on a condition)
  3. Whether or not to route payments down certain channels or at all (liquidity management, balance probe protection)
  4. Third party preimages (node not knowing the preimage but waiting for either a third party or a different application handle preimages)
  5. Hodl invoice (not advocating for long running but at least allowing for checks and processes to run for a few seconds)

You could still have SCID logic but I would love to see generic solved for first and then application specific tbh. I think that's worked really well in the LND/CLN ecosystems.

@valentinewallace

Copy link
Copy Markdown
ContributorAuthor

Are there plans for generic HTLC interception at all? Not dependent on the routing hints of someone else's invoice?

Yes, the plan is to swiftly follow up to this PR with adding general forward interception :)

(1), (4), and (5) are already supported via our PaymentReceived event, IIUC. LDK generates this event once all MPP parts arrive. Upon receipt, you can get the preimage and do whatever other desired operations you like, then call claim_funds (per the linked docs).

@valentinewallace
valentinewallaceforce-pushed the 2022-11-jit-chan-htlc-intercept branch from d763bb5 to 099533dCompareNovember 10, 2022 16:55
@valentinewallace

Copy link
Copy Markdown
ContributorAuthor

Had to rebase to get #1844.

@AnthonyRonning

Copy link
Copy Markdown
Contributor

Yes, the plan is to swiftly follow up to this PR with adding general forward interception :)

Awesome! Concept ACK from me then. I browsed through the code and the API usage sounds good to me but probably can't comment on the rest 👍

@ViktorT-11ViktorT-11 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.

First look-through generally looks good :).

Comment threadlightning/src/ln/channelmanager.rs
Comment threadlightning/src/ln/channelmanager.rs Outdated
Comment threadlightning/src/ln/channelmanager.rs
Comment threadlightning/src/ln/channelmanager.rs Outdated
Comment threadlightning/src/ln/channelmanager.rs Outdated

@TheBlueMattTheBlueMatt left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

I think we need a fallback failure on a timer. If the user screws up and loses the intercept event entirely we shouldn't just sit on the HTLC forever and get the channel force-closed.

Comment threadlightning/src/util/events.rs Outdated
Comment threadlightning/src/util/events.rs
Comment threadlightning/src/ln/channelmanager.rs Outdated
Comment threadlightning/src/ln/channelmanager.rs Outdated
Comment threadlightning/src/ln/channelmanager.rs Outdated
Comment threadlightning/src/ln/channelmanager.rs Outdated
Comment threadlightning/src/ln/channelmanager.rs Outdated
@valentinewallace

Copy link
Copy Markdown
ContributorAuthor

Great feedback once again @ViktorTigerstrom! Working on addressing it

@valentinewallace
valentinewallaceforce-pushed the 2022-11-jit-chan-htlc-intercept branch 2 times, most recently from 0759af8 to ee70d50CompareNovember 14, 2022 20:23
@valentinewallace
valentinewallaceforce-pushed the 2022-11-jit-chan-htlc-intercept branch from 72087f8 to 225a22bCompareNovember 28, 2022 20:13

@ViktorT-11ViktorT-11 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.

This looks good to me. Only real feedback I have left is that it would be valuable to include test coverage to ensure that we don't generate the PaymentIntercepted event + populate pending_intercepted_htlcs when accept_intercept_htlcs is set to false.

nodes[1].node.handle_update_add_htlc(&nodes[0].node.get_our_node_id(), &payment_event.msgs[0]);
commitment_signed_dance!(nodes[1], nodes[0], &payment_event.commitment_msg, false, true);

// Check that we generate the PaymentIntercepted event when an intercept forward is detected.

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.

Would be valuable to also have test coverage ensuring that the PaymentIntercepted event isn't generated + pending_intercepted_htlcs isn't populated when accept_intercept_htlcs is false.

@valentinewallacevalentinewallaceNov 28, 2022

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.

Gonna save that for follow-up for the sake of the size of this PR, but you can manually check that the test fails when the config change lines are commented out. FWIW, that would set a new standard of testing rigor for us since i.e. the zero-conf PR didn't/doesn't test its config.

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.

Ok fair enough :)

Comment threadlightning/src/ln/channelmanager.rs
Comment threadlightning/src/ln/channelmanager.rs
Comment threadlightning/src/ln/channelmanager.rs Outdated
_ => unreachable!(),
};
timed_out_htlcs.push((prev_hop_data, htlc.forward_info.payment_hash,
HTLCFailReason::Reason { failure_code: 0x1000 | 14, data: Vec::new() },

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

14 is definitely right here, but its an UPDATE error, so we need to include a channel_update for the outbound channel, which is obviously....unclear? I guess we could deliberately include the wrong channel's update here and use the previous-hop channel, but that's pretty nonsensical. Maybe we just temporary_node_failure?

@TheBlueMatt

Copy link
Copy Markdown
Collaborator

LGTM, I think.

@TheBlueMattTheBlueMatt added this to the 0.0.113 milestone Nov 29, 2022
@ViktorT-11

Copy link
Copy Markdown
Contributor

Looks good to me as well!

@dunxendunxen 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, just a tiny nit and question :)

payment_hash: PaymentHash,
/// How many msats were received on the inbound edge of this HTLC.
inbound_amount_msat: u64,
/// How many msats the payer intended to route to the next node. Depending on the reason you are

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.

new rust style team pls save us

Comment threadlightning/src/util/events.rs Outdated
});

failed_intercept_forwards.push((htlc_source, forward_info.payment_hash,
HTLCFailReason::Reason { failure_code: 0x4000 | 10, data: Vec::new() },

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.

not for this PR, but I've wondered whether we should collect failure code consts somewhere so it's easy to see what it is. I can create an issue if we'd want that, unless I missed some prior reasoning not to.

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.

Yeah, I think that would be nice to have!

/// [`HTLCIntercepted`]: events::Event::HTLCIntercepted
// TODO: when we move to deciding the best outbound channel at forward time, only take
// `next_node_id` and not `next_hop_channel_id`
pub fn forward_intercepted_htlc(&self, intercept_id: InterceptId, next_hop_channel_id: &[u8; 32], _next_node_id: PublicKey, amt_to_forward_msat: u64) -> Result<(), APIError> {

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 a question to check my understanding:

Is this basically the procedure for an LDK user?

  1. Calls ChannelManager::get_intercept_scid
  2. Generates invoice with intercept scid in route hints for end-user
  3. Receives an HTLCIntercepted event when the HTLC is intercepted
  4. At this point the LDK user can create a channel
  5. Then call this method to forward over that JIT channel

@ViktorT-11ViktorT-11Nov 30, 2022

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.

Yes that's my understanding, where the LDK user is the LSP in your example (nodes[1] in the test), and the end-user is nodes[2] in the test. I guess step (2) in your example doesn't necessarily need to be on the LDK user's side, as long as the Intercept scid is passed to the end-user.

@dunxendunxenNov 30, 2022

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.

Ah, I should have read the test.

Yeah I think I phrased that weirdly for (2). End user generates invoice but just shoves the scid they got from the LSP in the route hints.

valentinewallaceand others added 9 commits November 30, 2022 12:43
No htlcs are intercepted yet, that will be added in upcoming commit(s)
Co-authored-by: John Cantrell <johncantrell97@gmail.com>
Co-authored-by: Valentine Wallace <vwallace@protonmail.com>
This is useful for LSPs who wish to create a just-in-time channel for end users
receiving a lightning payment. These fake scids will be encoded into route
hints in end user invoices, and signal to LDK to create an event triggering the
JIT channel, after which the payment will be received.
Co-authored-by: John Cantrell <johncantrell97@gmail.com>
Co-authored-by: Valentine Wallace <vwallace@protonmail.com>
Used in upcoming commit(s) so users can intercept forwarded HTLCs
Co-authored-by: John Cantrell <johncantrell97@gmail.com>
Co-authored-by: Valentine Wallace <vwallace@protonmail.com>
And store the pending intercepted HTLC in pending_intercepted_htlcs
Co-authored-by: John Cantrell <johncantrell97@gmail.com>
Co-authored-by: Valentine Wallace <vwallace@protonmail.com>
See ChannelManager::forward_intercepted_htlc and
ChannelManager::get_intercept_scid for details
Co-authored-by: John Cantrell <johncantrell97@gmail.com>
Co-authored-by: Valentine Wallace <vwallace@protonmail.com>
Co-authored-by: John Cantrell <johncantrell97@gmail.com>
Co-authored-by: Valentine Wallace <vwallace@protonmail.com>
@valentinewallace
valentinewallaceforce-pushed the 2022-11-jit-chan-htlc-intercept branch from a5c5d53 to acff8f6CompareNovember 30, 2022 17:52
@valentinewallace

Copy link
Copy Markdown
ContributorAuthor

Rebased due to conflicts

@ariardariard left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

ACK acff8f6

Reviewed code changes since last diff, and also checked test coverage. Remaining comments are minor.

let next_hop_scid = match self.channel_state.lock().unwrap().by_id.get(next_hop_channel_id) {
Some(chan) => {
if !chan.is_usable() {
return Err(APIError::APIMisuseError {

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

We have APIError::ChannelUnavailable in fact, could be used.

let _persistence_guard = PersistenceNotifierGuard::notify_on_drop(&self.total_consistency_lock, &self.persistence_notifier);

let payment = self.pending_intercepted_htlcs.lock().unwrap().remove(&intercept_id)
.ok_or_else(|| APIError::APIMisuseError {

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Mutating this line does not break intercepted_payment

@TheBlueMattTheBlueMatt left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

LGTM, gonna land to get the conflicts out of the way but please address the two issues @ariard noted and the below one in a followup.

};
connect_block(&nodes[0], &block);
connect_block(&nodes[1], &block);
let block_count = 183; // find_route adds a random CLTV offset, so hardcode rather than summing consts

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

It adds a random value in a range, though, so we should still be able to sum consts. Please change it to summing consts cause otherwise our entire test suite fails any time we change any constant :(

Note that if you use the get_route method it won't add the random value, as well.

Sign up for freeto 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.

8 participants

@valentinewallace@codecov-commenter@AnthonyRonning@TheBlueMatt@ariard@ViktorT-11@dunxen@jkczyz
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content

Intercept HTLC forwards for JIT channels - #1835

Merged
TheBlueMatt merged 9 commits into
lightningdevkit:mainfrom
valentinewallace:2022-11-jit-chan-htlc-intercept
Dec 1, 2022
Merged

Intercept HTLC forwards for JIT channels #1835
TheBlueMatt merged 9 commits into
lightningdevkit:mainfrom
valentinewallace:2022-11-jit-chan-htlc-intercept

Conversation

@valentinewallace

@valentinewallacevalentinewallace commented Nov 7, 2022

Copy link
Copy Markdown
Contributor

For context, LSPs need to be able to open 0-conf JIT channels to users upon the first time the user is receiving a payment. To do this, they will put fake route hints in end user invoices that signal to LDK that this is an intercept forward, similar to phantom payments. LDK will then generate an event, giving the LSP the opportunity to open the JIT channel. The LSP can then forward the payment over the newly opened channel, or fail it.

Based on #1840
Supercedes #1601

@valentinewallace
valentinewallaceforce-pushed the 2022-11-jit-chan-htlc-intercept branch 5 times, most recently from beae304 to 90c4d75CompareNovember 7, 2022 18:42
@valentinewallacevalentinewallace mentioned this pull request Nov 7, 2022
@valentinewallace
valentinewallaceforce-pushed the 2022-11-jit-chan-htlc-intercept branch from 8e3a664 to b166af0CompareNovember 7, 2022 22:30
Comment threadlightning/src/ln/channelmanager.rs Outdated
@codecov-commenter

codecov-commenter commented Nov 7, 2022

Copy link
Copy Markdown

Codecov Report

Base: 90.70% // Head: 90.67% // Decreases project coverage by -0.02%⚠️

Coverage data is based on head (a5c5d53) compared to base (440c3ee).
Patch coverage: 84.34% of modified lines in pull request are covered.

❗ Current head a5c5d53 differs from pull request most recent head acff8f6. Consider uploading reports for the commit acff8f6 to get more accurate results

Additional details and impacted files
@@ Coverage Diff @@## main #1835 +/- ##
==========================================
- Coverage 90.70% 90.67% -0.03% 
==========================================
Files 91 91 Lines 48090 48303 +213 Branches 48090 48303 +213 ==========================================
+ Hits 43618 43800 +182 - Misses 4472 4503 +31 
Impacted FilesCoverage Δ
lightning/src/util/config.rs65.90% <0.00%> (-0.76%)⬇️
lightning/src/util/events.rs24.65% <4.16%> (-1.32%)⬇️
lightning/src/ln/channelmanager.rs86.20% <83.70%> (-0.16%)⬇️
lightning/src/ln/payment_tests.rs98.73% <97.74%> (-0.17%)⬇️
lightning/src/util/scid_utils.rs99.31% <100.00%> (+0.10%)⬆️
lightning-block-sync/src/rest.rs62.06% <0.00%> (-1.87%)⬇️
lightning-block-sync/src/rpc.rs74.80% <0.00%> (-1.14%)⬇️
lightning-block-sync/src/poll.rs86.33% <0.00%> (-0.58%)⬇️
lightning-net-tokio/src/lib.rs77.03% <0.00%> (-0.28%)⬇️
lightning-block-sync/src/lib.rs93.33% <0.00%> (-0.27%)⬇️
... and 13 more

Help us with your feedback. Take ten seconds to tell us how you rate us. Have a feature suggestion? Share it here.

☔ View full report at Codecov.
📢 Do you have feedback about the report comment? Let us know in this issue.

Comment threadlightning/src/util/events.rs Outdated
@AnthonyRonning

AnthonyRonning commented Nov 10, 2022

Copy link
Copy Markdown
Contributor

Are there plans for generic HTLC interception at all? Not dependent on the routing hints of someone else's invoice? There can still be logic into determining the type based on SCID but in general all HTLC's could still be intercepted or at least subscribed to based on type.

There are many use cases for generic HTLC interception that shouldn't depend on LDK development, here are a few:

  1. Other approaches to 0 conf JIT channel payments (something double-invoice like instead of routing hint-like)
  2. Escrow (having a router decide to continue routing to destination in order to deliver funds based on a condition)
  3. Whether or not to route payments down certain channels or at all (liquidity management, balance probe protection)
  4. Third party preimages (node not knowing the preimage but waiting for either a third party or a different application handle preimages)
  5. Hodl invoice (not advocating for long running but at least allowing for checks and processes to run for a few seconds)

You could still have SCID logic but I would love to see generic solved for first and then application specific tbh. I think that's worked really well in the LND/CLN ecosystems.

@valentinewallace

Copy link
Copy Markdown
ContributorAuthor

Are there plans for generic HTLC interception at all? Not dependent on the routing hints of someone else's invoice?

Yes, the plan is to swiftly follow up to this PR with adding general forward interception :)

(1), (4), and (5) are already supported via our PaymentReceived event, IIUC. LDK generates this event once all MPP parts arrive. Upon receipt, you can get the preimage and do whatever other desired operations you like, then call claim_funds (per the linked docs).

@valentinewallace
valentinewallaceforce-pushed the 2022-11-jit-chan-htlc-intercept branch from d763bb5 to 099533dCompareNovember 10, 2022 16:55
@valentinewallace

Copy link
Copy Markdown
ContributorAuthor

Had to rebase to get #1844.

@AnthonyRonning

Copy link
Copy Markdown
Contributor

Yes, the plan is to swiftly follow up to this PR with adding general forward interception :)

Awesome! Concept ACK from me then. I browsed through the code and the API usage sounds good to me but probably can't comment on the rest 👍

@ViktorT-11ViktorT-11 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.

First look-through generally looks good :).

Comment threadlightning/src/ln/channelmanager.rs
Comment threadlightning/src/ln/channelmanager.rs Outdated
Comment threadlightning/src/ln/channelmanager.rs
Comment threadlightning/src/ln/channelmanager.rs Outdated
Comment threadlightning/src/ln/channelmanager.rs Outdated

@TheBlueMattTheBlueMatt left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

I think we need a fallback failure on a timer. If the user screws up and loses the intercept event entirely we shouldn't just sit on the HTLC forever and get the channel force-closed.

Comment threadlightning/src/util/events.rs Outdated
Comment threadlightning/src/util/events.rs
Comment threadlightning/src/ln/channelmanager.rs Outdated
Comment threadlightning/src/ln/channelmanager.rs Outdated
Comment threadlightning/src/ln/channelmanager.rs Outdated
Comment threadlightning/src/ln/channelmanager.rs Outdated
Comment threadlightning/src/ln/channelmanager.rs Outdated
@valentinewallace

Copy link
Copy Markdown
ContributorAuthor

Great feedback once again @ViktorTigerstrom! Working on addressing it

@valentinewallace
valentinewallaceforce-pushed the 2022-11-jit-chan-htlc-intercept branch 2 times, most recently from 0759af8 to ee70d50CompareNovember 14, 2022 20:23
@valentinewallace
valentinewallaceforce-pushed the 2022-11-jit-chan-htlc-intercept branch from 72087f8 to 225a22bCompareNovember 28, 2022 20:13

@ViktorT-11ViktorT-11 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.

This looks good to me. Only real feedback I have left is that it would be valuable to include test coverage to ensure that we don't generate the PaymentIntercepted event + populate pending_intercepted_htlcs when accept_intercept_htlcs is set to false.

nodes[1].node.handle_update_add_htlc(&nodes[0].node.get_our_node_id(), &payment_event.msgs[0]);
commitment_signed_dance!(nodes[1], nodes[0], &payment_event.commitment_msg, false, true);

// Check that we generate the PaymentIntercepted event when an intercept forward is detected.

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.

Would be valuable to also have test coverage ensuring that the PaymentIntercepted event isn't generated + pending_intercepted_htlcs isn't populated when accept_intercept_htlcs is false.

@valentinewallacevalentinewallaceNov 28, 2022

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.

Gonna save that for follow-up for the sake of the size of this PR, but you can manually check that the test fails when the config change lines are commented out. FWIW, that would set a new standard of testing rigor for us since i.e. the zero-conf PR didn't/doesn't test its config.

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.

Ok fair enough :)

Comment threadlightning/src/ln/channelmanager.rs
Comment threadlightning/src/ln/channelmanager.rs
Comment threadlightning/src/ln/channelmanager.rs Outdated
_ => unreachable!(),
};
timed_out_htlcs.push((prev_hop_data, htlc.forward_info.payment_hash,
HTLCFailReason::Reason { failure_code: 0x1000 | 14, data: Vec::new() },

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

14 is definitely right here, but its an UPDATE error, so we need to include a channel_update for the outbound channel, which is obviously....unclear? I guess we could deliberately include the wrong channel's update here and use the previous-hop channel, but that's pretty nonsensical. Maybe we just temporary_node_failure?

@TheBlueMatt

Copy link
Copy Markdown
Collaborator

LGTM, I think.

@TheBlueMattTheBlueMatt added this to the 0.0.113 milestone Nov 29, 2022
@ViktorT-11

Copy link
Copy Markdown
Contributor

Looks good to me as well!

@dunxendunxen 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, just a tiny nit and question :)

payment_hash: PaymentHash,
/// How many msats were received on the inbound edge of this HTLC.
inbound_amount_msat: u64,
/// How many msats the payer intended to route to the next node. Depending on the reason you are

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.

new rust style team pls save us

Comment threadlightning/src/util/events.rs Outdated
});

failed_intercept_forwards.push((htlc_source, forward_info.payment_hash,
HTLCFailReason::Reason { failure_code: 0x4000 | 10, data: Vec::new() },

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.

not for this PR, but I've wondered whether we should collect failure code consts somewhere so it's easy to see what it is. I can create an issue if we'd want that, unless I missed some prior reasoning not to.

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.

Yeah, I think that would be nice to have!

/// [`HTLCIntercepted`]: events::Event::HTLCIntercepted
// TODO: when we move to deciding the best outbound channel at forward time, only take
// `next_node_id` and not `next_hop_channel_id`
pub fn forward_intercepted_htlc(&self, intercept_id: InterceptId, next_hop_channel_id: &[u8; 32], _next_node_id: PublicKey, amt_to_forward_msat: u64) -> Result<(), APIError> {

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 a question to check my understanding:

Is this basically the procedure for an LDK user?

  1. Calls ChannelManager::get_intercept_scid
  2. Generates invoice with intercept scid in route hints for end-user
  3. Receives an HTLCIntercepted event when the HTLC is intercepted
  4. At this point the LDK user can create a channel
  5. Then call this method to forward over that JIT channel

@ViktorT-11ViktorT-11Nov 30, 2022

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.

Yes that's my understanding, where the LDK user is the LSP in your example (nodes[1] in the test), and the end-user is nodes[2] in the test. I guess step (2) in your example doesn't necessarily need to be on the LDK user's side, as long as the Intercept scid is passed to the end-user.

@dunxendunxenNov 30, 2022

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.

Ah, I should have read the test.

Yeah I think I phrased that weirdly for (2). End user generates invoice but just shoves the scid they got from the LSP in the route hints.

valentinewallaceand others added 9 commits November 30, 2022 12:43
No htlcs are intercepted yet, that will be added in upcoming commit(s)
Co-authored-by: John Cantrell <johncantrell97@gmail.com>
Co-authored-by: Valentine Wallace <vwallace@protonmail.com>
This is useful for LSPs who wish to create a just-in-time channel for end users
receiving a lightning payment. These fake scids will be encoded into route
hints in end user invoices, and signal to LDK to create an event triggering the
JIT channel, after which the payment will be received.
Co-authored-by: John Cantrell <johncantrell97@gmail.com>
Co-authored-by: Valentine Wallace <vwallace@protonmail.com>
Used in upcoming commit(s) so users can intercept forwarded HTLCs
Co-authored-by: John Cantrell <johncantrell97@gmail.com>
Co-authored-by: Valentine Wallace <vwallace@protonmail.com>
And store the pending intercepted HTLC in pending_intercepted_htlcs
Co-authored-by: John Cantrell <johncantrell97@gmail.com>
Co-authored-by: Valentine Wallace <vwallace@protonmail.com>
See ChannelManager::forward_intercepted_htlc and
ChannelManager::get_intercept_scid for details
Co-authored-by: John Cantrell <johncantrell97@gmail.com>
Co-authored-by: Valentine Wallace <vwallace@protonmail.com>
Co-authored-by: John Cantrell <johncantrell97@gmail.com>
Co-authored-by: Valentine Wallace <vwallace@protonmail.com>
@valentinewallace
valentinewallaceforce-pushed the 2022-11-jit-chan-htlc-intercept branch from a5c5d53 to acff8f6CompareNovember 30, 2022 17:52
@valentinewallace

Copy link
Copy Markdown
ContributorAuthor

Rebased due to conflicts

@ariardariard left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

ACK acff8f6

Reviewed code changes since last diff, and also checked test coverage. Remaining comments are minor.

let next_hop_scid = match self.channel_state.lock().unwrap().by_id.get(next_hop_channel_id) {
Some(chan) => {
if !chan.is_usable() {
return Err(APIError::APIMisuseError {

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

We have APIError::ChannelUnavailable in fact, could be used.

let _persistence_guard = PersistenceNotifierGuard::notify_on_drop(&self.total_consistency_lock, &self.persistence_notifier);

let payment = self.pending_intercepted_htlcs.lock().unwrap().remove(&intercept_id)
.ok_or_else(|| APIError::APIMisuseError {

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Mutating this line does not break intercepted_payment

@TheBlueMattTheBlueMatt left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

LGTM, gonna land to get the conflicts out of the way but please address the two issues @ariard noted and the below one in a followup.

};
connect_block(&nodes[0], &block);
connect_block(&nodes[1], &block);
let block_count = 183; // find_route adds a random CLTV offset, so hardcode rather than summing consts

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

It adds a random value in a range, though, so we should still be able to sum consts. Please change it to summing consts cause otherwise our entire test suite fails any time we change any constant :(

Note that if you use the get_route method it won't add the random value, as well.

Sign up for freeto 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.

8 participants

@valentinewallace@codecov-commenter@AnthonyRonning@TheBlueMatt@ariard@ViktorT-11@dunxen@jkczyz
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Intercept HTLC forwards for JIT channels - #1835

Merged
TheBlueMatt merged 9 commits into
lightningdevkit:mainfrom
valentinewallace:2022-11-jit-chan-htlc-intercept
Dec 1, 2022
Merged

Intercept HTLC forwards for JIT channels #1835
TheBlueMatt merged 9 commits into
lightningdevkit:mainfrom
valentinewallace:2022-11-jit-chan-htlc-intercept

Conversation

@valentinewallace

@valentinewallacevalentinewallace commented Nov 7, 2022

Copy link
Copy Markdown
Contributor

For context, LSPs need to be able to open 0-conf JIT channels to users upon the first time the user is receiving a payment. To do this, they will put fake route hints in end user invoices that signal to LDK that this is an intercept forward, similar to phantom payments. LDK will then generate an event, giving the LSP the opportunity to open the JIT channel. The LSP can then forward the payment over the newly opened channel, or fail it.

Based on #1840
Supercedes #1601

@valentinewallace
valentinewallaceforce-pushed the 2022-11-jit-chan-htlc-intercept branch 5 times, most recently from beae304 to 90c4d75CompareNovember 7, 2022 18:42
@valentinewallacevalentinewallace mentioned this pull request Nov 7, 2022
@valentinewallace
valentinewallaceforce-pushed the 2022-11-jit-chan-htlc-intercept branch from 8e3a664 to b166af0CompareNovember 7, 2022 22:30
Comment threadlightning/src/ln/channelmanager.rs Outdated
@codecov-commenter

codecov-commenter commented Nov 7, 2022

Copy link
Copy Markdown

Codecov Report

Base: 90.70% // Head: 90.67% // Decreases project coverage by -0.02%⚠️

Coverage data is based on head (a5c5d53) compared to base (440c3ee).
Patch coverage: 84.34% of modified lines in pull request are covered.

❗ Current head a5c5d53 differs from pull request most recent head acff8f6. Consider uploading reports for the commit acff8f6 to get more accurate results

Additional details and impacted files
@@ Coverage Diff @@## main #1835 +/- ##
==========================================
- Coverage 90.70% 90.67% -0.03% 
==========================================
Files 91 91 Lines 48090 48303 +213 Branches 48090 48303 +213 ==========================================
+ Hits 43618 43800 +182 - Misses 4472 4503 +31 
Impacted FilesCoverage Δ
lightning/src/util/config.rs65.90% <0.00%> (-0.76%)⬇️
lightning/src/util/events.rs24.65% <4.16%> (-1.32%)⬇️
lightning/src/ln/channelmanager.rs86.20% <83.70%> (-0.16%)⬇️
lightning/src/ln/payment_tests.rs98.73% <97.74%> (-0.17%)⬇️
lightning/src/util/scid_utils.rs99.31% <100.00%> (+0.10%)⬆️
lightning-block-sync/src/rest.rs62.06% <0.00%> (-1.87%)⬇️
lightning-block-sync/src/rpc.rs74.80% <0.00%> (-1.14%)⬇️
lightning-block-sync/src/poll.rs86.33% <0.00%> (-0.58%)⬇️
lightning-net-tokio/src/lib.rs77.03% <0.00%> (-0.28%)⬇️
lightning-block-sync/src/lib.rs93.33% <0.00%> (-0.27%)⬇️
... and 13 more

Help us with your feedback. Take ten seconds to tell us how you rate us. Have a feature suggestion? Share it here.

☔ View full report at Codecov.
📢 Do you have feedback about the report comment? Let us know in this issue.

Comment threadlightning/src/util/events.rs Outdated
@AnthonyRonning

AnthonyRonning commented Nov 10, 2022

Copy link
Copy Markdown
Contributor

Are there plans for generic HTLC interception at all? Not dependent on the routing hints of someone else's invoice? There can still be logic into determining the type based on SCID but in general all HTLC's could still be intercepted or at least subscribed to based on type.

There are many use cases for generic HTLC interception that shouldn't depend on LDK development, here are a few:

  1. Other approaches to 0 conf JIT channel payments (something double-invoice like instead of routing hint-like)
  2. Escrow (having a router decide to continue routing to destination in order to deliver funds based on a condition)
  3. Whether or not to route payments down certain channels or at all (liquidity management, balance probe protection)
  4. Third party preimages (node not knowing the preimage but waiting for either a third party or a different application handle preimages)
  5. Hodl invoice (not advocating for long running but at least allowing for checks and processes to run for a few seconds)

You could still have SCID logic but I would love to see generic solved for first and then application specific tbh. I think that's worked really well in the LND/CLN ecosystems.

@valentinewallace

Copy link
Copy Markdown
ContributorAuthor

Are there plans for generic HTLC interception at all? Not dependent on the routing hints of someone else's invoice?

Yes, the plan is to swiftly follow up to this PR with adding general forward interception :)

(1), (4), and (5) are already supported via our PaymentReceived event, IIUC. LDK generates this event once all MPP parts arrive. Upon receipt, you can get the preimage and do whatever other desired operations you like, then call claim_funds (per the linked docs).

@valentinewallace
valentinewallaceforce-pushed the 2022-11-jit-chan-htlc-intercept branch from d763bb5 to 099533dCompareNovember 10, 2022 16:55
@valentinewallace

Copy link
Copy Markdown
ContributorAuthor

Had to rebase to get #1844.

@AnthonyRonning

Copy link
Copy Markdown
Contributor

Yes, the plan is to swiftly follow up to this PR with adding general forward interception :)

Awesome! Concept ACK from me then. I browsed through the code and the API usage sounds good to me but probably can't comment on the rest 👍

@ViktorT-11ViktorT-11 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.

First look-through generally looks good :).

Comment threadlightning/src/ln/channelmanager.rs
Comment threadlightning/src/ln/channelmanager.rs Outdated
Comment threadlightning/src/ln/channelmanager.rs
Comment threadlightning/src/ln/channelmanager.rs Outdated
Comment threadlightning/src/ln/channelmanager.rs Outdated

@TheBlueMattTheBlueMatt left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

I think we need a fallback failure on a timer. If the user screws up and loses the intercept event entirely we shouldn't just sit on the HTLC forever and get the channel force-closed.

Comment threadlightning/src/util/events.rs Outdated
Comment threadlightning/src/util/events.rs
Comment threadlightning/src/ln/channelmanager.rs Outdated
Comment threadlightning/src/ln/channelmanager.rs Outdated
Comment threadlightning/src/ln/channelmanager.rs Outdated
Comment threadlightning/src/ln/channelmanager.rs Outdated
Comment threadlightning/src/ln/channelmanager.rs Outdated
@valentinewallace

Copy link
Copy Markdown
ContributorAuthor

Great feedback once again @ViktorTigerstrom! Working on addressing it

@valentinewallace
valentinewallaceforce-pushed the 2022-11-jit-chan-htlc-intercept branch 2 times, most recently from 0759af8 to ee70d50CompareNovember 14, 2022 20:23
@valentinewallace
valentinewallaceforce-pushed the 2022-11-jit-chan-htlc-intercept branch from 72087f8 to 225a22bCompareNovember 28, 2022 20:13

@ViktorT-11ViktorT-11 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.

This looks good to me. Only real feedback I have left is that it would be valuable to include test coverage to ensure that we don't generate the PaymentIntercepted event + populate pending_intercepted_htlcs when accept_intercept_htlcs is set to false.

nodes[1].node.handle_update_add_htlc(&nodes[0].node.get_our_node_id(), &payment_event.msgs[0]);
commitment_signed_dance!(nodes[1], nodes[0], &payment_event.commitment_msg, false, true);

// Check that we generate the PaymentIntercepted event when an intercept forward is detected.

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.

Would be valuable to also have test coverage ensuring that the PaymentIntercepted event isn't generated + pending_intercepted_htlcs isn't populated when accept_intercept_htlcs is false.

@valentinewallacevalentinewallaceNov 28, 2022

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.

Gonna save that for follow-up for the sake of the size of this PR, but you can manually check that the test fails when the config change lines are commented out. FWIW, that would set a new standard of testing rigor for us since i.e. the zero-conf PR didn't/doesn't test its config.

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.

Ok fair enough :)

Comment threadlightning/src/ln/channelmanager.rs
Comment threadlightning/src/ln/channelmanager.rs
Comment threadlightning/src/ln/channelmanager.rs Outdated
_ => unreachable!(),
};
timed_out_htlcs.push((prev_hop_data, htlc.forward_info.payment_hash,
HTLCFailReason::Reason { failure_code: 0x1000 | 14, data: Vec::new() },

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

14 is definitely right here, but its an UPDATE error, so we need to include a channel_update for the outbound channel, which is obviously....unclear? I guess we could deliberately include the wrong channel's update here and use the previous-hop channel, but that's pretty nonsensical. Maybe we just temporary_node_failure?

@TheBlueMatt

Copy link
Copy Markdown
Collaborator

LGTM, I think.

@TheBlueMattTheBlueMatt added this to the 0.0.113 milestone Nov 29, 2022
@ViktorT-11

Copy link
Copy Markdown
Contributor

Looks good to me as well!

@dunxendunxen 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, just a tiny nit and question :)

payment_hash: PaymentHash,
/// How many msats were received on the inbound edge of this HTLC.
inbound_amount_msat: u64,
/// How many msats the payer intended to route to the next node. Depending on the reason you are

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.

new rust style team pls save us

Comment threadlightning/src/util/events.rs Outdated
});

failed_intercept_forwards.push((htlc_source, forward_info.payment_hash,
HTLCFailReason::Reason { failure_code: 0x4000 | 10, data: Vec::new() },

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.

not for this PR, but I've wondered whether we should collect failure code consts somewhere so it's easy to see what it is. I can create an issue if we'd want that, unless I missed some prior reasoning not to.

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.

Yeah, I think that would be nice to have!

/// [`HTLCIntercepted`]: events::Event::HTLCIntercepted
// TODO: when we move to deciding the best outbound channel at forward time, only take
// `next_node_id` and not `next_hop_channel_id`
pub fn forward_intercepted_htlc(&self, intercept_id: InterceptId, next_hop_channel_id: &[u8; 32], _next_node_id: PublicKey, amt_to_forward_msat: u64) -> Result<(), APIError> {

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 a question to check my understanding:

Is this basically the procedure for an LDK user?

  1. Calls ChannelManager::get_intercept_scid
  2. Generates invoice with intercept scid in route hints for end-user
  3. Receives an HTLCIntercepted event when the HTLC is intercepted
  4. At this point the LDK user can create a channel
  5. Then call this method to forward over that JIT channel

@ViktorT-11ViktorT-11Nov 30, 2022

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.

Yes that's my understanding, where the LDK user is the LSP in your example (nodes[1] in the test), and the end-user is nodes[2] in the test. I guess step (2) in your example doesn't necessarily need to be on the LDK user's side, as long as the Intercept scid is passed to the end-user.

@dunxendunxenNov 30, 2022

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.

Ah, I should have read the test.

Yeah I think I phrased that weirdly for (2). End user generates invoice but just shoves the scid they got from the LSP in the route hints.

valentinewallaceand others added 9 commits November 30, 2022 12:43
No htlcs are intercepted yet, that will be added in upcoming commit(s)
Co-authored-by: John Cantrell <johncantrell97@gmail.com>
Co-authored-by: Valentine Wallace <vwallace@protonmail.com>
This is useful for LSPs who wish to create a just-in-time channel for end users
receiving a lightning payment. These fake scids will be encoded into route
hints in end user invoices, and signal to LDK to create an event triggering the
JIT channel, after which the payment will be received.
Co-authored-by: John Cantrell <johncantrell97@gmail.com>
Co-authored-by: Valentine Wallace <vwallace@protonmail.com>
Used in upcoming commit(s) so users can intercept forwarded HTLCs
Co-authored-by: John Cantrell <johncantrell97@gmail.com>
Co-authored-by: Valentine Wallace <vwallace@protonmail.com>
And store the pending intercepted HTLC in pending_intercepted_htlcs
Co-authored-by: John Cantrell <johncantrell97@gmail.com>
Co-authored-by: Valentine Wallace <vwallace@protonmail.com>
See ChannelManager::forward_intercepted_htlc and
ChannelManager::get_intercept_scid for details
Co-authored-by: John Cantrell <johncantrell97@gmail.com>
Co-authored-by: Valentine Wallace <vwallace@protonmail.com>
Co-authored-by: John Cantrell <johncantrell97@gmail.com>
Co-authored-by: Valentine Wallace <vwallace@protonmail.com>
@valentinewallace
valentinewallaceforce-pushed the 2022-11-jit-chan-htlc-intercept branch from a5c5d53 to acff8f6CompareNovember 30, 2022 17:52
@valentinewallace

Copy link
Copy Markdown
ContributorAuthor

Rebased due to conflicts

@ariardariard left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

ACK acff8f6

Reviewed code changes since last diff, and also checked test coverage. Remaining comments are minor.

let next_hop_scid = match self.channel_state.lock().unwrap().by_id.get(next_hop_channel_id) {
Some(chan) => {
if !chan.is_usable() {
return Err(APIError::APIMisuseError {

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

We have APIError::ChannelUnavailable in fact, could be used.

let _persistence_guard = PersistenceNotifierGuard::notify_on_drop(&self.total_consistency_lock, &self.persistence_notifier);

let payment = self.pending_intercepted_htlcs.lock().unwrap().remove(&intercept_id)
.ok_or_else(|| APIError::APIMisuseError {

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Mutating this line does not break intercepted_payment

@TheBlueMattTheBlueMatt left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

LGTM, gonna land to get the conflicts out of the way but please address the two issues @ariard noted and the below one in a followup.

};
connect_block(&nodes[0], &block);
connect_block(&nodes[1], &block);
let block_count = 183; // find_route adds a random CLTV offset, so hardcode rather than summing consts

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

It adds a random value in a range, though, so we should still be able to sum consts. Please change it to summing consts cause otherwise our entire test suite fails any time we change any constant :(

Note that if you use the get_route method it won't add the random value, as well.

Sign up for freeto 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.

8 participants

@valentinewallace@codecov-commenter@AnthonyRonning@TheBlueMatt@ariard@ViktorT-11@dunxen@jkczyz
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Intercept HTLC forwards for JIT channels - #1835

Merged
TheBlueMatt merged 9 commits into
lightningdevkit:mainfrom
valentinewallace:2022-11-jit-chan-htlc-intercept
Dec 1, 2022
Merged

Intercept HTLC forwards for JIT channels #1835
TheBlueMatt merged 9 commits into
lightningdevkit:mainfrom
valentinewallace:2022-11-jit-chan-htlc-intercept

Conversation

@valentinewallace

@valentinewallacevalentinewallace commented Nov 7, 2022

Copy link
Copy Markdown
Contributor

For context, LSPs need to be able to open 0-conf JIT channels to users upon the first time the user is receiving a payment. To do this, they will put fake route hints in end user invoices that signal to LDK that this is an intercept forward, similar to phantom payments. LDK will then generate an event, giving the LSP the opportunity to open the JIT channel. The LSP can then forward the payment over the newly opened channel, or fail it.

Based on #1840
Supercedes #1601

@valentinewallace
valentinewallaceforce-pushed the 2022-11-jit-chan-htlc-intercept branch 5 times, most recently from beae304 to 90c4d75CompareNovember 7, 2022 18:42
@valentinewallacevalentinewallace mentioned this pull request Nov 7, 2022
@valentinewallace
valentinewallaceforce-pushed the 2022-11-jit-chan-htlc-intercept branch from 8e3a664 to b166af0CompareNovember 7, 2022 22:30
Comment threadlightning/src/ln/channelmanager.rs Outdated
@codecov-commenter

codecov-commenter commented Nov 7, 2022

Copy link
Copy Markdown

Codecov Report

Base: 90.70% // Head: 90.67% // Decreases project coverage by -0.02%⚠️

Coverage data is based on head (a5c5d53) compared to base (440c3ee).
Patch coverage: 84.34% of modified lines in pull request are covered.

❗ Current head a5c5d53 differs from pull request most recent head acff8f6. Consider uploading reports for the commit acff8f6 to get more accurate results

Additional details and impacted files
@@ Coverage Diff @@## main #1835 +/- ##
==========================================
- Coverage 90.70% 90.67% -0.03% 
==========================================
Files 91 91 Lines 48090 48303 +213 Branches 48090 48303 +213 ==========================================
+ Hits 43618 43800 +182 - Misses 4472 4503 +31 
Impacted FilesCoverage Δ
lightning/src/util/config.rs65.90% <0.00%> (-0.76%)⬇️
lightning/src/util/events.rs24.65% <4.16%> (-1.32%)⬇️
lightning/src/ln/channelmanager.rs86.20% <83.70%> (-0.16%)⬇️
lightning/src/ln/payment_tests.rs98.73% <97.74%> (-0.17%)⬇️
lightning/src/util/scid_utils.rs99.31% <100.00%> (+0.10%)⬆️
lightning-block-sync/src/rest.rs62.06% <0.00%> (-1.87%)⬇️
lightning-block-sync/src/rpc.rs74.80% <0.00%> (-1.14%)⬇️
lightning-block-sync/src/poll.rs86.33% <0.00%> (-0.58%)⬇️
lightning-net-tokio/src/lib.rs77.03% <0.00%> (-0.28%)⬇️
lightning-block-sync/src/lib.rs93.33% <0.00%> (-0.27%)⬇️
... and 13 more

Help us with your feedback. Take ten seconds to tell us how you rate us. Have a feature suggestion? Share it here.

☔ View full report at Codecov.
📢 Do you have feedback about the report comment? Let us know in this issue.

Comment threadlightning/src/util/events.rs Outdated
@AnthonyRonning

AnthonyRonning commented Nov 10, 2022

Copy link
Copy Markdown
Contributor

Are there plans for generic HTLC interception at all? Not dependent on the routing hints of someone else's invoice? There can still be logic into determining the type based on SCID but in general all HTLC's could still be intercepted or at least subscribed to based on type.

There are many use cases for generic HTLC interception that shouldn't depend on LDK development, here are a few:

  1. Other approaches to 0 conf JIT channel payments (something double-invoice like instead of routing hint-like)
  2. Escrow (having a router decide to continue routing to destination in order to deliver funds based on a condition)
  3. Whether or not to route payments down certain channels or at all (liquidity management, balance probe protection)
  4. Third party preimages (node not knowing the preimage but waiting for either a third party or a different application handle preimages)
  5. Hodl invoice (not advocating for long running but at least allowing for checks and processes to run for a few seconds)

You could still have SCID logic but I would love to see generic solved for first and then application specific tbh. I think that's worked really well in the LND/CLN ecosystems.

@valentinewallace

Copy link
Copy Markdown
ContributorAuthor

Are there plans for generic HTLC interception at all? Not dependent on the routing hints of someone else's invoice?

Yes, the plan is to swiftly follow up to this PR with adding general forward interception :)

(1), (4), and (5) are already supported via our PaymentReceived event, IIUC. LDK generates this event once all MPP parts arrive. Upon receipt, you can get the preimage and do whatever other desired operations you like, then call claim_funds (per the linked docs).

@valentinewallace
valentinewallaceforce-pushed the 2022-11-jit-chan-htlc-intercept branch from d763bb5 to 099533dCompareNovember 10, 2022 16:55
@valentinewallace

Copy link
Copy Markdown
ContributorAuthor

Had to rebase to get #1844.

@AnthonyRonning

Copy link
Copy Markdown
Contributor

Yes, the plan is to swiftly follow up to this PR with adding general forward interception :)

Awesome! Concept ACK from me then. I browsed through the code and the API usage sounds good to me but probably can't comment on the rest 👍

@ViktorT-11ViktorT-11 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.

First look-through generally looks good :).

Comment threadlightning/src/ln/channelmanager.rs
Comment threadlightning/src/ln/channelmanager.rs Outdated
Comment threadlightning/src/ln/channelmanager.rs
Comment threadlightning/src/ln/channelmanager.rs Outdated
Comment threadlightning/src/ln/channelmanager.rs Outdated

@TheBlueMattTheBlueMatt left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

I think we need a fallback failure on a timer. If the user screws up and loses the intercept event entirely we shouldn't just sit on the HTLC forever and get the channel force-closed.

Comment threadlightning/src/util/events.rs Outdated
Comment threadlightning/src/util/events.rs
Comment threadlightning/src/ln/channelmanager.rs Outdated
Comment threadlightning/src/ln/channelmanager.rs Outdated
Comment threadlightning/src/ln/channelmanager.rs Outdated
Comment threadlightning/src/ln/channelmanager.rs Outdated
Comment threadlightning/src/ln/channelmanager.rs Outdated
@valentinewallace

Copy link
Copy Markdown
ContributorAuthor

Great feedback once again @ViktorTigerstrom! Working on addressing it

@valentinewallace
valentinewallaceforce-pushed the 2022-11-jit-chan-htlc-intercept branch 2 times, most recently from 0759af8 to ee70d50CompareNovember 14, 2022 20:23
@valentinewallace
valentinewallaceforce-pushed the 2022-11-jit-chan-htlc-intercept branch from 72087f8 to 225a22bCompareNovember 28, 2022 20:13

@ViktorT-11ViktorT-11 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.

This looks good to me. Only real feedback I have left is that it would be valuable to include test coverage to ensure that we don't generate the PaymentIntercepted event + populate pending_intercepted_htlcs when accept_intercept_htlcs is set to false.

nodes[1].node.handle_update_add_htlc(&nodes[0].node.get_our_node_id(), &payment_event.msgs[0]);
commitment_signed_dance!(nodes[1], nodes[0], &payment_event.commitment_msg, false, true);

// Check that we generate the PaymentIntercepted event when an intercept forward is detected.

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.

Would be valuable to also have test coverage ensuring that the PaymentIntercepted event isn't generated + pending_intercepted_htlcs isn't populated when accept_intercept_htlcs is false.

@valentinewallacevalentinewallaceNov 28, 2022

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.

Gonna save that for follow-up for the sake of the size of this PR, but you can manually check that the test fails when the config change lines are commented out. FWIW, that would set a new standard of testing rigor for us since i.e. the zero-conf PR didn't/doesn't test its config.

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.

Ok fair enough :)

Comment threadlightning/src/ln/channelmanager.rs
Comment threadlightning/src/ln/channelmanager.rs
Comment threadlightning/src/ln/channelmanager.rs Outdated
_ => unreachable!(),
};
timed_out_htlcs.push((prev_hop_data, htlc.forward_info.payment_hash,
HTLCFailReason::Reason { failure_code: 0x1000 | 14, data: Vec::new() },

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

14 is definitely right here, but its an UPDATE error, so we need to include a channel_update for the outbound channel, which is obviously....unclear? I guess we could deliberately include the wrong channel's update here and use the previous-hop channel, but that's pretty nonsensical. Maybe we just temporary_node_failure?

@TheBlueMatt

Copy link
Copy Markdown
Collaborator

LGTM, I think.

@TheBlueMattTheBlueMatt added this to the 0.0.113 milestone Nov 29, 2022
@ViktorT-11

Copy link
Copy Markdown
Contributor

Looks good to me as well!

@dunxendunxen 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, just a tiny nit and question :)

payment_hash: PaymentHash,
/// How many msats were received on the inbound edge of this HTLC.
inbound_amount_msat: u64,
/// How many msats the payer intended to route to the next node. Depending on the reason you are

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.

new rust style team pls save us

Comment threadlightning/src/util/events.rs Outdated
});

failed_intercept_forwards.push((htlc_source, forward_info.payment_hash,
HTLCFailReason::Reason { failure_code: 0x4000 | 10, data: Vec::new() },

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.

not for this PR, but I've wondered whether we should collect failure code consts somewhere so it's easy to see what it is. I can create an issue if we'd want that, unless I missed some prior reasoning not to.

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.

Yeah, I think that would be nice to have!

/// [`HTLCIntercepted`]: events::Event::HTLCIntercepted
// TODO: when we move to deciding the best outbound channel at forward time, only take
// `next_node_id` and not `next_hop_channel_id`
pub fn forward_intercepted_htlc(&self, intercept_id: InterceptId, next_hop_channel_id: &[u8; 32], _next_node_id: PublicKey, amt_to_forward_msat: u64) -> Result<(), APIError> {

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 a question to check my understanding:

Is this basically the procedure for an LDK user?

  1. Calls ChannelManager::get_intercept_scid
  2. Generates invoice with intercept scid in route hints for end-user
  3. Receives an HTLCIntercepted event when the HTLC is intercepted
  4. At this point the LDK user can create a channel
  5. Then call this method to forward over that JIT channel

@ViktorT-11ViktorT-11Nov 30, 2022

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.

Yes that's my understanding, where the LDK user is the LSP in your example (nodes[1] in the test), and the end-user is nodes[2] in the test. I guess step (2) in your example doesn't necessarily need to be on the LDK user's side, as long as the Intercept scid is passed to the end-user.

@dunxendunxenNov 30, 2022

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.

Ah, I should have read the test.

Yeah I think I phrased that weirdly for (2). End user generates invoice but just shoves the scid they got from the LSP in the route hints.

valentinewallaceand others added 9 commits November 30, 2022 12:43
No htlcs are intercepted yet, that will be added in upcoming commit(s)
Co-authored-by: John Cantrell <johncantrell97@gmail.com>
Co-authored-by: Valentine Wallace <vwallace@protonmail.com>
This is useful for LSPs who wish to create a just-in-time channel for end users
receiving a lightning payment. These fake scids will be encoded into route
hints in end user invoices, and signal to LDK to create an event triggering the
JIT channel, after which the payment will be received.
Co-authored-by: John Cantrell <johncantrell97@gmail.com>
Co-authored-by: Valentine Wallace <vwallace@protonmail.com>
Used in upcoming commit(s) so users can intercept forwarded HTLCs
Co-authored-by: John Cantrell <johncantrell97@gmail.com>
Co-authored-by: Valentine Wallace <vwallace@protonmail.com>
And store the pending intercepted HTLC in pending_intercepted_htlcs
Co-authored-by: John Cantrell <johncantrell97@gmail.com>
Co-authored-by: Valentine Wallace <vwallace@protonmail.com>
See ChannelManager::forward_intercepted_htlc and
ChannelManager::get_intercept_scid for details
Co-authored-by: John Cantrell <johncantrell97@gmail.com>
Co-authored-by: Valentine Wallace <vwallace@protonmail.com>
Co-authored-by: John Cantrell <johncantrell97@gmail.com>
Co-authored-by: Valentine Wallace <vwallace@protonmail.com>
@valentinewallace
valentinewallaceforce-pushed the 2022-11-jit-chan-htlc-intercept branch from a5c5d53 to acff8f6CompareNovember 30, 2022 17:52
@valentinewallace

Copy link
Copy Markdown
ContributorAuthor

Rebased due to conflicts

@ariardariard left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

ACK acff8f6

Reviewed code changes since last diff, and also checked test coverage. Remaining comments are minor.

let next_hop_scid = match self.channel_state.lock().unwrap().by_id.get(next_hop_channel_id) {
Some(chan) => {
if !chan.is_usable() {
return Err(APIError::APIMisuseError {

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

We have APIError::ChannelUnavailable in fact, could be used.

let _persistence_guard = PersistenceNotifierGuard::notify_on_drop(&self.total_consistency_lock, &self.persistence_notifier);

let payment = self.pending_intercepted_htlcs.lock().unwrap().remove(&intercept_id)
.ok_or_else(|| APIError::APIMisuseError {

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Mutating this line does not break intercepted_payment

@TheBlueMattTheBlueMatt left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

LGTM, gonna land to get the conflicts out of the way but please address the two issues @ariard noted and the below one in a followup.

};
connect_block(&nodes[0], &block);
connect_block(&nodes[1], &block);
let block_count = 183; // find_route adds a random CLTV offset, so hardcode rather than summing consts

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

It adds a random value in a range, though, so we should still be able to sum consts. Please change it to summing consts cause otherwise our entire test suite fails any time we change any constant :(

Note that if you use the get_route method it won't add the random value, as well.

Sign up for freeto 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.

8 participants

@valentinewallace@codecov-commenter@AnthonyRonning@TheBlueMatt@ariard@ViktorT-11@dunxen@jkczyz
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content

Intercept HTLC forwards for JIT channels - #1835

Merged
TheBlueMatt merged 9 commits into
lightningdevkit:mainfrom
valentinewallace:2022-11-jit-chan-htlc-intercept
Dec 1, 2022
Merged

Intercept HTLC forwards for JIT channels #1835
TheBlueMatt merged 9 commits into
lightningdevkit:mainfrom
valentinewallace:2022-11-jit-chan-htlc-intercept

Conversation

@valentinewallace

@valentinewallacevalentinewallace commented Nov 7, 2022

Copy link
Copy Markdown
Contributor

For context, LSPs need to be able to open 0-conf JIT channels to users upon the first time the user is receiving a payment. To do this, they will put fake route hints in end user invoices that signal to LDK that this is an intercept forward, similar to phantom payments. LDK will then generate an event, giving the LSP the opportunity to open the JIT channel. The LSP can then forward the payment over the newly opened channel, or fail it.

Based on #1840
Supercedes #1601

@valentinewallace
valentinewallaceforce-pushed the 2022-11-jit-chan-htlc-intercept branch 5 times, most recently from beae304 to 90c4d75CompareNovember 7, 2022 18:42
@valentinewallacevalentinewallace mentioned this pull request Nov 7, 2022
@valentinewallace
valentinewallaceforce-pushed the 2022-11-jit-chan-htlc-intercept branch from 8e3a664 to b166af0CompareNovember 7, 2022 22:30
Comment threadlightning/src/ln/channelmanager.rs Outdated
@codecov-commenter

codecov-commenter commented Nov 7, 2022

Copy link
Copy Markdown

Codecov Report

Base: 90.70% // Head: 90.67% // Decreases project coverage by -0.02%⚠️

Coverage data is based on head (a5c5d53) compared to base (440c3ee).
Patch coverage: 84.34% of modified lines in pull request are covered.

❗ Current head a5c5d53 differs from pull request most recent head acff8f6. Consider uploading reports for the commit acff8f6 to get more accurate results

Additional details and impacted files
@@ Coverage Diff @@## main #1835 +/- ##
==========================================
- Coverage 90.70% 90.67% -0.03% 
==========================================
Files 91 91 Lines 48090 48303 +213 Branches 48090 48303 +213 ==========================================
+ Hits 43618 43800 +182 - Misses 4472 4503 +31 
Impacted FilesCoverage Δ
lightning/src/util/config.rs65.90% <0.00%> (-0.76%)⬇️
lightning/src/util/events.rs24.65% <4.16%> (-1.32%)⬇️
lightning/src/ln/channelmanager.rs86.20% <83.70%> (-0.16%)⬇️
lightning/src/ln/payment_tests.rs98.73% <97.74%> (-0.17%)⬇️
lightning/src/util/scid_utils.rs99.31% <100.00%> (+0.10%)⬆️
lightning-block-sync/src/rest.rs62.06% <0.00%> (-1.87%)⬇️
lightning-block-sync/src/rpc.rs74.80% <0.00%> (-1.14%)⬇️
lightning-block-sync/src/poll.rs86.33% <0.00%> (-0.58%)⬇️
lightning-net-tokio/src/lib.rs77.03% <0.00%> (-0.28%)⬇️
lightning-block-sync/src/lib.rs93.33% <0.00%> (-0.27%)⬇️
... and 13 more

Help us with your feedback. Take ten seconds to tell us how you rate us. Have a feature suggestion? Share it here.

☔ View full report at Codecov.
📢 Do you have feedback about the report comment? Let us know in this issue.

Comment threadlightning/src/util/events.rs Outdated
@AnthonyRonning

AnthonyRonning commented Nov 10, 2022

Copy link
Copy Markdown
Contributor

Are there plans for generic HTLC interception at all? Not dependent on the routing hints of someone else's invoice? There can still be logic into determining the type based on SCID but in general all HTLC's could still be intercepted or at least subscribed to based on type.

There are many use cases for generic HTLC interception that shouldn't depend on LDK development, here are a few:

  1. Other approaches to 0 conf JIT channel payments (something double-invoice like instead of routing hint-like)
  2. Escrow (having a router decide to continue routing to destination in order to deliver funds based on a condition)
  3. Whether or not to route payments down certain channels or at all (liquidity management, balance probe protection)
  4. Third party preimages (node not knowing the preimage but waiting for either a third party or a different application handle preimages)
  5. Hodl invoice (not advocating for long running but at least allowing for checks and processes to run for a few seconds)

You could still have SCID logic but I would love to see generic solved for first and then application specific tbh. I think that's worked really well in the LND/CLN ecosystems.

@valentinewallace

Copy link
Copy Markdown
ContributorAuthor

Are there plans for generic HTLC interception at all? Not dependent on the routing hints of someone else's invoice?

Yes, the plan is to swiftly follow up to this PR with adding general forward interception :)

(1), (4), and (5) are already supported via our PaymentReceived event, IIUC. LDK generates this event once all MPP parts arrive. Upon receipt, you can get the preimage and do whatever other desired operations you like, then call claim_funds (per the linked docs).

@valentinewallace
valentinewallaceforce-pushed the 2022-11-jit-chan-htlc-intercept branch from d763bb5 to 099533dCompareNovember 10, 2022 16:55
@valentinewallace

Copy link
Copy Markdown
ContributorAuthor

Had to rebase to get #1844.

@AnthonyRonning

Copy link
Copy Markdown
Contributor

Yes, the plan is to swiftly follow up to this PR with adding general forward interception :)

Awesome! Concept ACK from me then. I browsed through the code and the API usage sounds good to me but probably can't comment on the rest 👍

@ViktorT-11ViktorT-11 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.

First look-through generally looks good :).

Comment threadlightning/src/ln/channelmanager.rs
Comment threadlightning/src/ln/channelmanager.rs Outdated
Comment threadlightning/src/ln/channelmanager.rs
Comment threadlightning/src/ln/channelmanager.rs Outdated
Comment threadlightning/src/ln/channelmanager.rs Outdated

@TheBlueMattTheBlueMatt left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

I think we need a fallback failure on a timer. If the user screws up and loses the intercept event entirely we shouldn't just sit on the HTLC forever and get the channel force-closed.

Comment threadlightning/src/util/events.rs Outdated
Comment threadlightning/src/util/events.rs
Comment threadlightning/src/ln/channelmanager.rs Outdated
Comment threadlightning/src/ln/channelmanager.rs Outdated
Comment threadlightning/src/ln/channelmanager.rs Outdated
Comment threadlightning/src/ln/channelmanager.rs Outdated
Comment threadlightning/src/ln/channelmanager.rs Outdated
@valentinewallace

Copy link
Copy Markdown
ContributorAuthor

Great feedback once again @ViktorTigerstrom! Working on addressing it

@valentinewallace
valentinewallaceforce-pushed the 2022-11-jit-chan-htlc-intercept branch 2 times, most recently from 0759af8 to ee70d50CompareNovember 14, 2022 20:23
@valentinewallace
valentinewallaceforce-pushed the 2022-11-jit-chan-htlc-intercept branch from 72087f8 to 225a22bCompareNovember 28, 2022 20:13

@ViktorT-11ViktorT-11 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.

This looks good to me. Only real feedback I have left is that it would be valuable to include test coverage to ensure that we don't generate the PaymentIntercepted event + populate pending_intercepted_htlcs when accept_intercept_htlcs is set to false.

nodes[1].node.handle_update_add_htlc(&nodes[0].node.get_our_node_id(), &payment_event.msgs[0]);
commitment_signed_dance!(nodes[1], nodes[0], &payment_event.commitment_msg, false, true);

// Check that we generate the PaymentIntercepted event when an intercept forward is detected.

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.

Would be valuable to also have test coverage ensuring that the PaymentIntercepted event isn't generated + pending_intercepted_htlcs isn't populated when accept_intercept_htlcs is false.

@valentinewallacevalentinewallaceNov 28, 2022

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.

Gonna save that for follow-up for the sake of the size of this PR, but you can manually check that the test fails when the config change lines are commented out. FWIW, that would set a new standard of testing rigor for us since i.e. the zero-conf PR didn't/doesn't test its config.

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.

Ok fair enough :)

Comment threadlightning/src/ln/channelmanager.rs
Comment threadlightning/src/ln/channelmanager.rs
Comment threadlightning/src/ln/channelmanager.rs Outdated
_ => unreachable!(),
};
timed_out_htlcs.push((prev_hop_data, htlc.forward_info.payment_hash,
HTLCFailReason::Reason { failure_code: 0x1000 | 14, data: Vec::new() },

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

14 is definitely right here, but its an UPDATE error, so we need to include a channel_update for the outbound channel, which is obviously....unclear? I guess we could deliberately include the wrong channel's update here and use the previous-hop channel, but that's pretty nonsensical. Maybe we just temporary_node_failure?

@TheBlueMatt

Copy link
Copy Markdown
Collaborator

LGTM, I think.

@TheBlueMattTheBlueMatt added this to the 0.0.113 milestone Nov 29, 2022
@ViktorT-11

Copy link
Copy Markdown
Contributor

Looks good to me as well!

@dunxendunxen 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, just a tiny nit and question :)

payment_hash: PaymentHash,
/// How many msats were received on the inbound edge of this HTLC.
inbound_amount_msat: u64,
/// How many msats the payer intended to route to the next node. Depending on the reason you are

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.

new rust style team pls save us

Comment threadlightning/src/util/events.rs Outdated
});

failed_intercept_forwards.push((htlc_source, forward_info.payment_hash,
HTLCFailReason::Reason { failure_code: 0x4000 | 10, data: Vec::new() },

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.

not for this PR, but I've wondered whether we should collect failure code consts somewhere so it's easy to see what it is. I can create an issue if we'd want that, unless I missed some prior reasoning not to.

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.

Yeah, I think that would be nice to have!

/// [`HTLCIntercepted`]: events::Event::HTLCIntercepted
// TODO: when we move to deciding the best outbound channel at forward time, only take
// `next_node_id` and not `next_hop_channel_id`
pub fn forward_intercepted_htlc(&self, intercept_id: InterceptId, next_hop_channel_id: &[u8; 32], _next_node_id: PublicKey, amt_to_forward_msat: u64) -> Result<(), APIError> {

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 a question to check my understanding:

Is this basically the procedure for an LDK user?

  1. Calls ChannelManager::get_intercept_scid
  2. Generates invoice with intercept scid in route hints for end-user
  3. Receives an HTLCIntercepted event when the HTLC is intercepted
  4. At this point the LDK user can create a channel
  5. Then call this method to forward over that JIT channel

@ViktorT-11ViktorT-11Nov 30, 2022

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.

Yes that's my understanding, where the LDK user is the LSP in your example (nodes[1] in the test), and the end-user is nodes[2] in the test. I guess step (2) in your example doesn't necessarily need to be on the LDK user's side, as long as the Intercept scid is passed to the end-user.

@dunxendunxenNov 30, 2022

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.

Ah, I should have read the test.

Yeah I think I phrased that weirdly for (2). End user generates invoice but just shoves the scid they got from the LSP in the route hints.

valentinewallaceand others added 9 commits November 30, 2022 12:43
No htlcs are intercepted yet, that will be added in upcoming commit(s)
Co-authored-by: John Cantrell <johncantrell97@gmail.com>
Co-authored-by: Valentine Wallace <vwallace@protonmail.com>
This is useful for LSPs who wish to create a just-in-time channel for end users
receiving a lightning payment. These fake scids will be encoded into route
hints in end user invoices, and signal to LDK to create an event triggering the
JIT channel, after which the payment will be received.
Co-authored-by: John Cantrell <johncantrell97@gmail.com>
Co-authored-by: Valentine Wallace <vwallace@protonmail.com>
Used in upcoming commit(s) so users can intercept forwarded HTLCs
Co-authored-by: John Cantrell <johncantrell97@gmail.com>
Co-authored-by: Valentine Wallace <vwallace@protonmail.com>
And store the pending intercepted HTLC in pending_intercepted_htlcs
Co-authored-by: John Cantrell <johncantrell97@gmail.com>
Co-authored-by: Valentine Wallace <vwallace@protonmail.com>
See ChannelManager::forward_intercepted_htlc and
ChannelManager::get_intercept_scid for details
Co-authored-by: John Cantrell <johncantrell97@gmail.com>
Co-authored-by: Valentine Wallace <vwallace@protonmail.com>
Co-authored-by: John Cantrell <johncantrell97@gmail.com>
Co-authored-by: Valentine Wallace <vwallace@protonmail.com>
@valentinewallace
valentinewallaceforce-pushed the 2022-11-jit-chan-htlc-intercept branch from a5c5d53 to acff8f6CompareNovember 30, 2022 17:52
@valentinewallace

Copy link
Copy Markdown
ContributorAuthor

Rebased due to conflicts

@ariardariard left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

ACK acff8f6

Reviewed code changes since last diff, and also checked test coverage. Remaining comments are minor.

let next_hop_scid = match self.channel_state.lock().unwrap().by_id.get(next_hop_channel_id) {
Some(chan) => {
if !chan.is_usable() {
return Err(APIError::APIMisuseError {

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

We have APIError::ChannelUnavailable in fact, could be used.

let _persistence_guard = PersistenceNotifierGuard::notify_on_drop(&self.total_consistency_lock, &self.persistence_notifier);

let payment = self.pending_intercepted_htlcs.lock().unwrap().remove(&intercept_id)
.ok_or_else(|| APIError::APIMisuseError {

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Mutating this line does not break intercepted_payment

@TheBlueMattTheBlueMatt left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

LGTM, gonna land to get the conflicts out of the way but please address the two issues @ariard noted and the below one in a followup.

};
connect_block(&nodes[0], &block);
connect_block(&nodes[1], &block);
let block_count = 183; // find_route adds a random CLTV offset, so hardcode rather than summing consts

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

It adds a random value in a range, though, so we should still be able to sum consts. Please change it to summing consts cause otherwise our entire test suite fails any time we change any constant :(

Note that if you use the get_route method it won't add the random value, as well.

Sign up for freeto 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.

8 participants

@valentinewallace@codecov-commenter@AnthonyRonning@TheBlueMatt@ariard@ViktorT-11@dunxen@jkczyz