Browse Source

routing: don't return an error from failPayment within handleSendError

In this commit, we fix a regression introduced by a recent bug fix in
this area. Before this change, we'd inspect the error returned by
`processSendError`, and then fail the payment from the PoV of mission
control using the returned error.

A recent refactoring removed `processSendError` and combined the logic
with `tryApplyChannelUpdate` in order to introduce a new
`handleSendError` method that consolidates the logic within the
`shardHandler`. Along the way, the behavior of the prior check was
replicated in the form of a new internal `failPayment` closure. However,
the new function closure ends up returning a `channeldb.FailureReason`
instance, which is actually an `error`.

In the wild, when `SendToRoute` fails due to an error at the
destination, then this new logic caused the `handleSendErorr` method to
fail with an error, returning an unstructured error back to the caller,
instead of the usual payment failure details.

We fix this by no longer checking the `handleSendErorr` for an error as
normal. The `handleSendErorr` function as is will always return an error
of type `*channeldb.FailureReason`, therefore we don't need to treat it
as a normal error. Instead, we check for the type of error returned, and
update the control tower state accordingly.

With this commit, the test added in the prior commit now passes.

Fixes #5477.
master
Olaoluwa Osuntokun 3 years ago
parent
commit
525ef594c7
No known key found for this signature in database
GPG Key ID: 3BBD59E99B280306
  1. 7
      routing/payment_lifecycle.go
  2. 23
      routing/router.go

7
routing/payment_lifecycle.go

@ -782,10 +782,13 @@ func (p *shardHandler) handleSendError(attempt *channeldb.HTLCAttemptInfo,
if err := p.router.cfg.Control.Fail(
p.identifier, *reason); err != nil {
return err
log.Errorf("unable to report failure to control "+
"tower: %v", err)
return &internalErrorReason
}
return *reason
return reason
}
// reportFail is a helper closure that reports the failure to the

23
routing/router.go

@ -2,6 +2,7 @@ package routing
import (
"bytes"
goErrors "errors"
"fmt"
"runtime"
"strings"
@ -2163,13 +2164,23 @@ func (r *ChannelRouter) SendToRoute(htlcHash lntypes.Hash, rt *route.Route) (
// mark the payment failed with the control tower immediately. Process
// the error to check if it maps into a terminal error code, if not use
// a generic NO_ROUTE error.
if err := sh.handleSendError(attempt, shardError); err != nil {
return nil, err
}
var failureReason *channeldb.FailureReason
err = sh.handleSendError(attempt, shardError)
err = r.cfg.Control.Fail(
paymentIdentifier, channeldb.FailureReasonNoRoute,
)
switch {
// If we weren't able to extract a proper failure reason (which can
// happen if the second chance logic is triggered), then we'll use the
// normal no route error.
case err == nil:
err = r.cfg.Control.Fail(
paymentIdentifier, channeldb.FailureReasonNoRoute,
)
// If this is a failure reason, then we'll apply the failure directly
// to the control tower, and return the normal response to the caller.
case goErrors.As(err, &failureReason):
err = r.cfg.Control.Fail(paymentIdentifier, *failureReason)
}
if err != nil {
return nil, err
}

Loading…
Cancel
Save