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

[2/4] Route Blinding Receives: Receive and send to a single blinded path in an invoice. #8735

Merged
merged 30 commits into from
Jul 30, 2024

Conversation

ellemouton
Copy link
Collaborator

@ellemouton ellemouton commented May 7, 2024

Tracking Issue: #6690

Depends on lightningnetwork/lightning-onion#63

High level overview:

This PR is the first in a set of 3 PRs that will implement route blinding receive logic in LND.
As LND does not yet support blot 12 invoices, this PR adds them to the Bolt11 invoice serialisation.

With this PR, a user can request that a bolt 11 invoice include blinded paths and will also
be able to pay to a bolt 11 invoice that includes blinded paths. However, with this PR, only one of the
paths in the invoice will be used. A follow up PR will add the ability to make use of multiple paths.

UPDATE: This has been updated to include dummy hop padding :)

Lower level overview:

  1. Logic for constructing a full blinded payment path packet given a candidate route to ourselves.
  2. Graph traversal logic for finding a set of candidate routes to ourselves to use in a blinded path.
  3. Various receiver side updates to ensure that we correctly handle an incoming payment from a blinded route (by for example, extracting the payment address from the pathID). Also a few updates for the case where we receive MP payments for a blinded path.
  4. A couple of sender side updates to ensure that MP payments to a single blinded path can work
  5. Updates and additions to the route blinding itests to cover the new receive logic :)

@ellemouton ellemouton self-assigned this May 7, 2024
@lightningnetwork lightningnetwork deleted a comment from coderabbitai bot May 7, 2024
@saubyk saubyk added this to the v0.18.1 milestone May 9, 2024
Copy link
Contributor

coderabbitai bot commented May 14, 2024

Important

Review skipped

Auto reviews are limited to specific labels.

Labels to auto review (1)
  • llm-review

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.


Thank you for using CodeRabbit. We offer it for free to the OSS community and would appreciate your support in helping us grow. If you find it useful, would you consider giving us a shout-out on your favorite social media?

Share
Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>.
    • Generate unit testing code for this file.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai generate unit testing code for this file.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai generate interesting stats about this repository and render them as a table.
    • @coderabbitai show all the console.log statements in this repository.
    • @coderabbitai read src/utils.ts and generate unit testing code.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (invoked as PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Additionally, you can add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

@ellemouton ellemouton changed the title [1/3] Route Blinding Receives: Receive to a single blinded path in an invoice. [2/3] Route Blinding Receives: Receive and send to a single blinded path in an invoice. May 14, 2024
@ellemouton ellemouton force-pushed the rb-receives branch 2 times, most recently from a7c5c6d to 09d0075 Compare May 15, 2024 10:59
@ellemouton ellemouton changed the base branch from master to elle-rb-receives-1 May 15, 2024 11:00
lnrpc/invoicesrpc/addinvoice_test.go Outdated Show resolved Hide resolved
// incMultiplier while the maximum HTLC msat value is adjusted via the
// decMultiplier. If adjustments of the HTLC values no longer make sense
// then the original HTLC value is used.
func addPolicyBuffer(policy *models.ChannelEdgePolicy,
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

this is a naive first implementation. Some thoughts:

  1. We could have different multipliers for each field
  2. Perhaps not good enough to just multiply by a constant cause this might let the sender do some fingerprinting especially in the case where the route is super short. So perhaps we should also round to the nearest 10 or something?

Copy link
Collaborator

Choose a reason for hiding this comment

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

Suggestions 1. and 2. would mean that a sender could maybe find out the receiver's implementation (which is maybe not a very strong requirement). With fingerprinting, do you mean the case where a fee adjustment takes place at a suspected hop which is then out of bounds, that the sender can find out that a hop was on the route? This seems to be difficult to do in the current implementation because there is randomization due to the other hop's policies when aggregating the full amount. This is different from the spec example where the same buffer values are used for all hops, which seemsto be worse as that assumption could be used to derive the buffers for each hop.

Copy link
Collaborator

Choose a reason for hiding this comment

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

Q: Just to verify my understanding is correct, so setting this buffer too high in the first place means the sender of the payment overpays the route ? So we need to find a middle ground between privacy but also increased cost, or is there a way for the receiver to reimburse the sender in favour of his increased privacy demand ?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

would mean that a sender could maybe find out the receiver's implementation

This is what I mean by "fingerprinting"

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Q: Just to verify my understanding is correct, so setting this buffer too high in the first place means the sender of the payment overpays the route ?

Yeah - we dont want these paths to be wayyy too expensive. No there isnt a re-imburse flow. But at the end of the day, we will give the receiver control over these values - so they always have the option of just setting a really wide buffer

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

This seems to be difficult to do in the current implementation because there is randomization due to the other hop's policies when aggregating the full amount. This is different from the spec example where the same buffer values are used for all hops, which seemsto be worse as that assumption could be used to derive the buffers for each hop.

meaning you think this is ok as is?


// FindBlindedPaths finds a selection of paths to the destination node that can
// be used in blinded payment paths.
func (r *ChannelRouter) FindBlindedPaths(destination route.Vertex,
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

some food for thought here:

  • If we let the user set a non-equal MinHops and MaxHops, then this gonna pretty much select the shortest paths as is.. since those will always have the largest success probability. So perhaps we should also have a MinNumPaths and then always only select paths of the same length as long there are enough with that length to satisfy the MinNumPaths?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

  • we also in general probably dont want to include paths of diff lengths. Currently the user has the power to enforce this through just setting MaxNumHops = MinNumHops but I dont think they should have to do that

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

wanna hear other people's thoughts before I update anything though

Copy link
Collaborator

Choose a reason for hiding this comment

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

I tend to agree to enforce an equal length of routes, as the min hops number effectively determines the distance via sorting when we only know constant a priori probabilities (as you say). Also, if one looks at the routes created, if one allows min/max to be different, then we'll create shorter routes that are subsets of the larger ones. I wonder if that enables more probing vectors or is beneficial by creating a seemingly larger anonymity set?

Copy link
Collaborator

Choose a reason for hiding this comment

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

hmm what about making all of the fixed length by adding ddmmy hops ?

Copy link
Collaborator

Choose a reason for hiding this comment

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

Also, if one looks at the routes created, if one allows min/max to be different, then we'll create shorter routes that are subsets of the larger ones.

I think we should set minNumHops = maxNumHops as otherwise we'll give hints about which nodes are included in the other, longer paths (see the tests from the previous commit). We would degrade the longer path's privacy to the shorter ones if one can assume that all intro nodes may be present in the other paths as relay nodes. A downside of that is that it restricts the number of possible paths, so it may not be possible to find some path. This also circumvents the problem with the apriori probability (shortest paths are selected first).

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

dont think this is applicable anymore with the dummy hops. All paths are equal length always now.

FindBlindedPaths can be left to just return paths of multiple lengths - it is fine cause we pad with dummy hops later

Copy link
Collaborator

Choose a reason for hiding this comment

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

Just wanted to be clearer here, we could get the following paths:

// We expect the following paths:
	// 	- B, D
	//	- F, B, D
	// 	- E, B, D
	// 	- C, D
	// 	- E, C, D

I could assume that B, F, E, and C may be part of the other blinded routes, because as they were selected as introduction nodes, they may be included in other routes as well, because for example B, D is a sub-route of F, B, D. Not sure if this is too constructed and it behaves differently for larger networks? The shorter ones would be selected first in the current setup, so this argument is weakened a bit.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

sorry im still not sure i follow - we would only see intro nodes & we would not know that the routes are different lengths... so how do we know that one hop is part of the other?

Copy link
Collaborator

Choose a reason for hiding this comment

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

We would degrade the longer path's privacy to the shorter ones if one can assume that all intro nodes may be present in the other paths as relay nodes. A downside of that is that it restricts the number of possible paths, so it may not be possible to find some path. This also circumvents the problem with the apriori probability (shortest paths are selected first).

Ahh interesting point 👀, I would for the first release maybe focus on successful paths and introduce more privacy focused settings down the road ?

@ellemouton ellemouton force-pushed the elle-rb-receives-1 branch from e92e850 to d537c35 Compare May 15, 2024 11:10
@ellemouton ellemouton changed the title [2/3] Route Blinding Receives: Receive and send to a single blinded path in an invoice. [2/4] Route Blinding Receives: Receive and send to a single blinded path in an invoice. May 16, 2024
@saubyk
Copy link
Collaborator

saubyk commented May 16, 2024

cc: @calvinrzachman for review

@ziggie1984 ziggie1984 self-requested a review June 7, 2024 09:26
@ellemouton ellemouton requested a review from bitromortac June 10, 2024 12:54
Copy link
Collaborator

@bitromortac bitromortac left a comment

Choose a reason for hiding this comment

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

Awesome work 🔥! Really cool to see this working end-to-end 🙏. I need to improve my understanding of the hop expiries a bit more and also check spec compliance, but the PR looks great on first pass!

Comment on lines 892 to 1713
plainText, err := record.EncodeBlindedRouteData(
hop.data,
)
if err != nil {
return nil, 0, err
}

paymentPath[i] = &sphinx.HopInfo{
NodePub: hop.nodeID,
PlainText: plainText,
}
Copy link
Collaborator

Choose a reason for hiding this comment

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

one could save the encodings in paymentPath already in the previous iterations?

// iteration is required for padding values on the BigSize encoding bucket
// edges. The number of iterations that this function takes is also returned for
// testing purposes.
func padHopInfo(hopInfo []*hopData) ([]*sphinx.HopInfo, int, error) {
Copy link
Collaborator

Choose a reason for hiding this comment

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

I see the problem clearer now compared to the first review. Trying to think about other alternatives. Maybe one could replace PadBy with an erring PadTo method that would fail in case we can't pad to the requested size (at the varInt transitions) and we'd then we'd bump the requested size each time we get an error, which should eventually lead to a valid padding. This would hide more complexity in PadTo

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

This would hide more complexity in PadTo

Im not sure we want to add more complexity there. To me, PadTo shouldnt need to introspect how the TLV package is encoding things. To me it is nicer to have an outer function like this call the overall record.EncodeBlindedRouteData method so that we can really be sure that the lengths are converging. Else we are only zooming in on one field.

open to more thoughts here.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

to me the record package should not necessarily be aware of how we are going about using the padding. Although you could argue that it already kind of is aware cause of us only exposing PadBy(n) vs something like AddPadding([]byte).

But yeah I sort of prefer this iterative style here rather than relying on errors being returned & looping based off errors.

lnrpc/invoicesrpc/addinvoice.go Outdated Show resolved Hide resolved
lnrpc/invoicesrpc/addinvoice.go Outdated Show resolved Hide resolved
// incMultiplier while the maximum HTLC msat value is adjusted via the
// decMultiplier. If adjustments of the HTLC values no longer make sense
// then the original HTLC value is used.
func addPolicyBuffer(policy *models.ChannelEdgePolicy,
Copy link
Collaborator

Choose a reason for hiding this comment

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

Suggestions 1. and 2. would mean that a sender could maybe find out the receiver's implementation (which is maybe not a very strong requirement). With fingerprinting, do you mean the case where a fee adjustment takes place at a suspected hop which is then out of bounds, that the sender can find out that a hop was on the route? This seems to be difficult to do in the current implementation because there is randomization due to the other hop's policies when aggregating the full amount. This is different from the spec example where the same buffer values are used for all hops, which seemsto be worse as that assumption could be used to derive the buffers for each hop.

lncfg/invoices.go Outdated Show resolved Hide resolved
sample-lnd.conf Outdated Show resolved Hide resolved
sample-lnd.conf Outdated Show resolved Hide resolved
invoices/interface.go Show resolved Hide resolved
itest/lnd_route_blinding_test.go Show resolved Hide resolved
Copy link
Collaborator

@ziggie1984 ziggie1984 left a comment

Choose a reason for hiding this comment

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

As always great work on this 👏

Wanted to play around with it via the lncli tool but I think its still not updated yet ?

Apart from that I had mostly general questions in regards of the blinded path topic, especially dummy hops which we could include to make every blinded path of the same size ? Will continue with PR 3

lnrpc/invoicesrpc/addinvoice.go Outdated Show resolved Hide resolved
lnrpc/invoicesrpc/addinvoice.go Outdated Show resolved Hide resolved
lnrpc/invoicesrpc/addinvoice.go Outdated Show resolved Hide resolved
lnrpc/invoicesrpc/addinvoice_test.go Outdated Show resolved Hide resolved
lnrpc/invoicesrpc/addinvoice.go Outdated Show resolved Hide resolved
docs/release-notes/release-notes-0.18.1.md Outdated Show resolved Hide resolved
htlcswitch/hop/iterator.go Outdated Show resolved Hide resolved
lnrpc/routerrpc/router_backend.go Show resolved Hide resolved
routing/router.go Show resolved Hide resolved
itest/lnd_route_blinding_test.go Show resolved Hide resolved
@saubyk saubyk added the P2 should be fixed if one has time label Jun 25, 2024
@ellemouton
Copy link
Collaborator Author

ellemouton commented Jul 2, 2024

note to self: need to add new feature bit to the invoice here

EDIT: done

Copy link
Collaborator Author

@ellemouton ellemouton left a comment

Choose a reason for hiding this comment

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

submitting some comments so long - not yet ready for re-review :)

// iteration is required for padding values on the BigSize encoding bucket
// edges. The number of iterations that this function takes is also returned for
// testing purposes.
func padHopInfo(hopInfo []*hopData) ([]*sphinx.HopInfo, int, error) {
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

This would hide more complexity in PadTo

Im not sure we want to add more complexity there. To me, PadTo shouldnt need to introspect how the TLV package is encoding things. To me it is nicer to have an outer function like this call the overall record.EncodeBlindedRouteData method so that we can really be sure that the lengths are converging. Else we are only zooming in on one field.

open to more thoughts here.

lnrpc/invoicesrpc/addinvoice.go Outdated Show resolved Hide resolved
lnrpc/invoicesrpc/addinvoice.go Outdated Show resolved Hide resolved
lnrpc/invoicesrpc/addinvoice.go Outdated Show resolved Hide resolved
// incMultiplier while the maximum HTLC msat value is adjusted via the
// decMultiplier. If adjustments of the HTLC values no longer make sense
// then the original HTLC value is used.
func addPolicyBuffer(policy *models.ChannelEdgePolicy,
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

would mean that a sender could maybe find out the receiver's implementation

This is what I mean by "fingerprinting"

sample-lnd.conf Outdated Show resolved Hide resolved
htlcswitch/hop/iterator.go Outdated Show resolved Hide resolved
invoices/interface.go Show resolved Hide resolved
lnrpc/routerrpc/router_backend.go Show resolved Hide resolved
routing/router.go Show resolved Hide resolved
@ellemouton ellemouton force-pushed the rb-receives branch 3 times, most recently from 08a136e to ed7af80 Compare July 2, 2024 13:19
This commit adds all the logic for building a blinded path (from a given
route) and packaging it up in a zpay32.BlindedPaymentPath struct so that
it is ready for adding to an invoice. It also includes logic for padding
a path with dummy hops.

Note that in this commit, the logic for choosing an actual path to us
that can then be used in a blinded path is abstracted away. This logic
will be fleshed out in a future commit.
Here we add a new `Blind` option to the `AddInvoiceData` which will
signal that the new invoice should encode a blinded route.

Certain other changes are also made in the case that this invoice
contains a blinded route:
1) the payment address/secret no longer needs to be in the invoice
   itself since it will be put in the `PathID` recored of the encrypted
   recipient record for our hop.
2) When we sign the invoice, we now use an ephemeral key since we dont
   want the sender to be able to derive our real node pub key from the
   invoice signature.
3) The invoice's FinalCLTV field should be zero for blinded invoices
   since the CLTV delta info will be communicated in the accumulated
   route policy values.
This commit adds a new function, `findBlindedPaths`, that does a depth
first search from the target node to find a set of blinded paths to the
target node given the set of restrictions. This function will select and
return any candidate path. A candidate path is a path to the target node
with a size determined by the given hop number constraints where all the
nodes on the path signal the route blinding feature _and_ the
introduction node for the path has more than one public channel. Any
filtering of paths based on payment value or success probabilities is
left to the caller.
Add a `FindBlindedPaths` method to the `ChannelRouter` which will use
the new `findBlindedPaths` function to get a set of candidate blinded
path routes. It then uses mission control to select the best of these
paths.

Note that as of this commit, the MC data we get from these queries won't
mean much since we wont have data about a channel in the direction
towards us. But we do this now in preparation for a future PR which will
start writing mission control success pairs for successful receives from
blinded route paths.
Expose the ability to add blinded paths to an invoice. Also expose
various configuration values.

We also let the lncfg.Invoices struct satisfy the Validator interface so
that we can verify all its config values in one place.
In this commit, we expose the option to create an invoice containing
blinded paths to lncli.
In preparation for calling the TLV payload parsing logic recursively for
when we need to peel dummy hops from an onion, this commit creates a new
extractTLVPayload function. This is a pure refactor.
In this refactor commit, we extract all the steps from extractTLVPayload
that have to do with parsing the payload from the sender and verifying
the presence of various fields from the sender.
We further break up the extracTLVPayload into more modular pieces. The
pieces are structured in such a way as to prepare for extracTLVPayload
being called in a recursive manner from within
`deriveBlindedRouteForwardingInfo` when we add the logic for handling
dummy hops in a later commit. With this refactor, we completey remove
the BlindingKit's DecryptAndValidateFwdInfo method.
This will be required to construct a new hop iterator for when peeling
of dummy hops is done for route blinding.
We've covered all the logic for building a blinded path to ourselves and
putting that into an invoice - so now we start preparing to actually be
able to recognise the incoming payment as one from a blinded path we
created.

The incoming update_add_htlc will have an `encrypted_recipient_data`
blob for us that we would have put in the original invoice. From this we
extract the PathID which we wrote. We consider this the payment address
and we use this to derive the associated invoice location.

Blinded path payments will not include MPP records, so the payment
address and total payment amount must be gleaned from the pathID and new
totalAmtMsat onion field respectively.

This commit only covers the final hop payload of a hop in a blinded
path. Dummy hops will be handled in the following commit.
If a blinded path payload contains a signal that the following hop on
the path is a dummy hop, then we iteratively peel the dummy hops until
the final payload is reached.
The route blinding itests are now updated so that recipient logic is
tested. The creation of a blinded route is also now done through the
AddInvoice API instead of manually.
Update the SendPayment flow so that it is able to send to an invoice
containing a blinded path.
Update one of the route blinding itests to do a full end-to-end test
where the recipient generates and invoice with a blinded path and the
sender just provides that invoice to SendPayment.

The tests also covers the edge case where the recipient is the
introduction node.
Make various sender side adjustments so that a sender is able to send an
MP payment to a single blinded path without actually including an MPP
record in the payment.
Add an itest that tests the addition of dummy hops to a blinded path. By
testing that invoices containing such a path can be paid, it also tests
the peeling of dummy hops by the receiver.
Copy link
Collaborator Author

@ellemouton ellemouton left a comment

Choose a reason for hiding this comment

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

Thanks yall.

I've addressed most comments i think. Many i've addressed in new commits at the end so that the OG commits dont need to be changed too much.

Want to emphasise that this PR is mainly about getting initial plumbing into place & i think we could theoretically go around in circles indefinitely if we try get max privacy from the very start. So I really think we should just focus on bare essentials here and we can focus on smaller tweaks later on.
So let me know if there are un-addressed comments you guys feel very strongly about & maybe consider providing a code snippet if possible. I fear the PR is getting way too big.

// NextNodeID is the node ID of the next node on the path. In the
// context of blinded path payments, this is used to indicate the
// presence of dummy hops that need to be peeled from the onion.
NextNodeID tlv.OptionalRecordT[tlv.TlvType4, *btcec.PublicKey]
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

ok so I wrote a test to see what the actual sizes are. It can actually be that the non-final-hop payloads can be more than the average dummy if things fields like the next-blinding-override and/or feature fields are set.

But yeah peeps can probably assume that next-blinding-override and features are not set usually & then can make assumptions from there.

Looks like the change required is quite minimal. So gonna add 👍

// requires for the final hop of the payment.
minFinalCLTVExpiryDelta uint32

// blocksUntilExpiry is the number of blocks that this blinded path
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

i dont think i completely follow (these expiries and cltv's always confuse me 🙃 )

By default:

  • invoice expiry: 24 hours (ie, 144 blocks)
  • blocks till expiry: 288 blocks
  • minFinalCLTVDelta = 83.

why would we want to change minFinalCtlvdelta to 144?

moreover I think we still need to account for the overall max_cltv_delta of a route in general currently in LND (2016 blocks)?

can you elaborate on this part pls?


// dummyHopPolicy holds the policy values that should be used for dummy
// hops. Note that these will _not_ be buffered via addPolicyBuffer.
dummyHopPolicy *blindedHopPolicy
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

ok i've added a commit at the end that does this in a more sophisticated way. Let me know what you think. We just are not gonna get this perfect in this first PR I think

},
minNumHops: cfg.MinNumHops,
// TODO: make configurable
dummyHopPolicy: &blindedHopPolicy{
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

see new commit added at the end of the PR


// FindBlindedPaths finds a selection of paths to the destination node that can
// be used in blinded payment paths.
func (r *ChannelRouter) FindBlindedPaths(destination route.Vertex,
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

sorry im still not sure i follow - we would only see intro nodes & we would not know that the routes are different lengths... so how do we know that one hop is part of the other?


// Don't bother adding a route if its success probability less
// minimum that can be assigned to any single pair.
if totalRouteProbability <= DefaultMinRouteProbability {
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

could you clarify pls? maybe provide a code snippet

This commit introduces more sophisticated code for selecting dummy hop
policy values for dummy hops in blinded paths.

For the case where the path does contain real hops, the dummy hop policy
values are derived by taking the average of those hop polices. For the
case where there are no real hops (in other words, we are the
introduction node), we use the default policy values used for normal
ChannelUpdates but then for the MaxHTLC value, we take the average of
all our open channel capacities.
Copy link
Collaborator

@ziggie1984 ziggie1984 left a comment

Choose a reason for hiding this comment

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

Thank you for this monster-size PR 🥇 high quality material shipping soon :)

Nit Comment:
Maybe we can be more detailed when returning the error requiring hints and blinded paths, meaning that we already consider private channels in the blinded paths therefore there is no need to require them there - just realized this fact :)

if ctx.IsSet("private") && ctx.IsSet("blind") {
		return fmt.Errorf("cannot include both route hints and " +
			"blinded paths in the same invoice")
	}

BaseFee: r.server.cfg.Bitcoin.BaseFee,
MinHTLCMsat: r.server.cfg.Bitcoin.MinHTLCIn,

// MaxHTLCMsat will be calculated on the fly by using
Copy link
Collaborator

Choose a reason for hiding this comment

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

hmm, I think we can be more explicit in the comment and mention also that this only works when we are the introduction point of the route ?

@@ -884,7 +884,9 @@ func testErrorHandlingOnChainFailure(ht *lntest.HarnessTest) {
// The following graph is created where Dave is the destination node, and he
// will choose Carol as the introduction node. The channel capacities are set in
// such a way that Alice will have to split the payment to dave over both the
// A->B->C-D and A->E->C->D routes.
// A->B->C-D and A->E->C->D routes. The Carol-Dave channel will also be made
Copy link
Collaborator

Choose a reason for hiding this comment

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

Nit: C-D => C->D

Copy link
Member

@Roasbeef Roasbeef left a comment

Choose a reason for hiding this comment

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

LGTM 📈

@Roasbeef Roasbeef merged commit 9decf80 into lightningnetwork:master Jul 30, 2024
32 of 34 checks passed
@ellemouton ellemouton deleted the rb-receives branch August 1, 2024 06:42
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
blinded paths invoices P2 should be fixed if one has time
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants