mirror of
https://github.com/getAlby/lndhub.go.git
synced 2025-12-22 07:04:56 +01:00
Add DB constraints to check for user balances
This commit is contained in:
@@ -79,7 +79,8 @@ func (controller *PayInvoiceController) PayInvoice(c echo.Context) error {
|
|||||||
|
|
||||||
entry, err := controller.svc.PayInvoice(invoice)
|
entry, err := controller.svc.PayInvoice(invoice)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.Logger().Errorf("Failed: %v", err)
|
c.Logger().Errorf("Payment failed: %v", err)
|
||||||
|
// TODO: sentry notification
|
||||||
return c.JSON(http.StatusBadRequest, echo.Map{
|
return c.JSON(http.StatusBadRequest, echo.Map{
|
||||||
"error": true,
|
"error": true,
|
||||||
"code": 10,
|
"code": 10,
|
||||||
|
|||||||
59
db/migrations/20220120000700_add_constraints.up.go
Normal file
59
db/migrations/20220120000700_add_constraints.up.go
Normal file
@@ -0,0 +1,59 @@
|
|||||||
|
package migrations
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/uptrace/bun"
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
Migrations.MustRegister(func(ctx context.Context, db *bun.DB) error {
|
||||||
|
|
||||||
|
if db.Dialect().Name().String() != "pg" {
|
||||||
|
fmt.Printf("\033[1;31m%s\033[0m", "You are not using PostgreSQL. DB level checks can not be enabled!\n")
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
sql := `
|
||||||
|
-- make sure transfers happen from one account to another one
|
||||||
|
alter table transaction_entries
|
||||||
|
ADD CONSTRAINT check_not_same_account
|
||||||
|
CHECK (debit_account_id != credit_account_id);
|
||||||
|
|
||||||
|
-- make sure that account balances >= 0 (except for incoming account)
|
||||||
|
CREATE OR REPLACE FUNCTION check_balance()
|
||||||
|
RETURNS TRIGGER AS $$
|
||||||
|
DECLARE
|
||||||
|
sum BIGINT;
|
||||||
|
debit_account_type VARCHAR;
|
||||||
|
BEGIN
|
||||||
|
SELECT INTO debit_account_type type
|
||||||
|
FROM accounts
|
||||||
|
WHERE id = NEW.debit_account_id;
|
||||||
|
|
||||||
|
SELECT INTO sum SUM(amount)
|
||||||
|
FROM account_ledgers
|
||||||
|
WHERE account_ledgers.account_id = NEW.debit_account_id;
|
||||||
|
|
||||||
|
-- the incoming account can have a negative balance
|
||||||
|
-- all other accounts must have a positive balance
|
||||||
|
IF sum < 0 AND debit_account_type != 'incoming'
|
||||||
|
THEN
|
||||||
|
RAISE EXCEPTION 'invalid balance [user_id:%] [debit_account_id:%] balance [%]',
|
||||||
|
NEW.user_id,
|
||||||
|
NEW.debit_account_id,
|
||||||
|
sum;
|
||||||
|
END IF;
|
||||||
|
RETURN NEW;
|
||||||
|
END;
|
||||||
|
$$ LANGUAGE plpgsql;
|
||||||
|
CREATE TRIGGER check_balance
|
||||||
|
AFTER INSERT OR UPDATE ON transaction_entries
|
||||||
|
FOR EACH ROW EXECUTE PROCEDURE check_balance();
|
||||||
|
`
|
||||||
|
if _, err := db.Exec(sql); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}, nil)
|
||||||
|
}
|
||||||
@@ -54,6 +54,9 @@ func (svc *LndhubService) PayInvoice(invoice *models.Invoice) (*models.Transacti
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return &entry, err
|
return &entry, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// The DB constraints make sure the user actually has enough balance for the transaction
|
||||||
|
// If the user does not have enough balance this call fails
|
||||||
_, err = tx.NewInsert().Model(&entry).Exec(context.TODO())
|
_, err = tx.NewInsert().Model(&entry).Exec(context.TODO())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
tx.Rollback()
|
tx.Rollback()
|
||||||
|
|||||||
Reference in New Issue
Block a user