From 9f4edf39dda5277a2fc2b360810fe9e63d677632 Mon Sep 17 00:00:00 2001 From: Roland Bewick Date: Tue, 20 Aug 2024 12:57:23 +0700 Subject: [PATCH] fix: check for duplicate payment --- transactions/payments_test.go | 23 +++++++++++++++++++++++ transactions/transactions_service.go | 10 ++++++++++ 2 files changed, 33 insertions(+) diff --git a/transactions/payments_test.go b/transactions/payments_test.go index 25f2b71e..563b803a 100644 --- a/transactions/payments_test.go +++ b/transactions/payments_test.go @@ -6,6 +6,7 @@ import ( "testing" "github.com/getAlby/hub/constants" + "github.com/getAlby/hub/db" "github.com/getAlby/hub/lnclient" "github.com/getAlby/hub/tests" "github.com/stretchr/testify/assert" @@ -28,6 +29,28 @@ func TestSendPaymentSync_NoApp(t *testing.T) { assert.Equal(t, "123preimage", *transaction.Preimage) } +func TestSendPaymentSync_Duplicate(t *testing.T) { + ctx := context.TODO() + + defer tests.RemoveTestService() + svc, err := tests.CreateTestService() + assert.NoError(t, err) + + svc.DB.Create(&db.Transaction{ + State: constants.TRANSACTION_STATE_SETTLED, + Type: constants.TRANSACTION_TYPE_OUTGOING, + PaymentHash: tests.MockLNClientTransaction.PaymentHash, + AmountMsat: 123000, + }) + + transactionsService := NewTransactionsService(svc.DB, svc.EventPublisher) + transaction, err := transactionsService.SendPaymentSync(ctx, tests.MockLNClientTransaction.Invoice, svc.LNClient, nil, nil) + + assert.Error(t, err) + assert.Equal(t, "this invoice has already been paid", err.Error()) + assert.Nil(t, transaction) +} + func TestSendPaymentSync_FailedRemovesFeeReserve(t *testing.T) { ctx := context.TODO() diff --git a/transactions/transactions_service.go b/transactions/transactions_service.go index 4adf05cc..0d193ba4 100644 --- a/transactions/transactions_service.go +++ b/transactions/transactions_service.go @@ -174,6 +174,16 @@ func (svc *transactionsService) SendPaymentSync(ctx context.Context, payReq stri var dbTransaction db.Transaction err = svc.db.Transaction(func(tx *gorm.DB) error { + var existingSettledTransaction db.Transaction + if tx.Limit(1).Find(&existingSettledTransaction, &db.Transaction{ + Type: constants.TRANSACTION_TYPE_OUTGOING, + PaymentHash: paymentRequest.PaymentHash, + State: constants.TRANSACTION_STATE_SETTLED, + }).RowsAffected > 0 { + logger.Logger.WithField("payment_hash", dbTransaction.PaymentHash).Info("this invoice has already been paid") + return errors.New("this invoice has already been paid") + } + err := svc.validateCanPay(tx, appId, uint64(paymentRequest.MSatoshi)) if err != nil { return err