[bug]: AMP sub-invoice accepts HTLCs after cancellation
Pre-Submission Checklist
- I have searched the existing issues and believe this is a new bug.
- I am not asking a question about how to use lnd, but reporting a bug (otherwise open a discussion).
LND Version
0.21.99-beta
LND Configuration
Bug Description
An AMP sub-invoice that has already been canceled can still accept a new
HTLC for the same setID while the parent invoice remains open.
This happens because updateMpp() checks the parent invoice state but does
not check the state of the specific AMP sub-invoice.
Expected Behavior
A new HTLC for an AMP setID that is already in HtlcStateCanceled should
be rejected immediately with ResultInvoiceAlreadyCanceled.
Current Behavior
The HTLC is accepted/deferred and can remain pending until the invoice eventually expires.
Reproduction
- Create an AMP invoice.
- Send a partial AMP payment so the specific
setIDbecomes canceled. - Send another HTLC for the same
setID. - The new HTLC is accepted instead of being rejected immediately.
Background
This behavior was previously noted in invoices/invoiceregistry_test.go
with the following TODO:
TODO(ziggie): Fix this bug.
The existing test currently works around the issue by allowing the HTLC to remain pending until the MPP timeout.
Proposed Fix
Check the specific AMP sub-invoice state in updateMpp() after validating
the invoice payment address.
If the setID is already HtlcStateCanceled, return
ResultInvoiceAlreadyCanceled.
Testing
Update the existing regression test to verify the new immediate failure behavior and remove the existing expiry/timeout workaround.
Backend Version
Not applicable - this issue is in the invoice registry/state machine and does not depend on the Bitcoin backend.
Backend Configuration
Not applicable - the issue occurs in the invoice handling logic and does not depend on bitcoind/btcd configuration.
OS/Distribution
macOS (Darwin). Backend-independent issue in the LND invoice registry.
Bug Details & Steps to Reproduce
An AMP sub-invoice can accept a new HTLC after that specific AMP setID
has already been canceled, as long as the parent invoice remains open.
The existing test testFailPartialAMPPayment documents this behavior and
contains a TODO to fix it.
Steps to reproduce:
- Create an AMP invoice.
- Send a partial AMP payment so the specific
setIDbecomes canceled. - Send another HTLC for the same
setIDusing the correct payment address. - Observe that the new HTLC is accepted/deferred instead of being rejected immediately.
Expected Behavior
A new HTLC for an AMP setID that is already in HtlcStateCanceled should
be rejected immediately with ResultInvoiceAlreadyCanceled.
The canceled AMP sub-invoice should not accept or persist the new HTLC.
The parent invoice should remain open so that other AMP setIDs can still
receive payments.
Debug Information
No response
Environment
No response
Source: lightningnetwork/lnd