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 pass
class InvoiceFailure(Exception):
pass
async def create_invoice( async def create_invoice(
*, *,
wallet_id: str, wallet_id: str,
@ -50,7 +54,7 @@ async def create_invoice(
amount=amount, memo=invoice_memo, description_hash=description_hash amount=amount, memo=invoice_memo, description_hash=description_hash
) )
if not ok: if not ok:
raise Exception(error_message or "Unexpected backend error.") raise InvoiceFailure(error_message or "Unexpected backend error.")
invoice = bolt11.decode(payment_request) 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 lnbits.decorators import api_check_wallet_key, api_validate_post_request
from .. import core_app, db 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 from ..tasks import sse_listeners
@ -67,15 +73,20 @@ async def api_payments_create_invoice():
memo = g.data["memo"] memo = g.data["memo"]
async with db.connect() as conn: async with db.connect() as conn:
payment_hash, payment_request = await create_invoice( try:
wallet_id=g.wallet.id, payment_hash, payment_request = await create_invoice(
amount=g.data["amount"], wallet_id=g.wallet.id,
memo=memo, amount=g.data["amount"],
description_hash=description_hash, memo=memo,
extra=g.data.get("extra"), description_hash=description_hash,
webhook=g.data.get("webhook"), extra=g.data.get("extra"),
conn=conn, 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) invoice = bolt11.decode(payment_request)

View file

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

View file

@ -86,10 +86,13 @@ class BleskomatLnurl(NamedTuple):
raise LnurlValidationError("Maximum number of uses already reached") raise LnurlValidationError("Maximum number of uses already reached")
tag = self.tag tag = self.tag
if tag == "withdrawRequest": if tag == "withdrawRequest":
payment_hash = await pay_invoice( try:
wallet_id=self.wallet, payment_hash = await pay_invoice(
payment_request=query["pr"], 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: if not payment_hash:
raise LnurlValidationError("Failed to pay invoice") 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"])) nwords = len(re.split(r"\s+", g.data["ltext"]))
sats = g.data["sats"] sats = g.data["sats"]
payment_hash, payment_request = await create_invoice(
wallet_id=form.wallet, try:
amount=sats, payment_hash, payment_request = await create_invoice(
memo=f"ticket with {nwords} words on {form_id}", wallet_id=form.wallet,
extra={"tag": "lnticket"}, 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( ticket = await create_ticket(
payment_hash=payment_hash, wallet=form.wallet, **g.data payment_hash=payment_hash, wallet=form.wallet, **g.data

View file

@ -64,15 +64,19 @@ async def lnurl_callback(item_id):
) )
shop = await get_shop(item.shop) shop = await get_shop(item.shop)
payment_hash, payment_request = await create_invoice(
wallet_id=shop.wallet, try:
amount=int(amount_received / 1000), payment_hash, payment_request = await create_invoice(
memo=item.name, wallet_id=shop.wallet,
description_hash=hashlib.sha256( amount=int(amount_received / 1000),
(await item.lnurlpay_metadata()).encode("utf-8") memo=item.name,
).digest(), description_hash=hashlib.sha256(
extra={"tag": "offlineshop", "item": item.id}, (await item.lnurlpay_metadata()).encode("utf-8")
) ).digest(),
extra={"tag": "offlineshop", "item": item.id},
)
except Exception as exc:
return jsonify(LnurlErrorResponse(reason=exc.message).dict())
resp = LnurlPayActionResponse( resp = LnurlPayActionResponse(
pr=payment_request, pr=payment_request,

View file

@ -1,15 +1,10 @@
import re
from quart import g, jsonify, request from quart import g, jsonify, request
from http import HTTPStatus from http import HTTPStatus
from lnbits.core import crud
import json
import httpx from lnbits.core.crud import get_user
from lnbits.core.crud import get_user, get_wallet
from lnbits.core.services import create_invoice, check_invoice_status from lnbits.core.services import create_invoice, check_invoice_status
from lnbits.decorators import api_check_wallet_key, api_validate_post_request from lnbits.decorators import api_check_wallet_key, api_validate_post_request
from .util import isValidDomain, isvalidIPAddress
from . import subdomains_ext from . import subdomains_ext
from .crud import ( from .crud import (
create_subdomain, 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 ## ALL OK - create an invoice and return it to the user
sats = g.data["sats"] sats = g.data["sats"]
payment_hash, payment_request = await create_invoice(
wallet_id=domain.wallet, try:
amount=sats, payment_hash, payment_request = await create_invoice(
memo=f"subdomain {g.data['subdomain']}.{domain.domain} for {sats} sats for {g.data['duration']} days", wallet_id=domain.wallet,
extra={"tag": "lnsubdomain"}, 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( subdomain = await create_subdomain(
payment_hash=payment_hash, wallet=domain.wallet, **g.data 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) await update_withdraw_link(link.id, **changes)
except ValueError as e: except ValueError as e:
return jsonify({"status": "ERROR", "reason": str(e)}), HTTPStatus.OK return jsonify({"status": "ERROR", "reason": str(e)})
except PermissionError: except PermissionError:
return ( return jsonify({"status": "ERROR", "reason": "Withdraw link is empty."})
jsonify({"status": "ERROR", "reason": "Withdraw link is empty."}), except Exception as e:
HTTPStatus.OK, return jsonify({"status": "ERROR", "reason": str(e)})
)
return jsonify({"status": "OK"}), HTTPStatus.OK return jsonify({"status": "OK"}), HTTPStatus.OK

View file

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