catch errors in multiple places that might be destroying the async flow and causing lnbits to die silently.

This commit is contained in:
fiatjaf 2021-04-10 17:37:48 -03:00
parent b48a44bcd0
commit fdf4f6c1ae
9 changed files with 82 additions and 55 deletions

View file

@ -33,6 +33,10 @@ class PaymentFailure(Exception):
pass
class InvoiceFailure(Exception):
pass
async def create_invoice(
*,
wallet_id: str,
@ -50,7 +54,7 @@ async def create_invoice(
amount=amount, memo=invoice_memo, description_hash=description_hash
)
if not ok:
raise Exception(error_message or "Unexpected backend error.")
raise InvoiceFailure(error_message or "Unexpected backend error.")
invoice = bolt11.decode(payment_request)

View file

@ -12,7 +12,13 @@ from lnbits import bolt11
from lnbits.decorators import api_check_wallet_key, api_validate_post_request
from .. import core_app, db
from ..services import PaymentFailure, create_invoice, pay_invoice, perform_lnurlauth
from ..services import (
PaymentFailure,
InvoiceFailure,
create_invoice,
pay_invoice,
perform_lnurlauth,
)
from ..tasks import sse_listeners
@ -67,6 +73,7 @@ async def api_payments_create_invoice():
memo = g.data["memo"]
async with db.connect() as conn:
try:
payment_hash, payment_request = await create_invoice(
wallet_id=g.wallet.id,
amount=g.data["amount"],
@ -76,6 +83,10 @@ async def api_payments_create_invoice():
webhook=g.data.get("webhook"),
conn=conn,
)
except InvoiceFailure as e:
return jsonify({"message": str(e)}), 520
except Exception as exc:
raise exc
invoice = bolt11.decode(payment_request)

View file

@ -37,12 +37,15 @@ async def api_amilkit(amilk_id):
except LnurlException:
abort(HTTPStatus.INTERNAL_SERVER_ERROR, "Could not process withdraw LNURL.")
try:
payment_hash, payment_request = await create_invoice(
wallet_id=milk.wallet,
amount=withdraw_res.max_sats,
memo=memo,
extra={"tag": "amilk"},
)
except Exception as e:
return jsonify({"message": str(e)}), HTTPStatus.INTERNAL_SERVER_ERROR
r = httpx.get(
withdraw_res.callback.base,

View file

@ -86,10 +86,13 @@ class BleskomatLnurl(NamedTuple):
raise LnurlValidationError("Maximum number of uses already reached")
tag = self.tag
if tag == "withdrawRequest":
try:
payment_hash = await pay_invoice(
wallet_id=self.wallet,
payment_request=query["pr"],
)
except Exception as exc:
raise LnurlValidationError(f"Failed to pay invoice: {exc.message}")
if not payment_hash:
raise LnurlValidationError("Failed to pay invoice")

View file

@ -116,12 +116,16 @@ async def api_ticket_make_ticket(form_id):
nwords = len(re.split(r"\s+", g.data["ltext"]))
sats = g.data["sats"]
try:
payment_hash, payment_request = await create_invoice(
wallet_id=form.wallet,
amount=sats,
memo=f"ticket with {nwords} words on {form_id}",
extra={"tag": "lnticket"},
)
except Exception as e:
return jsonify({"message": str(e)}), HTTPStatus.INTERNAL_SERVER_ERROR
ticket = await create_ticket(
payment_hash=payment_hash, wallet=form.wallet, **g.data

View file

@ -64,6 +64,8 @@ async def lnurl_callback(item_id):
)
shop = await get_shop(item.shop)
try:
payment_hash, payment_request = await create_invoice(
wallet_id=shop.wallet,
amount=int(amount_received / 1000),
@ -73,6 +75,8 @@ async def lnurl_callback(item_id):
).digest(),
extra={"tag": "offlineshop", "item": item.id},
)
except Exception as exc:
return jsonify(LnurlErrorResponse(reason=exc.message).dict())
resp = LnurlPayActionResponse(
pr=payment_request,

View file

@ -1,15 +1,10 @@
import re
from quart import g, jsonify, request
from http import HTTPStatus
from lnbits.core import crud
import json
import httpx
from lnbits.core.crud import get_user, get_wallet
from lnbits.core.crud import get_user
from lnbits.core.services import create_invoice, check_invoice_status
from lnbits.decorators import api_check_wallet_key, api_validate_post_request
from .util import isValidDomain, isvalidIPAddress
from . import subdomains_ext
from .crud import (
create_subdomain,
@ -169,12 +164,16 @@ async def api_subdomain_make_subdomain(domain_id):
## ALL OK - create an invoice and return it to the user
sats = g.data["sats"]
try:
payment_hash, payment_request = await create_invoice(
wallet_id=domain.wallet,
amount=sats,
memo=f"subdomain {g.data['subdomain']}.{domain.domain} for {sats} sats for {g.data['duration']} days",
extra={"tag": "lnsubdomain"},
)
except Exception as e:
return jsonify({"message": str(e)}), HTTPStatus.INTERNAL_SERVER_ERROR
subdomain = await create_subdomain(
payment_hash=payment_hash, wallet=domain.wallet, **g.data

View file

@ -119,11 +119,10 @@ async def api_lnurl_callback(unique_hash):
await update_withdraw_link(link.id, **changes)
except ValueError as e:
return jsonify({"status": "ERROR", "reason": str(e)}), HTTPStatus.OK
return jsonify({"status": "ERROR", "reason": str(e)})
except PermissionError:
return (
jsonify({"status": "ERROR", "reason": "Withdraw link is empty."}),
HTTPStatus.OK,
)
return jsonify({"status": "ERROR", "reason": "Withdraw link is empty."})
except Exception as e:
return jsonify({"status": "ERROR", "reason": str(e)})
return jsonify({"status": "OK"}), HTTPStatus.OK

View file

@ -49,7 +49,7 @@ class SparkWallet(Wallet):
timeout=40,
)
except (OSError, httpx.ConnectError, httpx.RequestError) as exc:
raise SparkError("error connecting to spark: " + str(exc))
raise UnknownError("error connecting to spark: " + str(exc))
try:
data = r.json()
@ -123,7 +123,7 @@ class SparkWallet(Wallet):
payment_hash = pay["payment_hash"]
if len(pays) > 1:
raise Exception(
raise SparkError(
f"listpays({payment_hash}) returned an unexpected response: {listpays}"
)