From 6dbbf1b63d57802ea8bf4d1d5d0f3bc78335fb9a Mon Sep 17 00:00:00 2001 From: kiwiidb Date: Fri, 13 Jan 2023 12:34:08 +0100 Subject: [PATCH] atomic failed payment handling --- lib/service/invoices.go | 21 +++++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/lib/service/invoices.go b/lib/service/invoices.go index 7ebfb40..a25f96f 100644 --- a/lib/service/invoices.go +++ b/lib/service/invoices.go @@ -3,6 +3,7 @@ package service import ( "context" "crypto/sha256" + "database/sql" "encoding/hex" "errors" "fmt" @@ -242,6 +243,14 @@ func (svc *LndhubService) PayInvoice(ctx context.Context, invoice *models.Invoic } func (svc *LndhubService) HandleFailedPayment(ctx context.Context, invoice *models.Invoice, entryToRevert models.TransactionEntry, failedPaymentError error) error { + // Process the tx insertion and invoice update in a DB transaction + // analogous with the incoming invoice update + tx, err := svc.DB.BeginTx(ctx, &sql.TxOptions{}) + if err != nil { + sentry.CaptureException(err) + svc.Logger.Errorf("Could not open tx entry for updating failed payment:r_hash:%s %v", invoice.RHash, err) + return err + } // add transaction entry with reverted credit/debit account id entry := models.TransactionEntry{ UserID: invoice.UserID, @@ -250,8 +259,9 @@ func (svc *LndhubService) HandleFailedPayment(ctx context.Context, invoice *mode DebitAccountID: entryToRevert.CreditAccountID, Amount: invoice.Amount, } - _, err := svc.DB.NewInsert().Model(&entry).Exec(ctx) + _, err = tx.NewInsert().Model(&entry).Exec(ctx) if err != nil { + tx.Rollback() sentry.CaptureException(err) svc.Logger.Errorf("Could not insert transaction entry user_id:%v invoice_id:%v error %s", invoice.UserID, invoice.ID, err.Error()) return err @@ -262,11 +272,18 @@ func (svc *LndhubService) HandleFailedPayment(ctx context.Context, invoice *mode invoice.ErrorMessage = failedPaymentError.Error() } - _, err = svc.DB.NewUpdate().Model(invoice).WherePK().Exec(ctx) + _, err = tx.NewUpdate().Model(invoice).WherePK().Exec(ctx) if err != nil { + tx.Rollback() sentry.CaptureException(err) svc.Logger.Errorf("Could not update failed payment invoice user_id:%v invoice_id:%v error %s", invoice.UserID, invoice.ID, err.Error()) } + err = tx.Commit() + if err != nil { + sentry.CaptureException(err) + svc.Logger.Errorf("Failed to commit DB transaction user_id:%v invoice_id:%v %v", invoice.UserID, invoice.ID, err) + return err + } return err }