Skip to content

Conversation

ellemouton
Copy link
Collaborator

Adds route blinding receive functionality to hodl invoices.

Fixes #9024

Copy link
Contributor

coderabbitai bot commented Aug 25, 2024

Walkthrough

The changes introduced in this pull request enhance the handling of invoices with blinded paths in the Lightning Network. New command-line flags related to blinded paths have been added to the cmd_invoice.go and invoicesrpc_active.go files. The AddHoldInvoice functionality has been expanded to support these flags, allowing for more complex invoice configurations. Additionally, various structures and methods across multiple files have been updated to accommodate the new features, including modifications to the AddHoldInvoiceRequest message and updates to the RPC server methods. Comprehensive tests for these functionalities have also been implemented.

Changes

File Change Summary
cmd/commands/cmd_invoice.go Added flags for blinded paths: blind, min_real_blinded_hops, num_blinded_hops, max_blinded_paths, blinded_path_omit_node. Updated AddInvoiceCommand structure and addInvoice function to use new flags.
cmd/commands/invoicesrpc_active.go Enhanced addHoldInvoice command with new flags for blinded paths. Integrated blindedPathCfg into AddHoldInvoiceRequest.
docs/release-notes/release-notes-0.19.0.md Updated release notes to reflect new features and enhancements related to blinded paths and RPC endpoints.
itest/lnd_route_blinding_test.go Added tests for HODL invoices with blinded paths, expanded existing tests, and refined the structure for clarity.
lnrpc/invoicesrpc/addinvoice.go Updated AddInvoiceConfig and AddInvoiceData structures to support blinded paths, modified function signatures accordingly.
lnrpc/invoicesrpc/config_active.go Updated Config struct to include new methods for handling blinded paths and invoice features.
lnrpc/invoicesrpc/invoices.proto Added fields is_blinded and blinded_path_config to AddHoldInvoiceRequest message.
lnrpc/invoicesrpc/invoices_server.go Updated AddHoldInvoice method to handle new blinded path configurations and error handling.
rpcserver.go Enhanced AddInvoice method for blinded paths and added new methods for querying routes and generating invoice features.
subrpcserver_config.go Modified PopulateDependencies method to include new parameters for handling blinded paths.

Assessment against linked issues

Objective Addressed Explanation
Expand AddHoldInvoice to use blinded paths (#9024)

🐰 In the meadow, where shadows play,
New flags for invoices come out to sway.
Blinded paths now dance in the light,
HODL invoices take flight, oh what a sight!
With tests and features, the code's a delight,
In the world of finance, we're ready to fight! 🌟


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>, please review it.
    • 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 gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @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 using 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.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

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 added the size/micro small bug fix or feature, less than 15 mins of review, less than 250 label Aug 26, 2024
@ellemouton
Copy link
Collaborator Author

Labeling as Micro review load since this does not require any route blinding knowledge/context. All this does is a bit of refactor of the AddInvoice flow to make the same stuff re-usable for AddHoldInvoice

@saubyk saubyk added this to the v0.19.0 milestone Sep 2, 2024
@ellemouton ellemouton force-pushed the routeblindHoldInvoice branch 2 times, most recently from 0b16e81 to d2d9f3a Compare September 9, 2024 08:15
@ellemouton ellemouton force-pushed the routeblindHoldInvoice branch from d2d9f3a to 6dcfab8 Compare September 23, 2024 02:18
@ellemouton
Copy link
Collaborator Author

cc @saubyk

@ziggie1984
Copy link
Collaborator

@coderabbitai review

Copy link
Contributor

coderabbitai bot commented Oct 2, 2024

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 6

🧹 Outside diff range and nitpick comments (9)
lnrpc/invoicesrpc/invoices.proto (3)

131-143: LGTM! Consider a minor comment improvement.

The addition of is_blinded and blinded_path_config fields to the AddHoldInvoiceRequest message aligns well with the PR objectives to support route blinding for hodl invoices. The implementation looks correct and well-documented.

Consider updating the comment for blinded_path_config to clarify the relationship with is_blinded:

    /*
    Config values to use when creating blinded paths for this invoice. These
    can be used to override the defaults config values provided in by the
-   global config. This field is only used if is_blinded is true.
+   global config. This field is only applicable when is_blinded is set to true.
    */
    lnrpc.BlindedPathConfig blinded_path_config = 12;

This minor change emphasizes the dependency between the two fields more clearly.


Line range hint 1-143: Changes are consistent and maintain backward compatibility.

The additions to the AddHoldInvoiceRequest message are well-integrated into the existing protocol definition:

  1. Backward compatibility is maintained as the new fields are optional.
  2. The AddHoldInvoice RPC method can now support blinded paths without modifying its signature.
  3. The changes are consistent with the existing structure and naming conventions in the file.
  4. Clients using the old version of the protocol will not be affected.

To ensure smooth integration, consider updating any client-side code that generates AddHoldInvoiceRequest messages to include the new fields when appropriate. Also, update the server-side implementation of AddHoldInvoice to handle these new fields correctly.


Line range hint 1-143: Changes align well with PR objectives.

The additions to AddHoldInvoiceRequest directly address the PR objectives of making AddHoldInvoice compatible with route blinding. The implementation approach is consistent with the suggestion in the linked issue (#9024).

Consider updating the following documentation to reflect these changes:

  1. The comment for the AddHoldInvoice RPC method (around line 40) to mention support for blinded paths.
  2. Any relevant API documentation or developer guides that describe the usage of AddHoldInvoice.

This will ensure that developers are aware of the new functionality and how to use it.

cmd/commands/cmd_invoice.go (1)

Line range hint 206-246: LGTM: Well-implemented parseBlindedPathCfg function with a minor suggestion

The parseBlindedPathCfg function is well-implemented, correctly handling the blinded path configuration options. The initial check for the blind flag and the error handling for misconfigurations are good additions.

One minor suggestion for improvement:

Consider enhancing the error handling when decoding the node public keys in the NodeOmissionList. Currently, if the hex decoding fails, the error doesn't provide context about which public key caused the issue. You could improve this by including the problematic public key in the error message:

 for _, pubKey := range ctx.StringSlice(blindedPathNodeOmissions.Name) {
 	pubKeyBytes, err := hex.DecodeString(pubKey)
 	if err != nil {
-		return nil, err
+		return nil, fmt.Errorf("failed to decode node public key %s: %w", pubKey, err)
 	}

 	blindCfg.NodeOmissionList = append(
 		blindCfg.NodeOmissionList, pubKeyBytes,
 	)
 }

This change would make it easier for users to identify and correct any invalid public keys in their command.

lnrpc/invoicesrpc/config_active.go (3)

67-69: Update function comment to reflect new parameter

The comment for GenInvoiceFeatures does not mention the new blinded parameter. Please update the documentation to explain the purpose and effect of this parameter.


84-85: Add parameter names for clarity in BlindedPathCfg

In the BlindedPathCfg function signature, consider naming the parameters to improve readability. For example:

BlindedPathCfg func(useGlobalPolicy bool, config *lnrpc.BlindedPathConfig) (*BlindedPathConfig, error)

93-94: Include parameter names in QueryBlindedRoutes for better readability

For the QueryBlindedRoutes function, adding parameter names enhances code clarity. For example:

QueryBlindedRoutes func(restrictions *routing.BlindedPathRestrictions, amt lnwire.MilliSatoshi) ([]*route.Route, error)
itest/lnd_route_blinding_test.go (2)

611-611: Clarify the added comment for test documentation

The comment on line 611 could be clearer. Consider rephrasing for better readability.

Apply this change:

-// payment. It also tests that blinded paths work for hodl invoices.
+// This test verifies lnd's ability to handle blinded payment paths in invoices,
+// including the creation and settlement of HODL invoices with blinded paths.

695-699: Use dynamic fee limit instead of a hardcoded value

On line 698, the fee limit is hardcoded as FeeLimitSat: 1000000. This may not be suitable for all payment amounts and could cause issues if the payment amount changes.

Consider calculating the fee limit based on the payment amount:

FeeLimitSat: uint64(paymentAmt / 10), // e.g., 10% of the payment amount

Or set it to noFeeLimit if appropriate for the test context.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Files that changed from the base of the PR and between 84c91f7 and 6dcfab8.

⛔ Files ignored due to path filters (2)
  • lnrpc/invoicesrpc/invoices.pb.go is excluded by !**/*.pb.go, !**/*.pb.go
  • lnrpc/invoicesrpc/invoices.swagger.json is excluded by !**/*.json
📒 Files selected for processing (10)
  • cmd/commands/cmd_invoice.go (5 hunks)
  • cmd/commands/invoicesrpc_active.go (2 hunks)
  • docs/release-notes/release-notes-0.19.0.md (1 hunks)
  • itest/lnd_route_blinding_test.go (3 hunks)
  • lnrpc/invoicesrpc/addinvoice.go (6 hunks)
  • lnrpc/invoicesrpc/config_active.go (3 hunks)
  • lnrpc/invoicesrpc/invoices.proto (1 hunks)
  • lnrpc/invoicesrpc/invoices_server.go (3 hunks)
  • rpcserver.go (5 hunks)
  • subrpcserver_config.go (4 hunks)
🧰 Additional context used
🪛 LanguageTool
docs/release-notes/release-notes-0.19.0.md

[grammar] ~29-~29: There seems to be a noun/verb agreement error. Did you mean “receives” or “received”?
Context: ...onal Enhancements * Add route blinding receive functionality to for [hodl invoices]...

(SINGULAR_NOUN_VERB_AGREEMENT)

🪛 Markdownlint
docs/release-notes/release-notes-0.19.0.md

29-29: Expected: dash; Actual: asterisk
Unordered list style

(MD004, ul-style)

🔇 Additional comments (29)
docs/release-notes/release-notes-0.19.0.md (2)

29-29: Maintain consistent list style.

The static analysis tool suggests using a dash instead of an asterisk for the unordered list item. However, the current usage of asterisks is consistent with other list items in the document.

Ignore the static analysis hint in this case to maintain consistency throughout the release notes.

🧰 Tools
🪛 LanguageTool

[grammar] ~29-~29: There seems to be a noun/verb agreement error. Did you mean “receives” or “received”?
Context: ...onal Enhancements * Add route blinding receive functionality to for [hodl invoices]...

(SINGULAR_NOUN_VERB_AGREEMENT)

🪛 Markdownlint

29-29: Expected: dash; Actual: asterisk
Unordered list style

(MD004, ul-style)


Line range hint 1-31: Overall, the release notes accurately reflect the PR objectives.

The addition of route blinding receive functionality for hodl invoices is well-documented in the release notes. This aligns perfectly with the PR objectives and linked issue #9024. The changes are concise and informative, providing users with a clear understanding of the new feature.

Great job on keeping the release notes up-to-date with the latest changes!

🧰 Tools
🪛 LanguageTool

[uncategorized] ~27-~27: Possible missing preposition found.
Context: ...esponse is accurate. # New Features ## Functional Enhancements * Add route blinding rece...

(AI_HYDRA_LEO_MISSING_OF)


[grammar] ~29-~29: There seems to be a noun/verb agreement error. Did you mean “receives” or “received”?
Context: ...onal Enhancements * Add route blinding receive functionality to for [hodl invoices]...

(SINGULAR_NOUN_VERB_AGREEMENT)

🪛 Markdownlint

29-29: Expected: dash; Actual: asterisk
Unordered list style

(MD004, ul-style)


34-34: Expected: dash; Actual: asterisk
Unordered list style

(MD004, ul-style)

cmd/commands/cmd_invoice.go (4)

13-44: LGTM: Well-defined flags for blinded path configuration

The new flags for blinded path configuration are well-defined and clearly explained. The types and naming conventions are appropriate and consistent with the existing codebase.


120-124: LGTM: New flags correctly added to AddInvoiceCommand

The new blinded path flags have been correctly added to the Flags slice in the AddInvoiceCommand structure. The order is logical, with the new flags appended to the existing ones.


192-193: LGTM: Proper handling of blinded path options in addInvoice

The addInvoice function has been correctly updated to handle the new blinded path options. The mutually exclusive check for private and blind flags is a good addition to prevent conflicting configurations.


Line range hint 1-246: Summary: Excellent implementation of blinded path support for invoices

The changes introduced in this file successfully add support for blinded paths in invoice creation. The new flags and their handling are well-implemented and consistent with the existing codebase style. These changes provide users with clear options to configure blinded paths, enhancing the privacy features of the invoicing system.

Key improvements:

  1. Well-defined flags for blinded path configuration
  2. Proper integration of new flags into the AddInvoiceCommand structure
  3. Correct handling of blinded path options in the addInvoice function
  4. A comprehensive parseBlindedPathCfg function for processing blinded path configurations

These changes align well with the PR objectives of introducing route blinding functionality for receiving hodl invoices and making the AddHoldInvoice function compatible with route blinding.

lnrpc/invoicesrpc/config_active.go (1)

67-67: Ensure all usages of GenInvoiceFeatures are updated

The function signature of GenInvoiceFeatures has changed to accept a blinded boolean parameter. Please verify that all implementations and calls to this function are updated to include the new parameter.

Run the following script to identify all usages of GenInvoiceFeatures:

✅ Verification successful

All usages of GenInvoiceFeatures are updated to include the new blinded parameter.

  • lnrpc/invoicesrpc/addinvoice.go: invoiceFeatures = cfg.GenInvoiceFeatures(blind)
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Find all usages of GenInvoiceFeatures in the codebase.

rg 'GenInvoiceFeatures\('

Length of output: 109

cmd/commands/invoicesrpc_active.go (3)

265-266: Confirm that IsBlinded and BlindedPathConfig are correctly added to AddHoldInvoiceRequest

The fields IsBlinded and BlindedPathConfig are added to the AddHoldInvoiceRequest struct. Ensure that these fields are defined in the invoicesrpc.AddHoldInvoiceRequest struct and are compatible with the server-side implementation.

To verify that these fields are defined in the struct, you can run the following script:

#!/bin/bash
# Description: Check that `IsBlinded` and `BlindedPathConfig` are fields in `AddHoldInvoiceRequest`.

# Test: Search for the struct definition and look for the new fields. Expect: Fields are present.

rg --type go --no-heading --line-number 'type AddHoldInvoiceRequest struct' -A 20 | rg -E 'IsBlinded|BlindedPathConfig'

249-253: Ensure parseBlindedPathCfg function is defined and implemented correctly

The function parseBlindedPathCfg(ctx) is called to parse the blinded path configuration from the CLI context. Verify that this function is defined and correctly processes the new flags, returning an appropriate blindedPathCfg and handling errors properly.

To confirm the existence and correctness of parseBlindedPathCfg, you can run the following script:


201-205: Verify that new flags are properly defined and initialized

The new flags blindFlag, minRealBlindedHops, numBlindedHops, maxBlindedPaths, and blindedPathNodeOmissions are added to the addHoldInvoiceCommand. Ensure that these flags are properly defined with appropriate names, usage descriptions, and default values if necessary.

To confirm the definitions of these flags, you can run the following script:

subrpcserver_config.go (1)

286-294: Verify that new fields exist in 'invoicesrpc.Config'

Ensure that the fields BlindedPathCfg, BestHeight, and QueryBlindedRoutes exist in the invoicesrpc.Config struct and are properly defined for use. This is crucial to avoid runtime errors due to missing or misspelled fields.

Run the following script to check if these fields are defined in invoicesrpc.Config:

#!/bin/bash
# Description: Verify that 'invoicesrpc.Config' has the new fields.

# Search for the definition of invoicesrpc.Config and check for the fields.
ast-grep --lang go --pattern $'type Config struct {
    $$$
    BlindedPathCfg func($_)
    BestHeight func() ($_)
    QueryBlindedRoutes func($_)
    $$$
}'
lnrpc/invoicesrpc/invoices_server.go (3)

342-347: Addition of blindedPathCfg with proper error handling

The initialization of blindedPathCfg using s.cfg.BlindedPathCfg and the accompanying error handling are correctly implemented. This ensures that the blinded path configuration is properly set up for the invoice.


360-361: Inclusion of BestHeight and QueryBlindedRoutes in AddInvoiceConfig

The new fields BestHeight and QueryBlindedRoutes are appropriately added to the AddInvoiceConfig struct. This enhances the configuration by providing necessary context for invoice creation with respect to the blockchain height and routing queries.


391-391: Assignment of blindedPathCfg to AddInvoiceData

The assignment of blindedPathCfg to the BlindedPathCfg field in AddInvoiceData is correctly done. This ensures that the blinded path configuration is included when adding the invoice data.

lnrpc/invoicesrpc/addinvoice.go (6)

81-84: Change to GenInvoiceFeatures function signature is acceptable

The function GenInvoiceFeatures has been updated to accept a blinded boolean parameter, enabling feature generation based on whether the invoice includes a blinded path.


100-101: Update to QueryBlindedRoutes function signature is appropriate

The function QueryBlindedRoutes now accepts a *routing.BlindedPathRestrictions parameter, allowing for more precise control over route queries for blinded paths.


179-181: Addition of Restrictions field to BlindedPathConfig

The Restrictions field has been added to BlindedPathConfig, enabling more flexible and precise rules for constructing blinded paths.


489-489: Update to GenInvoiceFeatures call with blind argument

In the AddInvoice function, the call to cfg.GenInvoiceFeatures now includes the blind parameter, ensuring that the correct invoice features are generated based on whether the invoice contains a blinded path.


526-532: Proper handling of blindCfg.Restrictions in FindRoutes

The FindRoutes function now correctly passes blindCfg.Restrictions to cfg.QueryBlindedRoutes, ensuring that route queries adhere to the specified restrictions for blinded paths.


550-550: Set MinNumHops from blindCfg.Restrictions.NumHops

In the call to BuildBlindedPaymentPaths, MinNumHops is now set to blindCfg.Restrictions.NumHops, ensuring that the blinded path construction adheres to the minimum number of hops specified in the restrictions.

itest/lnd_route_blinding_test.go (2)

14-14: Import invoicesrpc package is necessary for AddHoldInvoice

The import of github.com/lightningnetwork/lnd/lnrpc/invoicesrpc on line 14 is necessary as the AddHoldInvoice function from this package is used later in the code (e.g., line 676).


714-715: Ensure payment status assertion is reliable

The assertion on line 715 checks that Alice's payment status is SUCCEEDED. Verify that there are no race conditions that might cause intermittent failures in test environments.

To confirm, you might inspect the payment status before asserting:

status := ht.AssertPaymentStatus(ht.Alice, preimage, lnrpc.Payment_SUCCEEDED)
require.Equal(ht, lnrpc.Payment_SUCCEEDED, status)
rpcserver.go (7)

5988-6001: Ensure proper initialization of AddInvoiceConfig

The AddInvoiceConfig struct is being initialized with new fields GenInvoiceFeatures, GenAmpInvoiceFeatures, BestHeight, and QueryBlindedRoutes. Verify that these fields are correctly handled downstream and that they integrate seamlessly with existing logic.

Ensure that the functions r.genInvoiceFeatures and r.queryBlindedRoutes are properly implemented and that they align with the expected interfaces.


6015-6019: Handle possible errors from blindedPathCfg

When calling r.blindedPathCfg, the error is checked immediately after the call. This is good practice to ensure any issues are caught promptly.


8727-8736: Verify feature bits adjustments for blinded paths

When blind is true, the code unsets PaymentAddrRequired and sets PaymentAddrOptional. Ensure that this adjustment complies with the protocol and that all clients interacting with these invoices can handle the absence of a payment address.

Confirm that unsetting PaymentAddrRequired and setting Bolt11BlindedPathsRequired align with the BOLT specifications for blinded payments.


8798-8801: Ensure proper type conversion for fee parameters

When assigning values to FeeRate and BaseFee, ensure that the data types match and that value ranges are appropriate.

Check that r.server.cfg.Bitcoin.FeeRate and r.server.cfg.Bitcoin.BaseFee fit within uint32 without loss of precision or overflow.


774-775: ⚠️ Potential issue

Consider handling possible negative bestHeight

The code converts bestHeight to uint32 without checking for potential negative values. Although block heights are typically non-negative, adding a check can prevent unexpected behavior if an error occurs.

Consider adding a check for negative bestHeight before casting:

 func() (uint32, error) {
   _, bestHeight, err := r.server.cc.ChainIO.GetBestBlock()
+  if bestHeight < 0 {
+    return 0, fmt.Errorf("bestHeight cannot be negative")
+  }
   return uint32(bestHeight), err
 }

795-795: 🛠️ Refactor suggestion

⚠️ Potential issue

Typo in function name updateAndBrodcastSelfNode

There is a typo in the function name updateAndBrodcastSelfNode. It should be updateAndBroadcastSelfNode.

Apply this diff to correct the typo:

- s.getNodeAnnouncement, s.updateAndBrodcastSelfNode, parseAddr,
+ s.getNodeAnnouncement, s.updateAndBroadcastSelfNode, parseAddr,

Ensure that all references to this function are updated accordingly.

Likely invalid or redundant comment.


8751-8754: 🛠️ Refactor suggestion

⚠️ Potential issue

Unreachable condition due to prior return

The condition if cfg != nil && !blind (line 8751) is unreachable because the function returns early if !blind is true (line 8747). This makes the condition redundant.

Remove the unreachable condition to clean up the code:

- if cfg != nil && !blind {
-     return nil, fmt.Errorf("blinded path config provided but IsBlinded not set")
- }

Likely invalid or redundant comment.

Comment on lines +28 to +31

* Add route blinding receive functionality to for [hodl
invoices](https://github.com/lightningnetwork/lnd/pull/9034).

Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue

Improve grammar and clarity in the new feature description.

The sentence structure in this new feature description can be improved for better clarity and grammatical correctness.

Consider applying the following changes:

-* Add route blinding receive functionality to for [hodl 
-  invoices](https://github.com/lightningnetwork/lnd/pull/9034).
+* Add route blinding receive functionality for [hodl 
+  invoices](https://github.com/lightningnetwork/lnd/pull/9034).

This change removes the redundant "to" and improves the overall readability of the sentence.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
* Add route blinding receive functionality to for [hodl
invoices](https://github.com/lightningnetwork/lnd/pull/9034).
* Add route blinding receive functionality for [hodl
invoices](https://github.com/lightningnetwork/lnd/pull/9034).
🧰 Tools
🪛 LanguageTool

[grammar] ~29-~29: There seems to be a noun/verb agreement error. Did you mean “receives” or “received”?
Context: ...onal Enhancements * Add route blinding receive functionality to for [hodl invoices]...

(SINGULAR_NOUN_VERB_AGREEMENT)

🪛 Markdownlint

29-29: Expected: dash; Actual: asterisk
Unordered list style

(MD004, ul-style)

Comment on lines +123 to +136
genInvoiceFeatures func(bool) *lnwire.FeatureVector,
genAmpInvoiceFeatures func() *lnwire.FeatureVector,
getNodeAnnouncement func() lnwire.NodeAnnouncement,
updateNodeAnnouncement func(features *lnwire.RawFeatureVector,
modifiers ...netann.NodeAnnModifier) error,
parseAddr func(addr string) (net.Addr, error),
rpcLogger btclog.Logger, aliasMgr *aliasmgr.Manager,
auxDataParser fn.Option[AuxDataParser],
invoiceHtlcModifier *invoices.HtlcModificationInterceptor) error {
invoiceHtlcModifier *invoices.HtlcModificationInterceptor,
bestHeight func() (uint32, error),
blindedPathCfg func(blind bool, cfg *lnrpc.BlindedPathConfig) (
*invoicesrpc.BlindedPathConfig, error),
queryBlindedRoutes func(*routing.BlindedPathRestrictions,
lnwire.MilliSatoshi) ([]*route.Route, error)) error {
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Consider refactoring 'PopulateDependencies' to reduce parameter list

The PopulateDependencies function now has over 30 parameters. This long parameter list can affect readability and maintainability. Consider refactoring by grouping related parameters into structs or passing a configuration object to simplify the function signature.

Comment on lines +131 to +136
invoiceHtlcModifier *invoices.HtlcModificationInterceptor,
bestHeight func() (uint32, error),
blindedPathCfg func(blind bool, cfg *lnrpc.BlindedPathConfig) (
*invoicesrpc.BlindedPathConfig, error),
queryBlindedRoutes func(*routing.BlindedPathRestrictions,
lnwire.MilliSatoshi) ([]*route.Route, error)) error {
Copy link
Contributor

Choose a reason for hiding this comment

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

💡 Codebase verification

PopulateDependencies Calls Not Updated

The following calls to PopulateDependencies do not match the updated function signature:

  • subrpcserver_config.go:107 - Arguments passed: 2
  • rpcserver.go:787 - Arguments passed: 1

Please update these function calls to include all required parameters.

🔗 Analysis chain

Ensure all callers of 'PopulateDependencies' are updated

With the addition of new parameters to the PopulateDependencies function, ensure that all function calls are updated accordingly to match the new signature. This will prevent build errors and potential runtime issues.

Run the following script to search for all calls to PopulateDependencies and verify they have the correct number of arguments:

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Find all usages of PopulateDependencies and display their function signatures.

# Search for the function definition to get the parameter count.
rg --type go --max-depth 1 -A 5 'func \(s \*subRPCServerConfigs\) PopulateDependencies' 

# Search for all calls to PopulateDependencies in the codebase.
rg --type go 'PopulateDependencies\('

Length of output: 430


Script:

#!/bin/bash
# Description: Find all calls to PopulateDependencies and count the number of arguments passed in each call.

# Search for all calls to PopulateDependencies and extract the lines containing the calls
rg --type go 'PopulateDependencies\(' -n | while IFS= read -r line; do
    filepath=$(echo "$line" | cut -d: -f1)
    lineno=$(echo "$line" | cut -d: -f2)
    call=$(echo "$line" | cut -d: -f3-)
    # Count the number of commas to estimate the number of arguments
    arg_count=$(echo "$call" | grep -o "," | wc -l)
    # Add one to represent the total number of arguments
    total_args=$((arg_count + 1))
    echo "$filepath:$lineno - Arguments passed: $total_args"
done

Length of output: 1340

Comment on lines +673 to +687
minNumRealHops = 2
numHops = 2
hodlResp := testCase.dave.RPC.AddHoldInvoice(
&invoicesrpc.AddHoldInvoiceRequest{
Memo: "test",
Hash: hash[:],
ValueMsat: 10_000_000,
IsBlinded: true,
BlindedPathConfig: &lnrpc.BlindedPathConfig{
MinNumRealHops: &minNumRealHops,
NumHops: &numHops,
},
},
)

Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Extract repeated code into a helper function to avoid duplication

The code block from lines 673-687 duplicates the logic for creating a HODL invoice with blinded path configuration. Extracting this into a helper function enhances maintainability.

Consider adding a helper function:

func addBlindedHoldInvoice(dave *node.HarnessNode, preimage lntypes.Preimage) *invoicesrpc.AddHoldInvoiceResp {
	var (
		minNumRealHops uint32 = 2
		numHops        uint32 = 2
	)
	hash := preimage.Hash()
	return dave.RPC.AddHoldInvoice(
		&invoicesrpc.AddHoldInvoiceRequest{
			Memo:      "test",
			Hash:      hash[:],
			ValueMsat: 10_000_000,
			IsBlinded: true,
			BlindedPathConfig: &lnrpc.BlindedPathConfig{
				MinNumRealHops: &minNumRealHops,
				NumHops:        &numHops,
			},
		},
	)
}

Then replace lines 673-687 with:

hodlResp := addBlindedHoldInvoice(testCase.dave, preimage)

Comment on lines +8707 to +8714
restrictions *routing.BlindedPathRestrictions,
amt lnwire.MilliSatoshi) ([]*route.Route, error) {

return r.server.chanRouter.FindBlindedPaths(
r.selfNode, amt, r.server.missionControl.GetProbability,
restrictions,
)
}
Copy link
Contributor

@coderabbitai coderabbitai bot Oct 2, 2024

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Add error context in queryBlindedRoutes

The function queryBlindedRoutes returns the result of FindBlindedPaths without adding context to potential errors. Enhancing error messages can aid in debugging.

Modify the function to wrap the error for more clarity:

 func (r *rpcServer) queryBlindedRoutes(
   restrictions *routing.BlindedPathRestrictions,
   amt lnwire.MilliSatoshi) ([]*route.Route, error) {

-  return r.server.chanRouter.FindBlindedPaths(
+  routes, err := r.server.chanRouter.FindBlindedPaths(
     r.selfNode, amt, r.server.missionControl.GetProbability,
     restrictions,
   )
+  if err != nil {
+    return nil, fmt.Errorf("failed to find blinded paths: %w", err)
+  }
+  return routes, nil
 }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
restrictions *routing.BlindedPathRestrictions,
amt lnwire.MilliSatoshi) ([]*route.Route, error) {
return r.server.chanRouter.FindBlindedPaths(
r.selfNode, amt, r.server.missionControl.GetProbability,
restrictions,
)
}
restrictions *routing.BlindedPathRestrictions,
amt lnwire.MilliSatoshi) ([]*route.Route, error) {
routes, err := r.server.chanRouter.FindBlindedPaths(
r.selfNode, amt, r.server.missionControl.GetProbability,
restrictions,
)
if err != nil {
return nil, fmt.Errorf("failed to find blinded paths: %w", err)
}
return routes, nil
}

Copy link
Collaborator

Choose a reason for hiding this comment

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

I think this log makes sense wdyt @ellemouton

Copy link
Contributor

Choose a reason for hiding this comment

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

Seems like the humans are having a chat. I'll hop back into my burrow for now. If you need me again, just tag @coderabbitai in a new comment, and I'll come hopping out!

Comment on lines +8767 to +8776
if cfg.MinNumRealHops != nil {
restrictions.MinDistanceFromIntroNode =
uint8(*cfg.MinNumRealHops)
}
if cfg.NumHops != nil {
restrictions.NumHops = uint8(*cfg.NumHops)
}
if cfg.MaxNumPaths != nil {
restrictions.MaxNumPaths = uint8(*cfg.MaxNumPaths)
}
Copy link
Contributor

@coderabbitai coderabbitai bot Oct 2, 2024

Choose a reason for hiding this comment

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

⚠️ Potential issue

Check for value overflows when casting to uint8

Casting configuration values to uint8 without validation may result in overflow if the values exceed 255.

Add validation to ensure values are within uint8 range:

 if cfg.MinNumRealHops != nil {
+   if *cfg.MinNumRealHops > 255 {
+     return nil, fmt.Errorf("MinNumRealHops exceeds uint8 max value")
+   }
    restrictions.MinDistanceFromIntroNode = uint8(*cfg.MinNumRealHops)
 }
 if cfg.NumHops != nil {
+   if *cfg.NumHops > 255 {
+     return nil, fmt.Errorf("NumHops exceeds uint8 max value")
+   }
    restrictions.NumHops = uint8(*cfg.NumHops)
 }
 if cfg.MaxNumPaths != nil {
+   if *cfg.MaxNumPaths > 255 {
+     return nil, fmt.Errorf("MaxNumPaths exceeds uint8 max value")
+   }
    restrictions.MaxNumPaths = uint8(*cfg.MaxNumPaths)
 }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
if cfg.MinNumRealHops != nil {
restrictions.MinDistanceFromIntroNode =
uint8(*cfg.MinNumRealHops)
}
if cfg.NumHops != nil {
restrictions.NumHops = uint8(*cfg.NumHops)
}
if cfg.MaxNumPaths != nil {
restrictions.MaxNumPaths = uint8(*cfg.MaxNumPaths)
}
if cfg.MinNumRealHops != nil {
if *cfg.MinNumRealHops > 255 {
return nil, fmt.Errorf("MinNumRealHops exceeds uint8 max value")
}
restrictions.MinDistanceFromIntroNode =
uint8(*cfg.MinNumRealHops)
}
if cfg.NumHops != nil {
if *cfg.NumHops > 255 {
return nil, fmt.Errorf("NumHops exceeds uint8 max value")
}
restrictions.NumHops = uint8(*cfg.NumHops)
}
if cfg.MaxNumPaths != nil {
if *cfg.MaxNumPaths > 255 {
return nil, fmt.Errorf("MaxNumPaths exceeds uint8 max value")
}
restrictions.MaxNumPaths = uint8(*cfg.MaxNumPaths)
}

Copy link
Collaborator

Choose a reason for hiding this comment

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

I think overflow checks are reasonable.

Copy link
Contributor

Choose a reason for hiding this comment

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

@ziggie1984, I'm glad you agree. Adding overflow checks will help prevent potential value overflows.

(_/)
( •ᴗ•)
(ᵔᵕᵔ)

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.

Can we add itests for the blinded hodlinvoice payment ?

Found buggy behaviour when testing with LND instances:

Created hodlinvoice on Node A

Paid it from Node C (NODE B is the intronode)

Payment reaches Node A - so far so good.

Now I cancel the hodlinvoice on Node A:

Now weird stuff happens, Node C goes crazy and retries the payment all over again:

Description:
Amount (in satoshis): 1000
Fee limit (in satoshis): 1000
Destination: 02acfc299123c6f01d3a116ebbcd10460a26b56b4067c2c5652f467fa2e3d233e4
Confirm payment (yes/no): yes
+----------------------------------+--------------+--------------+--------------+-------+----------+-----------------+-----------------------+
| HTLC_STATE                       | ATTEMPT_TIME | RESOLVE_TIME | RECEIVER_AMT | FEE   | TIMELOCK | CHAN_OUT        | ROUTE                 |
+----------------------------------+--------------+--------------+--------------+-------+----------+-----------------+-----------------------+
| INVALID_ONION_BLINDING @ 1st hop |        0.031 |       11.271 | 1000         | 2.204 |      700 | 479387069775872 | alice->032e4b->02efe1 |
| INVALID_ONION_BLINDING @ 1st hop |       11.295 |       11.909 | 1000         | 2.204 |      700 | 479387069775872 | alice->032e4b->02efe1 |
| INVALID_ONION_BLINDING @ 1st hop |       11.938 |       12.556 | 1000         | 2.204 |      700 | 479387069775872 | alice->032e4b->02efe1 |
| INVALID_ONION_BLINDING @ 1st hop |       12.605 |       13.198 | 1000         | 2.204 |      700 | 479387069775872 | alice->032e4b->02efe1 |
| IN_FLIGHT                        |       13.226 |            - | 1000         | 2.204 |      700 | 479387069775872 | alice->032e4b->02efe1 |
+----------------------------------+--------------+--------------+--------------+-------+----------+-----------------+-----------------------+
Amount + fee:   0 + 0 sat
Payment hash:   c472a6497526c9ed8e59ba3063e20b8040580c52135d90390e533e2177081db4
Payment status: IN_FLIGHT
^C[lncli] rpc error: code = Canceled desc = context canceled

if I do not cancel this goes on for a very long time.

==
Success Case works like charm.

// containing the blinded path, so we switch
// the bit to required.
v.Unset(lnwire.Bolt11BlindedPathsOptional)
v.Set(lnwire.Bolt11BlindedPathsRequired)
Copy link
Collaborator

Choose a reason for hiding this comment

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

I think we should also check for dependencies here maybe ?

Will be handled in #9143

// understand the new BOLT 11 tagged field
// containing the blinded path, so we switch
// the bit to required.
v.Unset(lnwire.Bolt11BlindedPathsOptional)
Copy link
Collaborator

Choose a reason for hiding this comment

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

I wonder if we could remove this bit from defaultSetDesc and only set it and its defaults here ?

Comment on lines +8707 to +8714
restrictions *routing.BlindedPathRestrictions,
amt lnwire.MilliSatoshi) ([]*route.Route, error) {

return r.server.chanRouter.FindBlindedPaths(
r.selfNode, amt, r.server.missionControl.GetProbability,
restrictions,
)
}
Copy link
Collaborator

Choose a reason for hiding this comment

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

I think this log makes sense wdyt @ellemouton

Comment on lines +8749 to +8752
bpConfig := r.server.cfg.Routing.BlindedPaths
defaultDelta := r.cfg.Bitcoin.TimeLockDelta

globalBlindCfg := r.server.cfg.Routing.BlindedPaths
Copy link
Collaborator

Choose a reason for hiding this comment

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

why 2 times the same variable ?

Comment on lines +8767 to +8776
if cfg.MinNumRealHops != nil {
restrictions.MinDistanceFromIntroNode =
uint8(*cfg.MinNumRealHops)
}
if cfg.NumHops != nil {
restrictions.NumHops = uint8(*cfg.NumHops)
}
if cfg.MaxNumPaths != nil {
restrictions.MaxNumPaths = uint8(*cfg.MaxNumPaths)
}
Copy link
Collaborator

Choose a reason for hiding this comment

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

I think overflow checks are reasonable.

Comment on lines +8740 to +8742
if !blind {
return nil, nil
}
Copy link
Collaborator

Choose a reason for hiding this comment

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

could we define the config as an option so we can remove the blinded param which feels somehow hacky ?

@ziggie1984
Copy link
Collaborator

Hmm thought about it now and I think the cancel payment can really be a problem for Hodlinvoices, because nodes will convert the error of the final node into an INVALID_ONION_BLINDING error, so we have no chance to know whether the destination canceled or an intermediate node failed the payment ?

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.

Very nice, did a first pass, nothing that stands out rn 👍. As ziggie mentioned, an itest for invoice cancellation would be great, but will also do some manual tests in the next round.

Hmm thought about it now and I think the cancel payment can really be a problem for Hodlinvoices, because nodes will convert the error of the final node into an INVALID_ONION_BLINDING error, so we have no chance to know whether the destination canceled or an intermediate node failed the payment ?

Right, there's nothing we can really do I think, but the sender needs to deal with this and be smart enough to recognize it's not possible to pay, by exhausting all blinded paths. If it results in an endless loop, we'd need to revisit the error attribution.

// blindedPathCfg takes the global routing blinded path policies and the given
// per-payment blinded path config values and uses these to construct the config
// values passed to the invoice server.
func (r *rpcServer) blindedPathCfg(blind bool, cfg *lnrpc.BlindedPathConfig) (
Copy link
Collaborator

Choose a reason for hiding this comment

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

nice extraction 🎉

}

bpConfig := r.server.cfg.Routing.BlindedPaths
defaultDelta := r.cfg.Bitcoin.TimeLockDelta
Copy link
Collaborator

Choose a reason for hiding this comment

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

nit: we could set that directly

@ziggie1984
Copy link
Collaborator

Right, there's nothing we can really do I think, but the sender needs to deal with this and be smart enough to recognize it's not possible to pay, by exhausting all blinded paths. If it results in an endless loop, we'd need to revisit the error attribution.

I believe we should explore the “attribute error” approach if we want to implement hold-blinded invoices. It seems unlikely that we can devise a smart way to detect when the receiver cancels the invoice.

While we could theoretically try all possible paths, we also need to consider the behavior of our MPP logic. Currently, it would attempt to send smaller chunks through paths that had previously failed for the original amount, which could significantly increase processing time. Additionally, this could lead to unnecessary payments, and in the worst case, result in on-chain resolutions.

From my current perspective, we should avoid introducing this change without a reliable way to identify the final node and handle the error message for blinded payments.

@lightninglabs-deploy
Copy link

@ellemouton, remember to re-request review from reviewers when ready

@ellemouton
Copy link
Collaborator Author

!lightninglabs-deploy mute

@saubyk saubyk removed this from the v0.19.0 milestone Jan 23, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
blinded paths size/micro small bug fix or feature, less than 15 mins of review, less than 250
Projects
None yet
Development

Successfully merging this pull request may close these issues.

[feature]: expand AddHoldInvoice to use blinded paths
6 participants