mirror of
https://github.com/lightninglabs/loop.git
synced 2026-08-13 12:33:03 +02:00
loopin: classify already-settled invoice RPC errors
lnd returns ErrInvoiceAlreadySettled from its RPC handler as an uncoded gRPC error. On the client it is reconstructed as an Unknown status, so comparing it directly with the Go sentinel never matches. This made the abandon path log a warning for an expected condition. The older timeout path had the same comparison and could return the RPC error instead of finishing normal timeout processing. Add a shared classifier that accepts the local sentinel and the exact gRPC status representation, and use it in both cancellation paths. Add coverage for the classifier and timeout handling.
This commit is contained in:
parent
89f2dcff8b
commit
8716a51722
2 changed files with 161 additions and 2 deletions
25
loopin.go
25
loopin.go
|
|
@ -27,6 +27,8 @@ import (
|
|||
"github.com/lightningnetwork/lnd/lnwallet/chainfee"
|
||||
"github.com/lightningnetwork/lnd/lnwire"
|
||||
"github.com/lightningnetwork/lnd/routing/route"
|
||||
"google.golang.org/grpc/codes"
|
||||
"google.golang.org/grpc/status"
|
||||
)
|
||||
|
||||
var (
|
||||
|
|
@ -58,6 +60,25 @@ var (
|
|||
ErrSwapFinalized = errors.New("swap is in a final state")
|
||||
)
|
||||
|
||||
// isInvoiceAlreadySettledError reports whether err indicates that an invoice
|
||||
// cancellation failed because the invoice was already settled. If lnd returns
|
||||
// the sentinel from an RPC handler, gRPC transports it as an Unknown status
|
||||
// with the sentinel's error text.
|
||||
func isInvoiceAlreadySettledError(err error) bool {
|
||||
if err == nil {
|
||||
return false
|
||||
}
|
||||
|
||||
if errors.Is(err, invpkg.ErrInvoiceAlreadySettled) {
|
||||
return true
|
||||
}
|
||||
|
||||
rpcStatus, ok := status.FromError(err)
|
||||
return ok &&
|
||||
rpcStatus.Code() == codes.Unknown &&
|
||||
rpcStatus.Message() == invpkg.ErrInvoiceAlreadySettled.Error()
|
||||
}
|
||||
|
||||
// loopInSwap contains all the in-memory state related to a pending loop in
|
||||
// swap.
|
||||
type loopInSwap struct {
|
||||
|
|
@ -1087,7 +1108,7 @@ func (s *loopInSwap) processHtlcSpend(ctx context.Context,
|
|||
// already settled. This means that the server didn't succeed in
|
||||
// sweeping the htlc after paying the invoice.
|
||||
err := s.lnd.Invoices.CancelInvoice(ctx, s.hash)
|
||||
if err != nil && err != invpkg.ErrInvoiceAlreadySettled {
|
||||
if err != nil && !isInvoiceAlreadySettledError(err) {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
|
@ -1179,7 +1200,7 @@ func (s *loopInSwap) setStateAbandoned(ctx context.Context) error {
|
|||
// behaviour of the timeout path. Any other unexpected error is logged
|
||||
// but does not prevent the abandon from completing.
|
||||
err = s.lnd.Invoices.CancelInvoice(ctx, s.hash)
|
||||
if err != nil && err != invpkg.ErrInvoiceAlreadySettled {
|
||||
if err != nil && !isInvoiceAlreadySettledError(err) {
|
||||
s.log.Warnf("Failed to cancel invoice for abandoned swap: %v",
|
||||
err)
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue