-
Notifications
You must be signed in to change notification settings - Fork 2.1k
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
multi: Forward Blinded Payments #7376
Conversation
4fb5e84
to
918ac69
Compare
Alice (CL) --> Bob(LND) --> Carol (LND) --> Dave(CL) forwarding interop achieved (though acquired with a pretty ungodly setup)!
Going to further split up this PR to ease reivew:
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). |
There was a problem hiding this 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.
lnwallet/channel.go
Outdated
if payDesc.EntryType == Add { | ||
if err = lc.remoteUpdateLog.restoreExtraAddData( |
There was a problem hiding this comment.
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!
lnwallet/channel.go
Outdated
@@ -417,6 +423,7 @@ func PayDescsFromRemoteLogUpdates(chanID lnwire.ShortChannelID, height uint64, | |||
Height: height, | |||
Index: uint16(i), | |||
}, | |||
BlindingPoint: wireMsg.BlindingPoint.PublicKey, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@@ -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{}, |
There was a problem hiding this comment.
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.
918ac69
to
5bd95c3
Compare
Needs rebase on #7710 - hold off on review for now! |
5bd95c3
to
28a7ccf
Compare
28a7ccf
to
3838130
Compare
1466a26
to
18806c1
Compare
18806c1
to
2301dd7
Compare
5736c79
to
69ff187
Compare
can be rebased! |
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 <[email protected]>
Co-authored-by: Calvin Zachman <[email protected]>
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.
69ff187
to
4510819
Compare
|
@yyforyongyu: review reminder |
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:
blinding_point
through to it (tbd separately)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 offercl fetchinvoice lno...
->lni....
is your invoicecl decode lni...
-> This will give blinded hops/data etc.You can then pay the blinded invoice from LND:
It's also covered in an itest, which may make life a little easier :')