From bd671d4596993b95caed4f22be1d63105b102e3b Mon Sep 17 00:00:00 2001 From: callebtc <93376500+callebtc@users.noreply.github.com> Date: Wed, 3 Apr 2024 13:22:58 +0200 Subject: [PATCH] test wallet spent state with hodl invoices --- cashu/lightning/corelightningrest.py | 2 +- cashu/lightning/lndrest.py | 3 - tests/test_mint_regtest.py | 111 +-------------------------- tests/test_wallet_regtest.py | 106 +++++++++++++++++++++++++ 4 files changed, 109 insertions(+), 113 deletions(-) create mode 100644 tests/test_wallet_regtest.py diff --git a/cashu/lightning/corelightningrest.py b/cashu/lightning/corelightningrest.py index cccf440a..6cbb7d10 100644 --- a/cashu/lightning/corelightningrest.py +++ b/cashu/lightning/corelightningrest.py @@ -250,7 +250,7 @@ async def get_payment_status(self, checking_id: str) -> PaymentStatus: if not data.get("pays"): # payment not found logger.error(f"payment not found: {data.get('pays')}") - return PaymentStatus(paid=False) + raise Exception("payment not found") if r.is_error or "error" in data: message = data.get("error") or data diff --git a/cashu/lightning/lndrest.py b/cashu/lightning/lndrest.py index da379f91..3c2e75ad 100644 --- a/cashu/lightning/lndrest.py +++ b/cashu/lightning/lndrest.py @@ -226,9 +226,6 @@ async def get_payment_status(self, checking_id: str) -> PaymentStatus: else line["error"] ) logger.error(f"LND get_payment_status error: {message}") - if "payment isn't initiated" in message: - # payment has not been initiated yet, return False - return PaymentStatus(paid=False) return PaymentStatus(paid=None) payment = line.get("result") diff --git a/tests/test_mint_regtest.py b/tests/test_mint_regtest.py index e6380ebb..10213a00 100644 --- a/tests/test_mint_regtest.py +++ b/tests/test_mint_regtest.py @@ -3,13 +3,12 @@ import pytest import pytest_asyncio -from cashu.core.base import Proof, SpentState +from cashu.core.base import SpentState from cashu.mint.ledger import Ledger from cashu.wallet.wallet import Wallet from tests.conftest import SERVER_ENDPOINT from tests.helpers import ( get_hold_invoice, - get_real_invoice, is_fake, pay_if_regtest, settle_invoice, @@ -73,113 +72,7 @@ async def test_regtest_pending_quote(wallet: Wallet, ledger: Ledger): states = await ledger.check_proofs_state([p.Y for p in send_proofs]) assert all([s.state == SpentState.spent for s in states]) - -@pytest.mark.asyncio -@pytest.mark.skipif(is_fake, reason="is_fake") -async def test_pending_melt_startup_routine(wallet: Wallet, ledger: Ledger): - """ - Test for startup routine that checks the melt quotes for pending proofs in the db. - - We first make a payment s.th. there is a successful lightning payment in the backend. - We then create an artificial melt quote and create fake pending proofs that correspond to it. We then run the - startup routine of the ledger and expect that the pending proofs are removed from the db and the proofs are marked - as spent. - - Args: - wallet (Wallet): _description_ - ledger (Ledger): _description_ - """ - # fill wallet - topup_invoice = await wallet.request_mint(128) - pay_if_regtest(topup_invoice.bolt11) - await wallet.mint(128, id=topup_invoice.id) - assert wallet.balance == 128 - - invoice_dict = get_real_invoice(64) - invoice_payment_request = invoice_dict["payment_request"] - - quote = await wallet.get_pay_amount_with_fees(invoice_payment_request) - total_amount = quote.amount + quote.fee_reserve - _, send_proofs = await wallet.split_to_send(wallet.proofs, total_amount) - melt_response = await wallet.pay_lightning( - proofs=send_proofs, - invoice=invoice_payment_request, - fee_reserve_sat=quote.fee_reserve, - quote_id=quote.quote, - ) - assert melt_response.paid, "Payment not paid" - - pending_proof = Proof(amount=123, C="asdasd", secret="asdasd", id="asdasd") - await ledger.crud.set_proof_pending( - db=ledger.db, - proof=pending_proof, - quote_id=quote.quote, - ) - - # expect that proofs are pending - states = await ledger.check_proofs_state([pending_proof.Y]) - assert all([s.state == SpentState.pending for s in states]) - - # run startup routinge - await ledger.startup_ledger() - - # 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.check_proofs_state([pending_proof.Y]) - assert all([s.state == SpentState.spent for s in states]) - - # 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 - - -@pytest.mark.asyncio -@pytest.mark.skipif(is_fake, reason="is_fake") -async def test_pending_failed_melt_startup_routine(wallet: Wallet, ledger: Ledger): - # fill wallet - topup_invoice = await wallet.request_mint(128) - pay_if_regtest(topup_invoice.bolt11) - await wallet.mint(128, id=topup_invoice.id) - assert wallet.balance == 128 - - invoice_dict = get_real_invoice(64) - invoice_payment_request = invoice_dict["payment_request"] - - quote = await wallet.get_pay_amount_with_fees(invoice_payment_request) - - pending_proof = Proof(amount=123, C="asdasd", secret="asdasd", id="asdasd") - await ledger.crud.set_proof_pending( - db=ledger.db, - proof=pending_proof, - quote_id=quote.quote, - ) - - # expect that proofs are pending - states = await ledger.check_proofs_state([pending_proof.Y]) - assert all([s.state == SpentState.pending for s in states]) - - # run startup routinge, this checks whether there is an associated payment in the backend - # to the melt quote. Since it was never paid, the pending proofs should be removed from the db. - await ledger.startup_ledger() - - # 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 unspent - states = await ledger.check_proofs_state([pending_proof.Y]) - assert all([s.state == SpentState.unspent for s in states]) - - # expect that no pending tokens are in db anymore + # expect that no melt quote is pending melt_quotes = await ledger.crud.get_all_melt_quotes_from_pending_proofs( db=ledger.db ) diff --git a/tests/test_wallet_regtest.py b/tests/test_wallet_regtest.py new file mode 100644 index 00000000..7f3a2311 --- /dev/null +++ b/tests/test_wallet_regtest.py @@ -0,0 +1,106 @@ +import asyncio + +import bolt11 +import pytest +import pytest_asyncio + +from cashu.core.base import SpentState +from cashu.mint.ledger import Ledger +from cashu.wallet.wallet import Wallet +from tests.conftest import SERVER_ENDPOINT +from tests.helpers import ( + cancel_invoice, + get_hold_invoice, + is_fake, + pay_if_regtest, + settle_invoice, +) + + +@pytest_asyncio.fixture(scope="function") +async def wallet(): + wallet = await Wallet.with_db( + url=SERVER_ENDPOINT, + db="test_data/wallet", + name="wallet", + ) + await wallet.load_mint() + yield wallet + + +@pytest.mark.asyncio +@pytest.mark.skipif(is_fake, reason="only regtest") +async def test_regtest_pending_quote(wallet: Wallet, ledger: Ledger): + # fill wallet + invoice = await wallet.request_mint(64) + pay_if_regtest(invoice.bolt11) + await wallet.mint(64, id=invoice.id) + assert wallet.balance == 64 + + # create hodl invoice + preimage, invoice_dict = get_hold_invoice(16) + invoice_payment_request = str(invoice_dict["payment_request"]) + + # wallet pays the invoice + quote = await wallet.get_pay_amount_with_fees(invoice_payment_request) + total_amount = quote.amount + quote.fee_reserve + _, send_proofs = await wallet.split_to_send(wallet.proofs, total_amount) + asyncio.create_task( + wallet.pay_lightning( + proofs=send_proofs, + invoice=invoice_payment_request, + fee_reserve_sat=quote.fee_reserve, + quote_id=quote.quote, + ) + ) + await asyncio.sleep(1) + + states = await wallet.check_proof_state(send_proofs) + assert all([s.state == SpentState.pending for s in states.states]) + + settle_invoice(preimage=preimage) + + await asyncio.sleep(1) + + states = await wallet.check_proof_state(send_proofs) + assert all([s.state == SpentState.spent for s in states.states]) + + +@pytest.mark.asyncio +@pytest.mark.skipif(is_fake, reason="only regtest") +async def test_regtest_failed_quote(wallet: Wallet, ledger: Ledger): + # fill wallet + invoice = await wallet.request_mint(64) + pay_if_regtest(invoice.bolt11) + await wallet.mint(64, id=invoice.id) + assert wallet.balance == 64 + + # create hodl invoice + preimage, invoice_dict = get_hold_invoice(16) + invoice_payment_request = str(invoice_dict["payment_request"]) + invoice_obj = bolt11.decode(invoice_payment_request) + preimage_hash = invoice_obj.payment_hash + + # wallet pays the invoice + quote = await wallet.get_pay_amount_with_fees(invoice_payment_request) + total_amount = quote.amount + quote.fee_reserve + _, send_proofs = await wallet.split_to_send(wallet.proofs, total_amount) + asyncio.create_task( + wallet.pay_lightning( + proofs=send_proofs, + invoice=invoice_payment_request, + fee_reserve_sat=quote.fee_reserve, + quote_id=quote.quote, + ) + ) + await asyncio.sleep(1) + + states = await wallet.check_proof_state(send_proofs) + assert all([s.state == SpentState.pending for s in states.states]) + + cancel_invoice(preimage_hash=preimage_hash) + + await asyncio.sleep(1) + + states = await wallet.check_proof_state(send_proofs) + assert all([s.state == SpentState.unspent for s in states.states])