Skip to content

Commit

Permalink
test blink failed payment (#446)
Browse files Browse the repository at this point in the history
  • Loading branch information
callebtc authored Feb 19, 2024
1 parent 2189728 commit 1c2c01c
Show file tree
Hide file tree
Showing 3 changed files with 77 additions and 18 deletions.
47 changes: 31 additions & 16 deletions cashu/lightning/blink.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
import asyncio
import json
import math
from typing import Dict, Optional
from typing import Dict, Optional, Union

import bolt11
import httpx
Expand Down Expand Up @@ -201,23 +201,36 @@ async def pay_invoice(
return PaymentResponse(ok=False, error_message=str(e))

resp: dict = r.json()

error_message: Union[None, str] = None
fee: Union[None, int] = None
if resp.get("data", {}).get("lnInvoicePaymentSend", {}).get("errors"):
error_message = (
resp["data"]["lnInvoicePaymentSend"]["errors"][0].get("message")
or "Unknown error"
)

paid = self.payment_execution_statuses[
resp.get("data", {}).get("lnInvoicePaymentSend", {}).get("status")
]
fee = (
resp.get("data", {})
.get("lnInvoicePaymentSend", {})
.get("transaction", {})
.get("settlementFee")
)
if paid is None:
error_message = "Invoice already paid."

if resp.get("data", {}).get("lnInvoicePaymentSend", {}).get("transaction", {}):
fee = (
resp.get("data", {})
.get("lnInvoicePaymentSend", {})
.get("transaction", {})
.get("settlementFee")
)
checking_id = quote.request

return PaymentResponse(
ok=paid,
checking_id=checking_id,
fee=Amount(Unit.sat, fee),
fee=Amount(Unit.sat, fee) if fee else None,
preimage=None,
error_message="Invoice already paid." if paid is None else None,
error_message=error_message,
)

async def get_invoice_status(self, checking_id: str) -> PaymentStatus:
Expand Down Expand Up @@ -373,15 +386,17 @@ async def get_payment_quote(self, bolt11: str) -> PaymentQuoteResponse:
r.raise_for_status()
resp: dict = r.json()
if resp.get("data", {}).get("lnInvoiceFeeProbe", {}).get("errors"):
raise Exception(
resp["data"]["lnInvoiceFeeProbe"]["errors"][0].get("message")
or "Unknown error"
# if there was an error, we simply ignore the response and decide the fees ourselves
fees_response_msat = 0
logger.debug(
f"Blink probe error: {resp['data']['lnInvoiceFeeProbe']['errors'][0].get('message')}"
)

fees_response_msat = (
int(resp.get("data", {}).get("lnInvoiceFeeProbe", {}).get("amount"))
* 1000
)
else:
fees_response_msat = (
int(resp.get("data", {}).get("lnInvoiceFeeProbe", {}).get("amount"))
* 1000
)
except httpx.ReadTimeout:
pass
except Exception as e:
Expand Down
4 changes: 2 additions & 2 deletions cashu/mint/ledger.py
Original file line number Diff line number Diff line change
Expand Up @@ -692,8 +692,8 @@ async def melt(
melt_quote, melt_quote.fee_reserve * 1000
)
logger.debug(
f"Melt status: {payment.ok}: preimage: {payment.preimage},"
f" fee: {payment.fee.str() if payment.fee else 0}"
f"Melt – Ok: {payment.ok}: preimage: {payment.preimage},"
f" fee: {payment.fee.str() if payment.fee is not None else 'None'}"
)
if not payment.ok:
raise LightningError(
Expand Down
44 changes: 44 additions & 0 deletions tests/test_mint_lightning_blink.py
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,38 @@ async def test_blink_pay_invoice():
assert payment.checking_id == payment_request


@respx.mock
@pytest.mark.asyncio
async def test_blink_pay_invoice_failure():
mock_response = {
"data": {
"lnInvoicePaymentSend": {
"status": "FAILURE",
"errors": [
{"message": "This is the error", "codee": "ROUTE_FINDING_ERROR"},
],
}
}
}
respx.post(blink.endpoint).mock(return_value=Response(200, json=mock_response))
quote = MeltQuote(
request=payment_request,
quote="asd",
method="bolt11",
checking_id=payment_request,
unit="sat",
amount=100,
fee_reserve=12,
paid=False,
)
payment = await blink.pay_invoice(quote, 1000)
assert not payment.ok
assert payment.fee is None
assert payment.error_message
assert "This is the error" in payment.error_message
assert payment.checking_id == payment_request


@respx.mock
@pytest.mark.asyncio
async def test_blink_get_invoice_status():
Expand Down Expand Up @@ -180,3 +212,15 @@ async def test_blink_get_payment_quote():
assert quote.checking_id == payment_request_1
assert quote.amount == Amount(Unit.msat, 1000) # msat
assert quote.fee == Amount(Unit.msat, MINIMUM_FEE_MSAT) # msat


@respx.mock
@pytest.mark.asyncio
async def test_blink_get_payment_quote_backend_error():
# response says error but invoice (1000 sat) * 0.5% is 5 sat so we expect 10 sat
mock_response = {"data": {"lnInvoiceFeeProbe": {"errors": [{"message": "error"}]}}}
respx.post(blink.endpoint).mock(return_value=Response(200, json=mock_response))
quote = await blink.get_payment_quote(payment_request)
assert quote.checking_id == payment_request
assert quote.amount == Amount(Unit.msat, 1000000) # msat
assert quote.fee == Amount(Unit.msat, 5000) # msat

0 comments on commit 1c2c01c

Please sign in to comment.