Skip to content

Conversation

@Roasbeef
Copy link
Member

@Roasbeef Roasbeef commented Feb 3, 2026

Fixes #10541

Previously, sending a payment with amt_msat set alongside a fixed-amount
BOLT11 invoice did not work as expected. The SendPaymentSync path in
rpcserver.go silently ignored the amt_msat field and used the invoice
amount, while the SendPaymentV2 path in router_backend.go rejected the
request outright with "amount must not be specified when paying a non-zero
amount invoice". Both behaviors prevented users from intentionally overpaying
an invoice, which is permitted by the BOLT spec.

This PR introduces a shared ValidatePayReqAmt helper in the lnrpc package
that consolidates the invoice-amount-vs-caller-amount validation logic. When a
caller specifies amt_msat (or amt) alongside a fixed-amount invoice, the
payment now proceeds as long as the specified amount is at least the invoice
amount. Underpayment is rejected with a clear error. For zero-amount invoices,
the existing behavior (caller must specify an amount) is preserved.

Both extractPaymentIntent (legacy SendPayment/SendPaymentSync) and
extractIntentFromSendRequest (SendPaymentV2) now use this shared helper,
eliminating duplicated logic and ensuring consistent behavior across both RPC
paths.

The change includes unit tests for the new helper covering overpayment, exact
payment, underpayment, zero-amount invoices, and sat/msat mutual exclusivity,
as well as an integration test that verifies end-to-end overpayment of a
fixed-amount invoice.

In this commit, we introduce a new ValidatePayReqAmt helper function
in the lnrpc package that consolidates the logic for validating a
caller-specified payment amount against a BOLT11 invoice amount. The
helper handles three cases: zero-amount invoices (caller must specify
an amount), fixed-amount invoices with no caller override (use invoice
amount), and fixed-amount invoices with a caller override (allow
overpayment, reject underpayment).

This helper will be used in the next commit to fix a bug where
amt_msat was silently ignored when paying fixed-amount invoices.
Previously, the SendPaymentSync path in rpcserver.go silently ignored
the amt_msat field when paying a BOLT11 invoice that already contained
a fixed amount, and the SendPaymentV2 path in router_backend.go
rejected the request outright with "amount must not be specified when
paying a non-zero amount invoice". Both behaviors prevented users from
intentionally overpaying an invoice, which is permitted by the BOLT
spec.

In this commit, we replace the duplicated amount validation logic in
both extractPaymentIntent (rpcserver.go) and
extractIntentFromSendRequest (router_backend.go) with calls to the new
ValidatePayReqAmt helper. When a caller specifies amt_msat alongside a
fixed-amount invoice, the payment now proceeds as long as the
specified amount is at least the invoice amount. Underpayment is still
rejected with a clear error message.

Fixes #10541
In this commit, we add an integration test that verifies a payer can
overpay a fixed-amount BOLT11 invoice by specifying a larger amt_msat
in the SendPaymentV2 request. The test creates a 1000 sat invoice,
pays it with 1100 sat (1,100,000 msat), and asserts that both the
sender's payment record and the receiver's invoice reflect the
overpaid amount.
@gemini-code-assist
Copy link

Summary of Changes

Hello @Roasbeef, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request addresses a long-standing issue where lnd's RPC payment methods inconsistently handled user-specified payment amounts for BOLT11 invoices. By introducing a centralized validation helper, the system now correctly permits overpayment of fixed-amount invoices as per the BOLT specification, while maintaining strict checks for zero-amount invoices and preventing underpayment. This change streamlines the payment processing logic and provides a more flexible and compliant user experience.

Highlights

  • Overpayment of Fixed-Amount Invoices: The pull request enables intentional overpayment of fixed-amount BOLT11 invoices, aligning the system with the BOLT specification. Previously, this was either ignored or explicitly rejected by different RPC paths.
  • Unified Payment Amount Validation: A new shared helper function, ValidatePayReqAmt, has been introduced in the lnrpc package. This function consolidates the logic for validating payment amounts against invoice requirements, ensuring consistent behavior across all RPC payment paths.
  • Consistent RPC Behavior: Both the legacy SendPayment/SendPaymentSync (via extractPaymentIntent) and SendPaymentV2 (via extractIntentFromSendRequest) RPC paths now utilize the new ValidatePayReqAmt helper, eliminating duplicated logic and ensuring uniform handling of payment amounts.
  • Enhanced Test Coverage: New unit tests for ValidatePayReqAmt cover various scenarios including zero-amount invoices, fixed-amount invoices, overpayment, underpayment, and mutual exclusivity of amount fields. An integration test has also been added to verify end-to-end overpayment functionality.

🧠 New Feature in Public Preview: You can now enable Memory to help Gemini Code Assist learn from your team's feedback. This makes future code reviews more consistent and personalized to your project's style. Click here to enable Memory in your admin console.

Changelog
  • itest/list_on_test.go
    • Added testSendPaymentOverpay to the list of integration test cases.
  • itest/lnd_send_overpayment_test.go
    • New file added containing the testSendPaymentOverpay integration test. This test verifies that a payer can successfully overpay a fixed-amount BOLT11 invoice and that the recipient receives the overpaid amount.
  • lnrpc/marshall_utils.go
    • Added ValidatePayReqAmt function. This helper validates a payment amount against an invoice's specified amount, allowing overpayment for fixed-amount invoices, rejecting underpayment, and requiring an amount for zero-amount invoices.
  • lnrpc/marshall_utils_test.go
    • New file added containing comprehensive unit tests for the ValidatePayReqAmt helper function, covering various scenarios like zero-amount invoices, fixed-amount invoices (exact, overpayment, underpayment), and mutual exclusivity of amtSat and amtMsat.
  • lnrpc/routerrpc/router_backend.go
    • Modified extractIntentFromSendRequest to use the new lnrpc.ValidatePayReqAmt function for validating and resolving payment amounts, replacing previous custom logic for handling invoice amounts.
  • rpcserver.go
    • Modified extractPaymentIntent to use the new lnrpc.ValidatePayReqAmt function for validating and resolving payment amounts, replacing previous custom logic for handling invoice amounts.
Activity
  • The pull request fixes issue https://github.com/lightningnetwork/lnd/issues/10541.
  • The author Roasbeef implemented a new shared helper function ValidatePayReqAmt to centralize payment amount validation.
  • Existing RPC payment paths (extractPaymentIntent and extractIntentFromSendRequest) were updated to use this new helper.
  • New unit tests for the ValidatePayReqAmt function and an integration test for end-to-end overpayment were added.
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

Copy link

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

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

Code Review

This pull request introduces a significant improvement by allowing intentional overpayment of fixed-amount invoices, aligning the behavior of SendPaymentSync and SendPaymentV2 with the BOLT specification. The introduction of the shared ValidatePayReqAmt helper in the lnrpc package is a great refactoring that centralizes validation logic, removes duplication, and ensures consistent behavior across different RPC paths. The changes are well-tested with both unit tests for the new helper and an end-to-end integration test, which gives high confidence in the correctness of the implementation. The code is clean, readable, and adheres to the project's style guide. Overall, this is an excellent contribution that improves correctness and maintainability.

@lightninglabs-deploy
Copy link
Collaborator

🔴 PR Severity: CRITICAL

rpcserver+routerrpc | 6 files | 256 lines changed

🔴 Critical (1 file)
  • rpcserver.go - Core server coordination for invoice overpayment handling
🟠 High (2 files)
  • lnrpc/marshall_utils.go - RPC utility functions for invoice marshalling
  • lnrpc/routerrpc/router_backend.go - Router RPC backend implementation
🟢 Low (3 files)
  • itest/list_on_test.go - Integration test configuration
  • itest/lnd_send_overpayment_test.go - Overpayment integration tests
  • lnrpc/marshall_utils_test.go - Unit tests for marshall utilities

Analysis

This PR is classified as CRITICAL because it modifies rpcserver.go, which is core server coordination code. The change allows overpayment of fixed-amount invoices, which affects fundamental payment processing logic.

Key considerations:

  • The PR touches the core RPC server payment handling logic
  • Changes affect how fixed-amount invoices are validated and settled
  • Router backend modifications alter payment routing behavior
  • While the change is relatively focused (3 non-test files, ~60 non-test lines), the rpcserver.go modification alone warrants critical severity due to its central role in coordinating server operations

Review focus areas:

  • Payment amount validation logic
  • Invoice settlement conditions
  • Backward compatibility with existing invoice behavior
  • Potential edge cases with overpayment acceptance

To override, add a severity-override-{critical,high,medium,low} label.

@NicolasDorier
Copy link
Contributor

Tested. It works. 👍

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.

[bug]: amt_msat ignored when sending a payment

3 participants