Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

multi: Forward Blinded Payments #7376

Closed

Conversation

carlaKC
Copy link
Collaborator

@carlaKC carlaKC commented Feb 1, 2023

Change Description

This PR adds forwarding of payments in blinded paths to LND, and depends on #7267, #7297.

Opening early for general approach feedback 🙏 and to provide an idea of the scope of the change (many rpc changes are inflating the change delta - it looks worse than it is, promise 😅 ).

There are a few notably missing elements:

Steps to Test

Since LND doesn't produce blinded routes, you'll need the following setup:
Alice (LND) --- Bob(LND) --- Carol (LND) --privatechan-- Dave(CL)

Since we need to retrieve a raw CL invoice, you need another CL node connected to Dave to fetch the invoice from an offer:

  • dave offer 1000 test -> lno... is your offer
  • cl fetchinvoice lno... -> lni.... is your invoice
  • cl decode lni... -> This will give blinded hops/data etc.

You can then pay the blinded invoice from LND:

lncli queryroutes --introduction_point={cleartext_introduction_node_id} --blinding_point={blinding_point} --blinded_hops={blinded_introduction_node}:{introduction_node_data} --blinded_cltv={blinded_route_total_cltv} --amt={invoice_amount} | lncli sendtoroute --payment_hash={payment_hash} -

It's also covered in an itest, which may make life a little easier :')

@carlaKC
Copy link
Collaborator Author

carlaKC commented Feb 24, 2023

Alice (CL) --> Bob(LND) --> Carol (LND) --> Dave(CL) forwarding interop achieved (though acquired with a pretty ungodly setup)!

  • Run CL with --experimental-offers --dev-fast-gossip + DEVELOPER=1 in configure
  • Run LND at 918ac69
  • Open public channels Alice - Bob, Bob-Carol
  • Open private chanel Carol-Dave (required to force a blinded path for the offer)
  • Alice / Bob / Carol / Dave lncli updatechanpolicy 1000 1 18 (run into blinded path timelock limit issues with CL otherwise)
  • P2P Connect Alice to Dave (required to use onion messaging to fetch an bolt 12 invoice)
  • Dave lightning-cli offer 1000 test -> lno...
  • Alice: lightning-cli fetchinvoice lno... -> lni...
  • Alice: lightning-cli pay lni... -> Success!

Going to further split up this PR to ease reivew:

  1. Preparatory PR adding structs, serialization
  2. Forwarding PR with blinded payment logic

Also going to decouple this from #7267 (that will make the itests a little longer because we need to do things manually, but I think it's going to result in a more reviewable PR chain).

Copy link
Contributor

@calvinrzachman calvinrzachman left a comment

Choose a reason for hiding this comment

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

Cool to make a first review pass for route blinding! You certainly did a much better job than I did at preserving the existing efforts to maintain separation between different components 😄 I like the finesse in hiding the handling of blind hops behind hop.DecodeHopIterators() and the hop.Iterator interface. These were already responsible for batch decrypting onions and providing a “hop iterator” from which we obtain all information needed to forward, so it really does make sense to also put the handling of the nested route blinding payload there as well. This keeps the channel link free from having to worry about whether the hops it processes are normal or blind.

I kept it focused to just the commits which are unique to this PR. I’ll try and dig a bit deeper as I have time to get back into the route blinding stuff very soon. Just a couple things to note so far! Let me know what you think.

if payDesc.EntryType == Add {
if err = lc.remoteUpdateLog.restoreExtraAddData(
Copy link
Contributor

Choose a reason for hiding this comment

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

So as you say in the commit description, with this change we handle the restoration of partially committed HTLCs from on-disk commitment. This covers us for the case where we restart part way through a commitment dance after adding the HTLC to the local commitment, but prior to sending a signature which covers the HTLC on the remote party's commitment.

I think we also need to handle the restoration of fully committed HTLC’s from forwarding packages so that the blinding point is available for ADDs which are re-transmitted in the incoming link by this code path. This requires both that the LogUpdate we create for the FwdPkg in ReceiveRevocation contains the blinding point and that we pull that blinding point out and put it back in the PaymentDescriptor. An example of that can be found here. Let me know what you think!

lnwire/blinding_point.go Outdated Show resolved Hide resolved
@@ -417,6 +423,7 @@ func PayDescsFromRemoteLogUpdates(chanID lnwire.ShortChannelID, height uint64,
Height: height,
Index: uint16(i),
},
BlindingPoint: wireMsg.BlindingPoint.PublicKey,
Copy link
Contributor

@calvinrzachman calvinrzachman Mar 30, 2023

Choose a reason for hiding this comment

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

At least as it pertains to restoring the blinding point from forwarding packages, I think we may need to pair this with placing the blinding point inside the LogUpdate stored in the FwdPkg created by ReceiveRevocation(). Check out my other comment and let me know what you think.

@@ -348,7 +348,9 @@ func testDecodeHopPayloadValidation(t *testing.T, test decodePayloadTest) {
testChildIndex = uint32(9)
)

p, err := hop.NewPayloadFromReader(bytes.NewReader(test.payload))
p, err := hop.NewPayloadFromReader(
bytes.NewReader(test.payload), &hop.BlindingKit{},
Copy link
Contributor

Choose a reason for hiding this comment

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

Even after removing the amount/timelock TLV here so we pass the route blinding validation step, I get a nil pointer dereference. I think the trouble is that this blinding kit is not fully initialized and is missing deriveForwardingInfo().

We could provide a mock blind hop processor implementation and use hop.MakeBlindingKit(), but I think the more general solution is - now that we do some validation across both onion TLV payload, route blinding TLV payload and TLV extension for UpdateAddHTLC that we cover the payload validation for blind hops in a bit more full fledged test case which provides control over those elements.

@carlaKC
Copy link
Collaborator Author

carlaKC commented May 25, 2023

Needs rebase on #7710 - hold off on review for now!

@carlaKC carlaKC force-pushed the 7298-forwardblindedroutes branch from 5bd95c3 to 28a7ccf Compare May 25, 2023 21:18
@carlaKC carlaKC force-pushed the 7298-forwardblindedroutes branch 3 times, most recently from 1466a26 to 18806c1 Compare August 9, 2023 19:20
@saubyk saubyk added this to the v0.18.0 milestone Aug 10, 2023
@saubyk saubyk added P1 MUST be fixed or reviewed blinded paths labels Aug 10, 2023
@yyforyongyu yyforyongyu self-requested a review August 31, 2023 09:50
@carlaKC carlaKC force-pushed the 7298-forwardblindedroutes branch 2 times, most recently from 5736c79 to 69ff187 Compare September 13, 2023 13:50
@yyforyongyu yyforyongyu changed the base branch from master to 0-18-staging September 28, 2023 10:58
@yyforyongyu
Copy link
Member

can be rebased!

carlaKC and others added 9 commits October 6, 2023 11:21
We'll need to pack feature vectors for route blinding, so we pull
the encoding/decoding out into separate functions (currently
contained in ChannelType). Though it's more lines of code, we keep
most of the ChannelType assertions so that we strictly enforce
use of the alias.
This commit adds encoding and decoding for blinded route data blobs.
TLV fields such as path_id (which are only used for the final hop)
are omitted to minimize the change size.
Add blinding points to update_add_htlc. This TLV will be set for
nodes that are relaying payments in blinded routes that are _not_
the introduction node.
If there is a blinding point present in update_add_htlc's TLVs, add
it to our payment descriptor struct so that it can be passed through
to onion decryption. This code path will be used for nodes that are
relaying payments inside of the blinded route (ie, all nodes except
the introduction node).

When we restore HTLCs from disk, we do not have the data provided in
UpdateAddHTLC's TLVs available. This is okay, because once we store
the HTLC as part of our commit state, either have the full wire message
stored (for acked but not signed htlcs) or a forwarding package with
all forwarding information has been produced (for fully locked in
htlcs).
When we have payments inside of a blinded route, we need to know
the incoming amount to be able to back-calculate the amount that
we need to forward using the forwarding parameters provided in the
blinded route encrypted data. This commit adds the payment amount
to our DecodeHopIteratorRequest so that it can be threaded down to
payment forwarding information creation in later commits.
Co-authored-by: Calvin Zachman <calvin.zachman@protonmail.com>
Co-authored-by: Calvin Zachman <calvin.zachman@protonmail.com>
This commit introduces a blinding kits which abstracts over the
operations required to decrypt, deserialize and reconstruct forwarding
data from an encrypted blob of data included for nodes in blinded
routes.

The concept of a BlindingKey is separated into a separate struct so
that it can be used independently of the kit (which is specifically used
to process encrypted blobs). This abstraction will be used later to help
determine how we handle errors.
When we have a HTLC that is part of a blinded route, we need to include
the next ephemeral blinding point in UpdateAddHtlc for the next hop. The
way that we handle the addition of this key is the same for introduction
nodes and relaying nodes within the route.
If we received a payload with a blinding point set, our forwarding
information should be set from the information in our encrypted blob.
This behavior is the same for introduction and relying nodes in a
blinded route.
Note: the itest is broken up into multiple commits to make it
more readable, they can be squashed post-review.
We don't support receiving blinded in this PR - just intercept and
settle instead.
@carlaKC
Copy link
Collaborator Author

carlaKC commented Oct 6, 2023

⚠️ Don't review, going to split out a prep PR with refactoring / basic plumbing.

@carlaKC carlaKC mentioned this pull request Oct 11, 2023
@lightninglabs-deploy
Copy link

@yyforyongyu: review reminder
@carlaKC, remember to re-request review from reviewers when ready

@carlaKC
Copy link
Collaborator Author

carlaKC commented Nov 8, 2023

Broke this up into 2 PRs (with a small, third PR for error handling to come).
Replaced by #8159, #8160

@carlaKC carlaKC closed this Nov 8, 2023
@saubyk saubyk removed this from the v0.18.0 milestone Nov 9, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
blinded paths P1 MUST be fixed or reviewed
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants