Skip to content

Commit

Permalink
fix tests
Browse files Browse the repository at this point in the history
  • Loading branch information
callebtc committed Oct 19, 2023
1 parent d17e65c commit 498fa3d
Show file tree
Hide file tree
Showing 9 changed files with 100 additions and 88 deletions.
12 changes: 7 additions & 5 deletions cashu/lightning/base.py
Original file line number Diff line number Diff line change
@@ -1,28 +1,30 @@
from abc import ABC, abstractmethod
from typing import Coroutine, NamedTuple, Optional
from typing import Coroutine, Optional

from pydantic import BaseModel

class StatusResponse(NamedTuple):

class StatusResponse(BaseModel):
error_message: Optional[str]
balance_msat: int


class InvoiceResponse(NamedTuple):
class InvoiceResponse(BaseModel):
ok: bool # True: invoice created, False: failed
checking_id: Optional[str] = None
payment_request: Optional[str] = None
error_message: Optional[str] = None


class PaymentResponse(NamedTuple):
class PaymentResponse(BaseModel):
ok: Optional[bool] = None # True: paid, False: failed, None: pending or unknown
checking_id: Optional[str] = None
fee_msat: Optional[int] = None
preimage: Optional[str] = None
error_message: Optional[str] = None


class PaymentStatus(NamedTuple):
class PaymentStatus(BaseModel):
paid: Optional[bool] = None
fee_msat: Optional[int] = None
preimage: Optional[str] = None
Expand Down
12 changes: 7 additions & 5 deletions cashu/lightning/fake.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ class FakeWallet(Wallet):
).hex()

async def status(self) -> StatusResponse:
return StatusResponse(None, 1337)
return StatusResponse(error_message=None, balance_msat=1337)

async def create_invoice(
self,
Expand Down Expand Up @@ -92,7 +92,9 @@ async def create_invoice(

payment_request = encode(bolt11, self.privkey)

return InvoiceResponse(True, checking_id, payment_request)
return InvoiceResponse(
ok=True, checking_id=checking_id, payment_request=payment_request
)

async def pay_invoice(self, bolt11: str, fee_limit_msat: int) -> PaymentResponse:
invoice = decode(bolt11)
Expand All @@ -114,12 +116,12 @@ async def pay_invoice(self, bolt11: str, fee_limit_msat: int) -> PaymentResponse
async def get_invoice_status(self, checking_id: str) -> PaymentStatus:
if STOCHASTIC_INVOICE:
paid = random.random() > 0.7
return PaymentStatus(paid)
return PaymentStatus(paid=paid)
paid = checking_id in self.paid_invoices or BRR
return PaymentStatus(paid or None)
return PaymentStatus(paid=paid or None)

async def get_payment_status(self, _: str) -> PaymentStatus:
return PaymentStatus(None)
return PaymentStatus(paid=None)

async def paid_invoices_stream(self) -> AsyncGenerator[str, None]:
while True:
Expand Down
44 changes: 24 additions & 20 deletions cashu/mint/ledger.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@
from ..core.helpers import fee_reserve, sum_proofs
from ..core.settings import settings
from ..core.split import amount_split
from ..lightning.base import Wallet
from ..lightning.base import PaymentResponse, Wallet
from ..mint.crud import LedgerCrud
from .conditions import LedgerSpendingConditions
from .lightning import LedgerLightning
Expand Down Expand Up @@ -247,23 +247,26 @@ async def request_mint(self, amount: int) -> Tuple[str, str]:
raise NotAllowedError("Mint does not allow minting new tokens.")

logger.trace(f"requesting invoice for {amount} satoshis")
payment_request, payment_hash = await self._request_lightning_invoice(amount)
logger.trace(f"got invoice {payment_request} with hash {payment_hash}")
assert payment_request and payment_hash, LightningError(
"could not fetch invoice from Lightning backend"
invoice_response = await self._request_lightning_invoice(amount)
logger.trace(
f"got invoice {invoice_response.payment_request} with check id"
f" {invoice_response.checking_id}"
)
assert (
invoice_response.payment_request and invoice_response.checking_id
), LightningError("could not fetch invoice from Lightning backend")

invoice = Invoice(
amount=amount,
id=random_hash(),
bolt11=payment_request,
payment_hash=payment_hash, # what we got from the backend
bolt11=invoice_response.payment_request,
payment_hash=invoice_response.checking_id, # what we got from the backend
issued=False,
)
logger.trace(f"crud: storing invoice {invoice.id} in db")
await self.crud.store_lightning_invoice(invoice=invoice, db=self.db)
logger.trace(f"crud: stored invoice {invoice.id} in db")
return payment_request, invoice.id
return invoice_response.payment_request, invoice.id

async def mint(
self,
Expand Down Expand Up @@ -357,32 +360,31 @@ async def melt(

if settings.lightning:
logger.trace(f"paying lightning invoice {invoice}")
status, preimage, paid_fee_msat = await self._pay_lightning_invoice(
payment = await self._pay_lightning_invoice(
invoice, reserve_fees_sat * 1000
)
preimage = preimage or ""
logger.trace("paid lightning invoice")
else:
status, preimage, paid_fee_msat = True, "preimage", 0
payment = PaymentResponse(ok=True, preimage="preimage", fee_msat=0)

logger.debug(
f"Melt status: {status}: preimage: {preimage}, fee_msat:"
f" {paid_fee_msat}"
f"Melt status: {payment.ok}: preimage: {payment.preimage}, fee_msat:"
f" {payment.fee_msat}"
)

if not status:
if not payment.ok:
raise LightningError("Lightning payment unsuccessful.")

# melt successful, invalidate proofs
await self._invalidate_proofs(proofs)

# prepare change to compensate wallet for overpaid fees
return_promises: List[BlindedSignature] = []
if outputs and paid_fee_msat is not None:
if outputs and payment.fee_msat is not None:
return_promises = await self._generate_change_promises(
total_provided=total_provided,
invoice_amount=invoice_amount,
ln_fee_msat=paid_fee_msat,
ln_fee_msat=payment.fee_msat,
outputs=outputs,
)

Expand All @@ -393,7 +395,7 @@ async def melt(
# delete proofs from pending list
await self._unset_proofs_pending(proofs)

return status, preimage, return_promises
return payment.ok, payment.preimage or "", return_promises

async def get_melt_fees(self, pr: str) -> int:
"""Returns the fee reserve (in sat) that a wallet must add to its proofs
Expand All @@ -416,9 +418,11 @@ async def get_melt_fees(self, pr: str) -> int:
"get_melt_fees: checking lightning invoice:"
f" {decoded_invoice.payment_hash}"
)
paid = await self.lightning.get_invoice_status(decoded_invoice.payment_hash)
logger.trace(f"get_melt_fees: paid: {paid}")
internal = paid.paid is False
payment = await self.lightning.get_invoice_status(
decoded_invoice.payment_hash
)
logger.trace(f"get_melt_fees: paid: {payment.paid}")
internal = payment.paid is False
else:
amount_msat = 0
internal = True
Expand Down
70 changes: 35 additions & 35 deletions cashu/mint/lightning.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from typing import Literal, Optional, Tuple, Union
from typing import Optional, Union

from loguru import logger

Expand All @@ -10,7 +10,7 @@
InvoiceNotPaidError,
LightningError,
)
from ..lightning.base import Wallet
from ..lightning.base import InvoiceResponse, PaymentResponse, PaymentStatus, Wallet
from ..mint.crud import LedgerCrud
from .protocols import SupportLightning, SupportsDb

Expand All @@ -22,7 +22,7 @@ class LedgerLightning(SupportLightning, SupportsDb):
crud: LedgerCrud
db: Database

async def _request_lightning_invoice(self, amount: int) -> Tuple[str, str]:
async def _request_lightning_invoice(self, amount: int) -> InvoiceResponse:
"""Generate a Lightning invoice using the funding source backend.
Args:
Expand All @@ -38,30 +38,30 @@ async def _request_lightning_invoice(self, amount: int) -> Tuple[str, str]:
"_request_lightning_invoice: Requesting Lightning invoice for"
f" {amount} satoshis."
)
error, balance = await self.lightning.status()
logger.trace(f"_request_lightning_invoice: Lightning wallet balance: {balance}")
if error:
raise LightningError(f"Lightning wallet not responding: {error}")
(
ok,
checking_id,
payment_request,
error_message,
) = await self.lightning.create_invoice(amount, "Cashu deposit")
status = await self.lightning.status()
logger.trace(
f"_request_lightning_invoice: Lightning invoice: {payment_request}"
"_request_lightning_invoice: Lightning wallet balance:"
f" {status.balance_msat}"
)
if status.error_message:
raise LightningError(
f"Lightning wallet not responding: {status.error_message}"
)
payment = await self.lightning.create_invoice(amount, "Cashu deposit")
logger.trace(
f"_request_lightning_invoice: Lightning invoice: {payment.payment_request}"
)

if not ok:
raise LightningError(f"Lightning wallet error: {error_message}")
assert payment_request and checking_id, LightningError(
if not payment.ok:
raise LightningError(f"Lightning wallet error: {payment.error_message}")
assert payment.payment_request and payment.checking_id, LightningError(
"could not fetch invoice from Lightning backend"
)
return payment_request, checking_id
return payment

async def _check_lightning_invoice(
self, *, amount: int, id: str, conn: Optional[Connection] = None
) -> Literal[True]:
) -> PaymentStatus:
"""Checks with the Lightning backend whether an invoice with `id` was paid.
Args:
Expand Down Expand Up @@ -98,7 +98,7 @@ async def _check_lightning_invoice(
try:
status = await self.lightning.get_invoice_status(invoice.payment_hash)
if status.paid:
return status.paid
return status
else:
raise InvoiceNotPaidError()
except Exception as e:
Expand All @@ -108,7 +108,9 @@ async def _check_lightning_invoice(
)
raise e

async def _pay_lightning_invoice(self, invoice: str, fee_limit_msat: int):
async def _pay_lightning_invoice(
self, invoice: str, fee_limit_msat: int
) -> PaymentResponse:
"""Pays a Lightning invoice via the funding source backend.
Args:
Expand All @@ -121,17 +123,15 @@ async def _pay_lightning_invoice(self, invoice: str, fee_limit_msat: int):
Returns:
Tuple[bool, string, int]: Returns payment status, preimage of invoice, paid fees (in Millisatoshi)
"""
error, balance = await self.lightning.status()
if error:
raise LightningError(f"Lightning wallet not responding: {error}")
(
ok,
checking_id,
fee_msat,
preimage,
error_message,
) = await self.lightning.pay_invoice(invoice, fee_limit_msat=fee_limit_msat)
logger.trace(f"_pay_lightning_invoice: Lightning payment status: {ok}")
# make sure that fee is positive
fee_msat = abs(fee_msat) if fee_msat else fee_msat
return ok, preimage, fee_msat
status = await self.lightning.status()
if status.error_message:
raise LightningError(
f"Lightning wallet not responding: {status.error_message}"
)
payment = await self.lightning.pay_invoice(
invoice, fee_limit_msat=fee_limit_msat
)
logger.trace(f"_pay_lightning_invoice: Lightning payment status: {payment.ok}")
# make sure that fee is positive and not None
payment.fee_msat = abs(payment.fee_msat) if payment.fee_msat else 0
return payment
8 changes: 4 additions & 4 deletions cashu/mint/startup.py
Original file line number Diff line number Diff line change
Expand Up @@ -52,14 +52,14 @@ async def start_mint_init():

if settings.lightning:
logger.info(f"Using backend: {settings.mint_lightning_backend}")
error_message, balance = await ledger.lightning.status()
if error_message:
status = await ledger.lightning.status()
if status.error_message:
logger.warning(
f"The backend for {ledger.lightning.__class__.__name__} isn't"
f" working properly: '{error_message}'",
f" working properly: '{status.error_message}'",
RuntimeWarning,
)
logger.info(f"Lightning balance: {balance} msat")
logger.info(f"Lightning balance: {status.balance_msat} msat")

logger.info(f"Data dir: {settings.cashu_dir}")
logger.info("Mint started.")
Expand Down
20 changes: 9 additions & 11 deletions cashu/wallet/api/router.py
Original file line number Diff line number Diff line change
Expand Up @@ -49,13 +49,15 @@
router: APIRouter = APIRouter()


async def mint_wallet(mint_url: Optional[str] = None):
async def mint_wallet(
mint_url: Optional[str] = None, raise_connection_error: bool = True
):
wallet = await LightningWallet.with_db(
mint_url or settings.mint_url,
db=os.path.join(settings.cashu_dir, settings.wallet_name),
name=settings.wallet_name,
)
await wallet.async_init()
await wallet.async_init(raise_connection_error=raise_connection_error)
return wallet


Expand All @@ -69,15 +71,9 @@ async def mint_wallet(mint_url: Optional[str] = None):
@router.on_event("startup")
async def start_wallet():
global wallet
wallet = await LightningWallet.with_db(
settings.mint_url,
db=os.path.join(settings.cashu_dir, settings.wallet_name),
name=settings.wallet_name,
)

wallet = await mint_wallet(settings.mint_url, raise_connection_error=False)
if settings.tor and not TorProxy().check_platform():
raise Exception("tor not working.")
await wallet.async_init()


@router.post(
Expand Down Expand Up @@ -166,8 +162,10 @@ async def lightning_balance() -> StatusResponse:
try:
await wallet.load_proofs(reload=True)
except Exception as exc:
return StatusResponse(str(exc), balance_msat=0)
return StatusResponse(None, balance_msat=wallet.available_balance * 1000)
return StatusResponse(error_message=str(exc), balance_msat=0)
return StatusResponse(
error_message=None, balance_msat=wallet.available_balance * 1000
)


@router.post(
Expand Down
10 changes: 6 additions & 4 deletions cashu/wallet/lightning/lightning.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,13 +17,15 @@ class LightningWallet(Wallet):
Lightning wallet interface for Cashu
"""

# wallet: Wallet

async def async_init(self):
async def async_init(self, raise_connection_error: bool = True):
"""Async init for lightning wallet"""
settings.tor = False
await self.load_proofs()
await self.load_mint()
try:
await self.load_mint()
except Exception as e:
if raise_connection_error:
raise e

def __init__(self, *args, **kwargs):
if not args and not kwargs:
Expand Down
Loading

0 comments on commit 498fa3d

Please sign in to comment.