add tests fix interface
This commit is contained in:
dni ⚡
2025-01-08 09:39:18 +01:00
parent 5c688e08c9
commit 5210693440
3 changed files with 126 additions and 51 deletions

View File

@@ -29,6 +29,7 @@ from lnbits.wallets.base import (
PaymentResponse,
PaymentStatus,
PaymentSuccessStatus,
UnsupportedError,
)
from ..crud import (
@@ -965,17 +966,15 @@ async def create_hold_invoice(
invoice_memo = None if description_hash else memo
funding_source = get_funding_source()
if funding_source.__class__.__name__ not in ["LndRestWallet", "LndWallet"]:
raise InvoiceError(
"Hold invoices are only supported with LND.", status="failed"
try:
res = await funding_source.create_hold_invoice(
amount=amount,
memo=invoice_memo,
rhash=rhash,
description_hash=description_hash,
)
res = await funding_source.create_hold_invoice(
amount=amount,
memo=invoice_memo,
rhash=rhash,
description_hash=description_hash,
)
except UnsupportedError as exc:
raise InvoiceError(str(exc), status="failed") from exc
if not res.ok:
raise InvoiceError(
@@ -1004,23 +1003,24 @@ async def create_hold_invoice(
)
# TODO: should return payment
# TODO: update payment status to success
async def settle_hold_invoice(
*,
preimage: str,
) -> bool:
if len(preimage) != 32:
if len(bytes.fromhex(preimage)) != 32:
raise InvoiceError(
"Invalid preimage length. Must be 32 bytes",
status="failed",
)
funding_source = get_funding_source()
if funding_source.__class__.__name__ not in ["LndRestWallet", "LndWallet"]:
raise InvoiceError(
"Hold invoices are only supported with LND.", status="failed"
)
response = await funding_source.settle_hold_invoice(preimage=preimage)
try:
response = await funding_source.settle_hold_invoice(preimage=preimage)
except UnsupportedError as exc:
raise InvoiceError(str(exc), status="failed") from exc
if not response.ok:
raise InvoiceError("Unexpected backend error.", status="failed")
@@ -1028,32 +1028,38 @@ async def settle_hold_invoice(
return True
async def cancel_hold_invoice(payment_hash: str) -> bool:
async def cancel_hold_invoice(payment_hash: str) -> Payment:
payment = await get_standalone_payment(payment_hash, incoming=True)
if not payment:
raise InvoiceError("Payment not found.", status="failed")
funding_source = get_funding_source()
if funding_source.__class__.__name__ not in ["LndRestWallet", "LndWallet"]:
raise InvoiceError(
"Hold invoices are only supported with LND.", status="failed"
)
response = await funding_source.cancel_hold_invoice(payment_hash=payment_hash)
try:
response = await funding_source.cancel_hold_invoice(payment_hash=payment_hash)
except UnsupportedError as exc:
raise InvoiceError(str(exc), status="failed") from exc
if not response.ok:
raise InvoiceError("Unexpected backend error.", status="failed")
return True
raise InvoiceError(
response.error_message or "Unexpected backend error.", status="failed"
)
payment.status = PaymentState.FAILED
await update_payment(payment)
return payment
async def subscribe_hold_invoice(payment_hash: str) -> bool:
payment = await get_standalone_payment(payment_hash, incoming=True)
if not payment:
raise InvoiceError("Payment not found.", status="failed")
funding_source = get_funding_source()
if funding_source.__class__.__name__ not in ["LndRestWallet", "LndWallet"]:
raise InvoiceError(
"Hold invoices are only supported with LND.", status="failed"
)
# if payment.webhook:
# asyncio. create_task(
# funding_source.hold_invoices_stream(
# payment_hash=payment_hash, webhook=payment.webhook
# )
# )
# funding_source = get_funding_source()
try:
# if payment.webhook:
# asyncio. create_task(
# funding_source.hold_invoices_stream(
# payment_hash=payment_hash, webhook=payment.webhook
# )
# )
pass
except UnsupportedError as exc:
raise InvoiceError(str(exc), status="failed") from exc
return True

View File

@@ -346,9 +346,12 @@ class LndRestWallet(Wallet):
else:
data["memo"] = memo or ""
r = await self.client.post(url="/v2/invoices/hodl", json=data)
r.raise_for_status()
data = r.json()
try:
r = await self.client.post(url="/v2/invoices/hodl", json=data)
r.raise_for_status()
data = r.json()
except httpx.HTTPStatusError as exc:
return InvoiceResponse(False, None, None, exc.response.text)
payment_request = data["payment_request"]
payment_hash = base64.b64encode(bytes.fromhex(rhash)).decode("ascii")
@@ -357,20 +360,27 @@ class LndRestWallet(Wallet):
return InvoiceResponse(True, checking_id, payment_request, None)
async def settle_hold_invoice(self, preimage: str) -> PaymentResponse:
data: dict = {"preimage": base64.b64encode(preimage.encode()).decode("ascii")}
r = await self.client.post(url="/v2/invoices/settle", json=data)
r.raise_for_status()
return PaymentResponse(True, None, None, None, None)
data: dict = {
"preimage": base64.b64encode(bytes.fromhex(preimage)).decode("ascii")
}
try:
r = await self.client.post(url="/v2/invoices/settle", json=data)
r.raise_for_status()
return PaymentResponse(True, None, None, None, None)
except httpx.HTTPStatusError as exc:
return PaymentResponse(False, None, None, None, exc.response.text)
async def cancel_hold_invoice(self, payment_hash: str) -> PaymentResponse:
data: dict = {
"payment_hash": base64.b64encode(payment_hash.encode()).decode("ascii")
}
r = await self.client.post(url="/v2/invoices/cancel", json=data)
r.raise_for_status()
return PaymentResponse(True, None, None, None, None)
rhash = bytes.fromhex(payment_hash)
try:
r = await self.client.post(
url="/v2/invoices/cancel",
json={"payment_hash": base64.b64encode(rhash).decode("ascii")},
)
r.raise_for_status()
return PaymentResponse(True, None, None, None, None)
except httpx.HTTPStatusError as exc:
return PaymentResponse(False, None, None, None, exc.response.text)
async def hold_invoices_stream(self, payment_hash: str, webhook: str):
try:

View File

@@ -0,0 +1,59 @@
import hashlib
import os
import pytest
from lnbits.core.services.payments import (
cancel_hold_invoice,
create_hold_invoice,
settle_hold_invoice,
)
from lnbits.exceptions import InvoiceError
from ..helpers import funding_source, is_fake
@pytest.mark.anyio
@pytest.mark.skipif(is_fake, reason="this only works in regtest")
@pytest.mark.skipif(
funding_source.__class__.__name__ in ["LndRestWallet", "LndWallet"],
reason="this should not raise for lnd",
)
async def test_pay_raise_unsupported():
rhash = "0" * 32
with pytest.raises(InvoiceError):
await create_hold_invoice(
wallet_id="fake_wallet_id",
amount=1000,
memo="fake_holdinvoice",
rhash=rhash,
)
with pytest.raises(InvoiceError):
await settle_hold_invoice(preimage=rhash)
with pytest.raises(InvoiceError):
await cancel_hold_invoice(rhash)
@pytest.mark.anyio
@pytest.mark.skipif(is_fake, reason="this only works in regtest")
@pytest.mark.skipif(
funding_source.__class__.__name__ not in ["LndRestWallet"],
reason="this only works for lndrest",
)
async def test_pay_real_hold_invoice(from_wallet):
preimage = os.urandom(32)
preimage_hash = hashlib.sha256(preimage).hexdigest()
payment = await create_hold_invoice(
wallet_id=from_wallet.id,
amount=1000,
memo="test_holdinvoice",
rhash=preimage_hash,
)
assert payment.amount == 1000 * 1000
assert payment.memo == "test_holdinvoice"
assert payment.status == "pending"
assert payment.wallet_id == from_wallet.id
payment = await cancel_hold_invoice(payment_hash=preimage_hash)
assert payment.status == "failed"