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

Expose cltv_expiry flag of addinvoice to cli #8491

Merged
merged 3 commits into from
Jun 4, 2024

Conversation

davidgumberg
Copy link
Contributor

@davidgumberg davidgumberg commented Feb 19, 2024

This PR allows users of the lncli RPC interface to set the min_final_cltv_expiry_delta described in BOLT's 11, 7, and 2 by setting the cltv_expiry flag when calling either addinvoice or addholdinvoice.

It also fixes an error message in lnrpc/invoicesrpc/addinvoice.go which printed the user-set CltvExpiry and the minimum allowed CltvExpiry in the wrong order when a value that was too low was used.

I can add a release note if that seems like a good idea.

Steps to Test

To test this change, run addinvoice or addholdinvoice and set a cltv_expiry value.

Pull Request Checklist

Testing

  • Your PR passes all CI checks.
  • Tests covering the positive and negative (error paths) are included.
  • Bug fixes contain tests triggering the bug to prevent regressions.

Code Style and Documentation

📝 Please see our Contribution Guidelines for further guidance.

Summary by CodeRabbit

  • New Features
    • Introduced a new option for setting the minimum CLTV delta for the final hop on invoices, enhancing flexibility for users.
  • Bug Fixes
    • Improved the clarity and accuracy of error messages when setting a CLTV delta below the required minimum.
  • Tests
    • Added tests to validate the functionality and error handling of the new CLTV delta setting on invoices.

Copy link
Contributor

coderabbitai bot commented Feb 19, 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.

Walkthrough

The recent updates introduce a new cltv_expiry flag for invoice commands, enhancing the flexibility in setting the minimum CLTV delta for the final hop. This allows users to define a custom CLTV delta, adhering more closely to their needs or preferences. Additionally, error messaging for non-compliant CLTV deltas has been improved for better clarity. New test cases ensure the functionality works as expected, and an assertion function for error handling in tests has been added.

Changes

File Path Change Summary
cmd/lncli/cmd_invoice.go, lnrpc/invoicesrpc/addinvoice.go Introduced cltv_expiry flag for setting minimum CLTV delta; improved error messaging for CLTV delta constraints.
cmd/lncli/invoicesrpc_active.go Added cltv_expiry flag to addHoldInvoiceCommand for specifying minimum CLTV delta.
itest/list_on_test.go, itest/lnd_misc_test.go Added tests for the cltv_expiry flag functionality and error handling.
lntest/rpc/lnd.go Added AddInvoiceAssertErr function for error assertion in RPC calls.

Related issues

Poem

In the land of code, where the bits do hop,
A rabbit tweaked the time, not with a clock, but a hop!
🕒🐰 With flags anew, in the ledger's stew,
Errors clear, and tests to cheer, through and through.
"Hop with care, and time to spare," it said with glee,
For a smoother path, in the crypto sea. 🌊🥕


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 Configration 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.

@davidgumberg
Copy link
Contributor Author

@coderabbitai review

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.

Review Status

Actionable comments generated: 1

Configuration used: CodeRabbit UI

Commits Files that changed from the base of the PR and between a3bf2c7 and cfceb97d133c9b48a3cf604efb540990564dce23.
Files selected for processing (6)
  • cmd/lncli/cmd_invoice.go (2 hunks)
  • cmd/lncli/invoicesrpc_active.go (2 hunks)
  • itest/list_on_test.go (1 hunks)
  • itest/lnd_misc_test.go (2 hunks)
  • lnrpc/invoicesrpc/addinvoice.go (1 hunks)
  • lntest/rpc/lnd.go (1 hunks)
Additional comments: 7
cmd/lncli/invoicesrpc_active.go (2)
  • 187-194: The addition of the cltv_expiry flag to the addHoldInvoiceCommand and its usage in setting the CltvExpiry field in the AddHoldInvoiceRequest struct aligns well with the PR's objectives. It's important to ensure that the default behavior when the flag is not set (or set to 0) adheres to the system's default cltv_expiry value as per the BOLT specifications and the existing configuration (bitcoin.timelockdelta option).
  • 251-251: Setting the CltvExpiry field in the AddHoldInvoiceRequest based on the cltv_expiry flag value is correctly implemented. This change allows users to specify the minimum CLTV delta for the final hop, enhancing the flexibility of invoice creation in LND.
cmd/lncli/cmd_invoice.go (2)
  • 63-70: The addition of the cltv_expiry flag to the addInvoiceCommand and its usage in setting the CltvExpiry field in the Invoice struct aligns well with the PR's objectives. It's important to ensure that the default behavior when the flag is not set (or set to 0) adheres to the system's default cltv_expiry value as per the BOLT specifications and the existing configuration (bitcoin.timelockdelta option).
  • 138-138: Setting the CltvExpiry field in the Invoice struct based on the cltv_expiry flag value is correctly implemented. This change allows users to specify the minimum CLTV delta for the final hop, enhancing the flexibility of invoice creation in LND.
itest/list_on_test.go (1)
  • 192-195: The addition of the "invoice cltv expiry flag" test case is a positive step towards ensuring the new functionality works as expected and error handling is correctly implemented. It's important that this test case covers scenarios with valid cltv_expiry values and error cases with values outside the acceptable range to ensure comprehensive testing.
lntest/rpc/lnd.go (1)
  • 295-303: The implementation of AddInvoiceAssertErr correctly follows the pattern established by other methods in HarnessRPC for making RPC calls and asserting the outcome. It properly uses a context with a timeout, cleans up resources with defer cancel(), and uses require.Error to assert that an error is expected from the AddInvoice call. This addition enhances the test harness's ability to validate error scenarios, which is crucial for robust testing.

However, it would be beneficial to include a comment explaining the specific error scenarios this function is intended to test. While the function's purpose is somewhat clear from its name and implementation, a brief comment could help future maintainers understand the context in which it should be used or if there are any specific error conditions it's particularly useful for.

lnrpc/invoicesrpc/addinvoice.go (1)
  • 368-370: The updated error message in the AddInvoice function now correctly reflects the order of the user-set CltvExpiry and the minimum required CltvExpiry when the provided value is too low. This change improves the clarity and accuracy of feedback provided to users in error scenarios. The modification aligns with the PR's objective to enhance user experience by providing more informative error messages. The logic and syntax of the change are correct, and it adheres to the project's code style guidelines.

Comment on lines 1246 to 1304

// testInvoiceCltvExpiryFlag ensures that the CltvExpiry option passed to the
// AddInvoice RPC interface sets `min_final_cltv_expiry_delta` in the invoice
// and that it fails when a cltv too small or too large is passed
func testInvoiceCltvExpiryFlag(ht *lntest.HarnessTest) {
// Set up a node
alice := ht.Alice

// Create an invoice with a CltvExpiry set
const paymentAmt = 1000
min_cltv_delta := uint64(100)
invoice := &lnrpc.Invoice{
Value: paymentAmt,
CltvExpiry: min_cltv_delta,
}

// Add the invoice and use the decodepayreq rpc to parse it
invoiceResp := alice.RPC.AddInvoice(invoice)
payReq := alice.RPC.DecodePayReq(invoiceResp.PaymentRequest)

// Requested CltvExpiry must equal what decodepayreq reports as the
// cltv_expiry of the invoice
require.Equal(ht, uint64(payReq.CltvExpiry), min_cltv_delta)

// Set the min_cltv delta to a value lower than router.MinCLTVDelta
// which is the minimum value permitted. (18 in February 2024) and
// assert an error when adding invoice
min_cltv_delta = uint64(17)
invoice = &lnrpc.Invoice{
Value: paymentAmt,
CltvExpiry: min_cltv_delta,
}
alice.RPC.AddInvoiceAssertErr(invoice)

// Set the min_cltv delta to a value greater than math.MaxUint16
// which is the maximum value permitted and assert an error when
// adding the invoice
min_cltv_delta = uint64(math.MaxUint16 + 1)
invoice = &lnrpc.Invoice{
Value: paymentAmt,
CltvExpiry: min_cltv_delta,
}
alice.RPC.AddInvoiceAssertErr(invoice)
}
Copy link
Contributor

Choose a reason for hiding this comment

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

The test function testInvoiceCltvExpiryFlag correctly implements the functionality to test setting the min_final_cltv_expiry_delta in an invoice through the CltvExpiry field. It checks for the expected behavior when a valid CltvExpiry is set and asserts errors for values too small or too large. However, there are a few improvements and clarifications that could enhance the test:

  1. Clarify Expected Error: When asserting errors for CltvExpiry values too small or too large, it would be helpful to specify the expected error message or type. This ensures that the test fails for the right reasons and provides clearer documentation for the expected behavior.

  2. Use Constants for Magic Numbers: The test uses magic numbers for the CltvExpiry values (e.g., 17, math.MaxUint16 + 1). It would improve readability and maintainability to define these as constants at the beginning of the test or use existing constants if they are defined elsewhere in the codebase. This makes it clear what these values represent and why they are significant.

  3. Comment on router.MinCLTVDelta Reference: The comment mentions router.MinCLTVDelta as the minimum value permitted for CltvExpiry, but this value is hardcoded in the test (17). If router.MinCLTVDelta is accessible from the test context, consider using it directly in the test to avoid discrepancies if the minimum value changes in the future. If not accessible, clarify in the comment that the hardcoded value should be kept in sync with router.MinCLTVDelta.

  4. Error Handling Verification: For the error assertions (alice.RPC.AddInvoiceAssertErr(invoice)), ensure that the test framework's AddInvoiceAssertErr method checks for specific errors related to CltvExpiry being too low or too high. This ties back to the first point about clarifying expected errors.

Overall, the test function is well-structured and targets the intended functionality effectively. Implementing these suggestions would further solidify the test's robustness and clarity.

- // Set the min_cltv delta to a value lower than router.MinCLTVDelta
+ // Set the min_cltv delta to a value lower than router.MinCLTVDelta (18 as of February 2024)
+ // Note: If router.MinCLTVDelta is accessible here, use it directly to avoid hardcoding.

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.

Suggested change
// testInvoiceCltvExpiryFlag ensures that the CltvExpiry option passed to the
// AddInvoice RPC interface sets `min_final_cltv_expiry_delta` in the invoice
// and that it fails when a cltv too small or too large is passed
func testInvoiceCltvExpiryFlag(ht *lntest.HarnessTest) {
// Set up a node
alice := ht.Alice
// Create an invoice with a CltvExpiry set
const paymentAmt = 1000
min_cltv_delta := uint64(100)
invoice := &lnrpc.Invoice{
Value: paymentAmt,
CltvExpiry: min_cltv_delta,
}
// Add the invoice and use the decodepayreq rpc to parse it
invoiceResp := alice.RPC.AddInvoice(invoice)
payReq := alice.RPC.DecodePayReq(invoiceResp.PaymentRequest)
// Requested CltvExpiry must equal what decodepayreq reports as the
// cltv_expiry of the invoice
require.Equal(ht, uint64(payReq.CltvExpiry), min_cltv_delta)
// Set the min_cltv delta to a value lower than router.MinCLTVDelta
// which is the minimum value permitted. (18 in February 2024) and
// assert an error when adding invoice
min_cltv_delta = uint64(17)
invoice = &lnrpc.Invoice{
Value: paymentAmt,
CltvExpiry: min_cltv_delta,
}
alice.RPC.AddInvoiceAssertErr(invoice)
// Set the min_cltv delta to a value greater than math.MaxUint16
// which is the maximum value permitted and assert an error when
// adding the invoice
min_cltv_delta = uint64(math.MaxUint16 + 1)
invoice = &lnrpc.Invoice{
Value: paymentAmt,
CltvExpiry: min_cltv_delta,
}
alice.RPC.AddInvoiceAssertErr(invoice)
}
// Set the min_cltv delta to a value lower than router.MinCLTVDelta (18 as of February 2024)
// Note: If router.MinCLTVDelta is accessible here, use it directly to avoid hardcoding.

@davidgumberg davidgumberg force-pushed the invoice_cltv_expiry branch 2 times, most recently from 86199e9 to 9df3821 Compare February 20, 2024 22:04
Copy link
Collaborator

@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 for the contribution @davidgumberg!

Looks good so far! left some comments :)

Also, please see our contribution guidelines for how to structure the title of your commits :)

// testInvoiceCltvExpiryFlag ensures that the CltvExpiry option passed to the
// AddInvoice RPC interface sets `min_final_cltv_expiry_delta` in the invoice
// and that it fails when a cltv too small or too large is passed.
func testInvoiceCltvExpiryFlag(ht *lntest.HarnessTest) {
Copy link
Collaborator

Choose a reason for hiding this comment

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

interested in hearing an opinion from another reviewer too but I personally dont think this warrants an integration test. This might be more appropriate in a unit test for the invoicesrpc.AddInvoice function

Copy link
Contributor Author

@davidgumberg davidgumberg Mar 12, 2024

Choose a reason for hiding this comment

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

The only problem with a unit test is that AFAICT a lot of mocking would be required: we would need a NodeSigner and an InvoiceRegistry in order to test invoicesrpc.AddInvoice. I would be happy to do it if you think that's the right approach

Copy link
Collaborator

Choose a reason for hiding this comment

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

To me this might be a case were manual testing alone might be good enough. Especially since no new logic is being tested here. ie, this is not testing something added in this PR.

If we really want to tests this through an itest, perhaps there is another test we can append...

But again - would like another reviewers opinion here 🙏

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I've rebased and dropped the tests from this PR

@davidgumberg
Copy link
Contributor Author

@ellemouton Thank you very much for the review! I've tried to address all your points except for whether or not the test I've added should be an itest or a unit test. Repeating what I mentioned above, since there aren't any existing unit tests for invoicesrpc.AddInvoice some setup and mocking is needed to make a unit test for this PR, just wondering if that is outside of the scope of this PR. Sorry if I'm being obtuse, I'm new here! Let me know what you think the best approach is.

Copy link
Member

@yyforyongyu yyforyongyu left a comment

Choose a reason for hiding this comment

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

Thanks for the PR! Could you do a rebase on the latest master? Kinda wanna test it out locally.

@davidgumberg
Copy link
Contributor Author

@yyforyongyu Rebased on master

Copy link
Member

@yyforyongyu yyforyongyu left a comment

Choose a reason for hiding this comment

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

tACK 🙏

@yyforyongyu yyforyongyu added this to the v0.18.1 milestone May 20, 2024
@lightninglabs-deploy
Copy link

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

Copy link
Collaborator

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

LGTM - thanks @davidgumberg 🙏

just needs a release notes entry!

@davidgumberg davidgumberg force-pushed the invoice_cltv_expiry branch from c953f2e to 70c4034 Compare June 2, 2024 15:08
@davidgumberg
Copy link
Contributor Author

@ellemouton Rebased and added a release note

Copy link
Collaborator

@guggero guggero left a comment

Choose a reason for hiding this comment

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

One more nit, otherwise good to go, thanks for the update.

"hop. If this is set to 0, the default value " +
"is used. The default value for " +
"cltv_expiry_delta is configured by the " +
"bitcoin.timelockdelta' option.",
Copy link
Collaborator

Choose a reason for hiding this comment

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

nit: missing leading single quote of config option name, same below.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Thanks for catching this! Pushed a fixup commit: e14c25a

@guggero
Copy link
Collaborator

guggero commented Jun 4, 2024

Thanks for the fix. Can you rebase to squash the fixup commit please? Then we're good to go.

Allows users of the RPC CLI to set the `min_final_cltv_expiry_delta`
described in BOLT's 11, 7, and 2 by setting the `cltv_expiry` flag when
calling either of the `addinvoice` or `addholdinvoice` RPC's from
`lncli`.
Previously the error message produced when `CltvExpiry` is less
than the minimum final cltv (18 at present) set by
`routing.MinCLTVDelta` inserted the values into the wrong spots of the
formatted string.
@davidgumberg davidgumberg force-pushed the invoice_cltv_expiry branch from e14c25a to 3c1b7ad Compare June 4, 2024 10:19
@davidgumberg
Copy link
Contributor Author

Thanks for the fix. Can you rebase to squash the fixup commit please? Then we're good to go.

Done!

@guggero guggero merged commit a832371 into lightningnetwork:master Jun 4, 2024
24 of 27 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants