From 4eb8ca5ac636d17282827c74e8e242d202aef3db Mon Sep 17 00:00:00 2001 From: Vlad Stan Date: Tue, 13 May 2025 10:03:54 +0300 Subject: [PATCH] fix: guard internal payments --- lnbits/core/services/payments.py | 18 +++++++++++++++--- tests/unit/test_pay_invoice.py | 3 ++- 2 files changed, 17 insertions(+), 4 deletions(-) diff --git a/lnbits/core/services/payments.py b/lnbits/core/services/payments.py index d1ff7dec4..34bbbe6a6 100644 --- a/lnbits/core/services/payments.py +++ b/lnbits/core/services/payments.py @@ -46,6 +46,8 @@ from .notifications import send_payment_notification outgoing_payments_processing: list[str] = [] +internal_payment_lock = asyncio.Lock() + async def pay_invoice( *, @@ -443,15 +445,20 @@ async def get_payments_daily_stats( return data -async def _pay_invoice(wallet, create_payment_model, conn): - payment = await _pay_internal_invoice(wallet, create_payment_model, conn) +async def _pay_invoice( + wallet: Wallet, + create_payment_model: CreatePayment, + conn: Optional[Connection] = None, +): + async with internal_payment_lock: + payment = await _pay_internal_invoice(wallet.id, create_payment_model, conn) if not payment: payment = await _pay_external_invoice(wallet, create_payment_model, conn) return payment async def _pay_internal_invoice( - wallet: Wallet, + wallet_id: str, create_payment_model: CreatePayment, conn: Optional[Connection] = None, ) -> Optional[Payment]: @@ -485,6 +492,11 @@ async def _pay_internal_invoice( fee_reserve_total_msat = fee_reserve_total(amount_msat, internal=True) create_payment_model.fee = abs(fee_reserve_total_msat) + # get the wallet again to make sure we have the latest balance + wallet = await get_wallet(wallet_id, conn=conn) + if not wallet: + raise PaymentError(f"Could not fetch wallet '{wallet_id}'.", status="failed") + print("### wallet.balance", wallet.balance_msat, wallet.balance) if wallet.balance_msat < abs(amount_msat) + fee_reserve_total_msat: raise PaymentError("Insufficient balance.", status="failed") diff --git a/tests/unit/test_pay_invoice.py b/tests/unit/test_pay_invoice.py index b8e9879a5..8d3e78fdf 100644 --- a/tests/unit/test_pay_invoice.py +++ b/tests/unit/test_pay_invoice.py @@ -158,7 +158,7 @@ async def test_pay_twice_fast_b(): payment_request=payment_b.bolt11, ) - payments = await asyncio.gather(pay_first(), pay_second()) + await asyncio.gather(pay_first(), pay_second()) wallet_one_after = await get_wallet(wallet_one.id) assert wallet_one_after @@ -167,6 +167,7 @@ async def test_pay_twice_fast_b(): assert wallet_two_after print("### wallet_two", wallet_two_after.balance) + @pytest.mark.anyio async def test_fake_wallet_pay_external( to_wallet: Wallet, external_funding_source: FakeWallet