Skip to content

Commit

Permalink
new tests?
Browse files Browse the repository at this point in the history
  • Loading branch information
callebtc committed Sep 21, 2024
1 parent 2634c41 commit 6f0ec64
Show file tree
Hide file tree
Showing 3 changed files with 201 additions and 48 deletions.
67 changes: 20 additions & 47 deletions cashu/mint/ledger.py
Original file line number Diff line number Diff line change
Expand Up @@ -151,52 +151,10 @@ async def _check_pending_proofs_and_melt_quotes(self):
)
if not melt_quotes:
return
logger.info("Checking pending melt quotes")
for quote in melt_quotes:
# get pending proofs for quote
pending_proofs = await self.crud.get_pending_proofs_for_quote(
quote_id=quote.quote, db=self.db
)
# check with the backend whether the quote has been paid during downtime
status = await self.backends[Method[quote.method]][
Unit[quote.unit]
].get_payment_status(quote.checking_id)
match status.result:
case PaymentResult.SETTLED:
logger.success(
f"Melt quote checking_id {quote.checking_id} state: {status}"
)
quote.paid_time = int(time.time())
if not quote.paid:
quote.state = MeltQuoteState.paid
if status.fee:
quote.fee_paid = status.fee.to(Unit[quote.unit]).amount
quote.payment_preimage = status.preimage or ""
await self.crud.update_melt_quote(quote=quote, db=self.db)
# invalidate proofs
await self._invalidate_proofs(
proofs=pending_proofs, quote_id=quote.quote
)
# unset pending
await self.db_write._unset_proofs_pending(pending_proofs)
case PaymentResult.FAILED | PaymentResult.UNKNOWN:
logger.info(
f"Melt quote checking_id {quote.checking_id} state: {status}"
)
logger.info(
f"Unsetting pending proofs: {Amount(Unit[quote.unit], sum_proofs(pending_proofs)).str()}"
)
# unset pending
await self.db_write._unset_proofs_pending(
pending_proofs, spent=False
)
case PaymentResult.PENDING:
logger.info(
f"Melt quote checking_id {quote.checking_id} state: {status}"
)
pass
case _:
logger.error(f"Melt quote state unknown: {status.error_message}")
pass
quote = await self.get_melt_quote(quote_id=quote.quote)
logger.info(f"Melt quote {quote.quote} state: {quote.state}")

# ------- KEYS -------

Expand Down Expand Up @@ -755,15 +713,16 @@ async def get_melt_quote(self, quote_id: str) -> MeltQuote:
)

if not melt_quote.paid and not mint_quote:
logger.trace(
logger.debug(
"Lightning: checking outgoing Lightning payment"
f" {melt_quote.checking_id}"
)
status: PaymentStatus = await self.backends[method][
unit
].get_payment_status(melt_quote.checking_id)
logger.debug(f"State: {status.result}")
if status.settled:
logger.trace(f"Setting quote {quote_id} as paid")
logger.debug(f"Setting quote {quote_id} as paid")
melt_quote.state = MeltQuoteState.paid
if status.fee:
melt_quote.fee_paid = status.fee.to(unit).amount
Expand All @@ -772,6 +731,20 @@ async def get_melt_quote(self, quote_id: str) -> MeltQuote:
melt_quote.paid_time = int(time.time())
await self.crud.update_melt_quote(quote=melt_quote, db=self.db)
await self.events.submit(melt_quote)
pending_proofs = await self.crud.get_pending_proofs_for_quote(
quote_id=quote_id, db=self.db
)
await self._invalidate_proofs(proofs=pending_proofs, quote_id=quote_id)
await self.db_write._unset_proofs_pending(pending_proofs)
if status.failed or status.unknown:
logger.debug(f"Setting quote {quote_id} as failed")
melt_quote.state = MeltQuoteState.unpaid
await self.crud.update_melt_quote(quote=melt_quote, db=self.db)
await self.events.submit(melt_quote)
pending_proofs = await self.crud.get_pending_proofs_for_quote(
quote_id=quote_id, db=self.db
)
await self.db_write._unset_proofs_pending(pending_proofs)

return melt_quote

Expand Down
2 changes: 1 addition & 1 deletion tests/test_mint_init.py
Original file line number Diff line number Diff line change
Expand Up @@ -144,7 +144,7 @@ async def create_pending_melts(
request="asdasd",
checking_id=check_id,
unit="sat",
state=MeltQuoteState.unpaid,
state=MeltQuoteState.pending,
amount=100,
fee_reserve=1,
)
Expand Down
180 changes: 180 additions & 0 deletions tests/test_mint_melt.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,180 @@
from typing import List, Tuple

import pytest
import pytest_asyncio

from cashu.core.base import MeltQuote, MeltQuoteState, Proof
from cashu.core.settings import settings
from cashu.lightning.base import PaymentResult
from cashu.mint.ledger import Ledger
from cashu.wallet.wallet import Wallet
from tests.conftest import SERVER_ENDPOINT
from tests.helpers import (
is_regtest,
)

SEED = "TEST_PRIVATE_KEY"
DERIVATION_PATH = "m/0'/0'/0'"
DECRYPTON_KEY = "testdecryptionkey"
ENCRYPTED_SEED = "U2FsdGVkX1_7UU_-nVBMBWDy_9yDu4KeYb7MH8cJTYQGD4RWl82PALH8j-HKzTrI"


async def assert_err(f, msg):
"""Compute f() and expect an error message 'msg'."""
try:
await f
except Exception as exc:
assert exc.args[0] == msg, Exception(
f"Expected error: {msg}, got: {exc.args[0]}"
)


def assert_amt(proofs: List[Proof], expected: int):
"""Assert amounts the proofs contain."""
assert [p.amount for p in proofs] == expected


@pytest_asyncio.fixture(scope="function")
async def wallet(ledger: Ledger):
wallet1 = await Wallet.with_db(
url=SERVER_ENDPOINT,
db="test_data/wallet_mint_api_deprecated",
name="wallet_mint_api_deprecated",
)
await wallet1.load_mint()
yield wallet1


async def create_pending_melts(
ledger: Ledger, check_id: str = "checking_id"
) -> Tuple[Proof, MeltQuote]:
"""Helper function for startup tests for fakewallet. Creates fake pending melt
quote and fake proofs that are in the pending table that look like they're being
used to pay the pending melt quote."""
quote_id = "quote_id"
quote = MeltQuote(
quote=quote_id,
method="bolt11",
request="asdasd",
checking_id=check_id,
unit="sat",
state=MeltQuoteState.pending,
amount=100,
fee_reserve=1,
)
await ledger.crud.store_melt_quote(
quote=quote,
db=ledger.db,
)
pending_proof = Proof(amount=123, C="asdasd", secret="asdasd", id=quote_id)
await ledger.crud.set_proof_pending(
db=ledger.db,
proof=pending_proof,
quote_id=quote_id,
)
# expect a pending melt quote
melt_quotes = await ledger.crud.get_all_melt_quotes_from_pending_proofs(
db=ledger.db
)
assert melt_quotes
return pending_proof, quote


@pytest.mark.asyncio
@pytest.mark.skipif(is_regtest, reason="only fake wallet")
async def test_fakewallet_pending_quote_get_melt_quote_success(ledger: Ledger):
"""Startup routine test. Expects that a pending proofs are removed form the pending db
after the startup routine determines that the associated melt quote was paid."""
pending_proof, quote = await create_pending_melts(ledger)
states = await ledger.db_read.get_proofs_states([pending_proof.Y])
assert states[0].pending
settings.fakewallet_payment_state = PaymentResult.SETTLED.name

# get_melt_quote should check the payment status and update the db
quote2 = await ledger.get_melt_quote(quote_id=quote.quote)
assert quote2.state == MeltQuoteState.paid

# expect that no pending tokens are in db anymore
melt_quotes = await ledger.crud.get_all_melt_quotes_from_pending_proofs(
db=ledger.db
)
assert not melt_quotes

# expect that proofs are spent
states = await ledger.db_read.get_proofs_states([pending_proof.Y])
assert states[0].spent


@pytest.mark.asyncio
@pytest.mark.skipif(is_regtest, reason="only fake wallet")
async def test_fakewallet_pending_quote_get_melt_quote_pending(ledger: Ledger):
"""Startup routine test. Expects that a pending proofs are removed form the pending db
after the startup routine determines that the associated melt quote was paid."""
pending_proof, quote = await create_pending_melts(ledger)
states = await ledger.db_read.get_proofs_states([pending_proof.Y])
assert states[0].pending
settings.fakewallet_payment_state = PaymentResult.PENDING.name

# get_melt_quote should check the payment status and update the db
quote2 = await ledger.get_melt_quote(quote_id=quote.quote)
assert quote2.state == MeltQuoteState.pending

# expect that pending tokens are still in db
melt_quotes = await ledger.crud.get_all_melt_quotes_from_pending_proofs(
db=ledger.db
)
assert melt_quotes

# expect that proofs are pending
states = await ledger.db_read.get_proofs_states([pending_proof.Y])
assert states[0].pending


@pytest.mark.asyncio
@pytest.mark.skipif(is_regtest, reason="only fake wallet")
async def test_fakewallet_pending_quote_get_melt_quote_failed(ledger: Ledger):
"""Startup routine test. Expects that a pending proofs are removed form the pending db
after the startup routine determines that the associated melt quote was paid."""
pending_proof, quote = await create_pending_melts(ledger)
states = await ledger.db_read.get_proofs_states([pending_proof.Y])
assert states[0].pending
settings.fakewallet_payment_state = PaymentResult.FAILED.name

# get_melt_quote should check the payment status and update the db
quote2 = await ledger.get_melt_quote(quote_id=quote.quote)
assert quote2.state == MeltQuoteState.unpaid

# expect that pending tokens are still in db
melt_quotes = await ledger.crud.get_all_melt_quotes_from_pending_proofs(
db=ledger.db
)
assert not melt_quotes

# expect that proofs are pending
states = await ledger.db_read.get_proofs_states([pending_proof.Y])
assert states[0].unspent


@pytest.mark.asyncio
@pytest.mark.skipif(is_regtest, reason="only fake wallet")
async def test_fakewallet_pending_quote_get_melt_quote_unknown(ledger: Ledger):
"""Startup routine test. Expects that a pending proofs are removed form the pending db
after the startup routine determines that the associated melt quote was paid."""
pending_proof, quote = await create_pending_melts(ledger)
states = await ledger.db_read.get_proofs_states([pending_proof.Y])
assert states[0].pending
settings.fakewallet_payment_state = PaymentResult.UNKNOWN.name

# get_melt_quote should check the payment status and update the db
quote2 = await ledger.get_melt_quote(quote_id=quote.quote)
assert quote2.state == MeltQuoteState.unpaid

# expect that pending tokens are still in db
melt_quotes = await ledger.crud.get_all_melt_quotes_from_pending_proofs(
db=ledger.db
)
assert not melt_quotes

# expect that proofs are pending
states = await ledger.db_read.get_proofs_states([pending_proof.Y])
assert states[0].unspent

0 comments on commit 6f0ec64

Please sign in to comment.