Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions docs/release-notes/release-notes-0.19.3.md
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,10 @@
situations where the sending amount would violate the channel policy
restriction (min,max HTLC).

- [Fixed](https://github.com/lightningnetwork/lnd/pull/10141) a case where we
would not resolve all outstanding payment attempts after the overall payment
lifecycle was canceled due to a timeout.

# New Features

## Functional Enhancements
Expand Down
29 changes: 17 additions & 12 deletions routing/payment_lifecycle.go
Original file line number Diff line number Diff line change
Expand Up @@ -226,6 +226,19 @@ func (p *paymentLifecycle) resumePayment(ctx context.Context) ([32]byte,
// critical error during path finding.
lifecycle:
for {
// Before we attempt any new shard, we'll check to see if we've
// gone past the payment attempt timeout or if the context was
// canceled. If the context is done, the payment is marked as
// failed and we reload the latest payment state to reflect
// this.
//
// NOTE: This can be called several times if there are more
// attempts to be resolved after the timeout or context is
// cancelled.
if err := p.checkContext(ctx); err != nil {
return exitWithErr(err)
}

// We update the payment state on every iteration.
currentPayment, ps, err := p.reloadPayment()
if err != nil {
Expand All @@ -241,19 +254,11 @@ lifecycle:

// We now proceed our lifecycle with the following tasks in
// order,
// 1. check context.
// 2. request route.
// 3. create HTLC attempt.
// 4. send HTLC attempt.
// 5. collect HTLC attempt result.
// 1. request route.
// 2. create HTLC attempt.
// 3. send HTLC attempt.
// 4. collect HTLC attempt result.
//
// Before we attempt any new shard, we'll check to see if we've
// gone past the payment attempt timeout, or if the context was
// cancelled, or the router is exiting. In any of these cases,
// we'll stop this payment attempt short.
if err := p.checkContext(ctx); err != nil {
return exitWithErr(err)
}

// Now decide the next step of the current lifecycle.
step, err := p.decideNextStep(payment)
Expand Down
17 changes: 4 additions & 13 deletions routing/payment_lifecycle_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -868,25 +868,16 @@ func TestResumePaymentFailOnTimeoutErr(t *testing.T) {
// Create a test paymentLifecycle with the initial two calls mocked.
p, m := setupTestPaymentLifecycle(t)

paymentAmt := lnwire.MilliSatoshi(10000)

// We now enter the payment lifecycle loop.
//
// 1. calls `FetchPayment` and return the payment.
m.control.On("FetchPayment", p.identifier).Return(m.payment, nil).Once()

// 2. calls `GetState` and return the state.
ps := &channeldb.MPPaymentState{
RemainingAmt: paymentAmt,
}
m.payment.On("GetState").Return(ps).Once()
// We now enter the payment lifecycle loop, we will check the router
// quit channel in the beginning and quit immediately without reloading
// the payment.

// NOTE: GetStatus is only used to populate the logs which is
// not critical so we loosen the checks on how many times it's
// been called.
m.payment.On("GetStatus").Return(channeldb.StatusInFlight)

// 3. quit the router to return an error.
// Quit the router to return an error.
close(p.router.quit)

// Send the payment and assert it failed when router is shutting down.
Expand Down
Loading