mirror of
https://github.com/aljazceru/nutshell.git
synced 2026-02-11 03:34:22 +01:00
Mint: table locks (#566)
* clean up db * db: table lock * db.table_with_schema * fix encrypt.py * postgres nowait * add timeout to lock * melt quote state in db * kinda working * kinda working with postgres * remove dispose * getting there * porperly clean up db for tests * faster tests * configure connection pooling * try github with connection pool * invoice dispatcher does not lock db * fakewallet: pay_if_regtest waits * pay fakewallet invoices * add more * faster * slower * pay_if_regtest async * do not lock the invoice dispatcher * test: do I get disk I/O errors if we disable the invoice_callback_dispatcher? * fix fake so it workss without a callback dispatchert * test on github * readd tasks * refactor * increase time for lock invoice disatcher * try avoiding a race * remove task * github actions: test regtest with postgres * mint per module * no connection pool for testing * enable pool * do not resend paid event * reuse connection * close db connections * sessions * enable debug * dispose engine * disable connection pool for tests * enable connection pool for postgres only * clean up shutdown routine * remove wait for lightning fakewallet lightning invoice * cancel invoice listener tasks on shutdown * fakewallet conftest: decrease outgoing delay * delay payment and set postgres only if needed * disable fail fast for regtest * clean up regtest.yml * change order of tests_db.py * row-specific mint_quote locking * refactor * fix lock statement * refactor swap * refactor * remove psycopg2 * add connection string example to .env.example * remove unnecessary pay * shorter sleep in test_wallet_subscription_swap
This commit is contained in:
@@ -22,7 +22,8 @@ from cashu.mint.ledger import Ledger
|
||||
SERVER_PORT = 3337
|
||||
SERVER_ENDPOINT = f"http://localhost:{SERVER_PORT}"
|
||||
|
||||
settings.debug = False
|
||||
settings.debug = True
|
||||
settings.log_level = "TRACE"
|
||||
settings.cashu_dir = "./test_data/"
|
||||
settings.mint_host = "localhost"
|
||||
settings.mint_port = SERVER_PORT
|
||||
@@ -49,6 +50,7 @@ settings.mint_transaction_rate_limit_per_minute = 60
|
||||
settings.mint_lnd_enable_mpp = True
|
||||
settings.mint_clnrest_enable_mpp = False
|
||||
settings.mint_input_fee_ppk = 0
|
||||
settings.db_connection_pool = True
|
||||
|
||||
assert "test" in settings.cashu_dir
|
||||
shutil.rmtree(settings.cashu_dir, ignore_errors=True)
|
||||
@@ -83,11 +85,6 @@ class UvicornServer(multiprocessing.Process):
|
||||
async def ledger():
|
||||
async def start_mint_init(ledger: Ledger) -> Ledger:
|
||||
await migrate_databases(ledger.db, migrations_mint)
|
||||
# add a new keyset (with a new ID) which will be duplicated with a keyset with an
|
||||
# old ID by mint migration m018_duplicate_deprecated_keyset_ids
|
||||
# await ledger.activate_keyset(derivation_path=settings.mint_derivation_path, version="0.15.0")
|
||||
# await migrations_mint.m018_duplicate_deprecated_keyset_ids(ledger.db)
|
||||
|
||||
ledger = Ledger(
|
||||
db=Database("mint", settings.mint_database),
|
||||
seed=settings.mint_private_key,
|
||||
@@ -107,8 +104,10 @@ async def ledger():
|
||||
# clear postgres database
|
||||
db = Database("mint", settings.mint_database)
|
||||
async with db.connect() as conn:
|
||||
# drop all tables
|
||||
await conn.execute("DROP SCHEMA public CASCADE;")
|
||||
await conn.execute("CREATE SCHEMA public;")
|
||||
await db.engine.dispose()
|
||||
|
||||
wallets_module = importlib.import_module("cashu.lightning")
|
||||
lightning_backend = getattr(wallets_module, settings.mint_backend_bolt11_sat)()
|
||||
@@ -125,6 +124,7 @@ async def ledger():
|
||||
ledger = await start_mint_init(ledger)
|
||||
yield ledger
|
||||
print("teardown")
|
||||
await ledger.shutdown_ledger()
|
||||
|
||||
|
||||
# # This fixture is used for tests that require API access to the mint
|
||||
@@ -134,6 +134,7 @@ def mint():
|
||||
"cashu.mint.app:app",
|
||||
port=settings.mint_listen_port,
|
||||
host=settings.mint_listen_host,
|
||||
log_level="trace",
|
||||
)
|
||||
|
||||
server = UvicornServer(config=config)
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import asyncio
|
||||
import hashlib
|
||||
import importlib
|
||||
import json
|
||||
@@ -6,13 +7,44 @@ import random
|
||||
import string
|
||||
import time
|
||||
from subprocess import PIPE, Popen, TimeoutExpired
|
||||
from typing import Tuple
|
||||
from typing import List, Tuple, Union
|
||||
|
||||
from loguru import logger
|
||||
|
||||
from cashu.core.errors import CashuError
|
||||
from cashu.core.settings import settings
|
||||
|
||||
|
||||
async def assert_err(f, msg: Union[str, CashuError]):
|
||||
"""Compute f() and expect an error message 'msg'."""
|
||||
try:
|
||||
await f
|
||||
except Exception as exc:
|
||||
error_message: str = str(exc.args[0])
|
||||
if isinstance(msg, CashuError):
|
||||
if msg.detail not in error_message:
|
||||
raise Exception(
|
||||
f"CashuError. Expected error: {msg.detail}, got: {error_message}"
|
||||
)
|
||||
return
|
||||
if msg not in error_message:
|
||||
raise Exception(f"Expected error: {msg}, got: {error_message}")
|
||||
return
|
||||
raise Exception(f"Expected error: {msg}, got no error")
|
||||
|
||||
|
||||
async def assert_err_multiple(f, msgs: List[str]):
|
||||
"""Compute f() and expect an error message 'msg'."""
|
||||
try:
|
||||
await f
|
||||
except Exception as exc:
|
||||
for msg in msgs:
|
||||
if msg in str(exc.args[0]):
|
||||
return
|
||||
raise Exception(f"Expected error: {msgs}, got: {exc.args[0]}")
|
||||
raise Exception(f"Expected error: {msgs}, got no error")
|
||||
|
||||
|
||||
def get_random_string(N: int = 10):
|
||||
return "".join(
|
||||
random.SystemRandom().choice(string.ascii_uppercase + string.digits)
|
||||
@@ -157,6 +189,9 @@ def pay_onchain(address: str, sats: int) -> str:
|
||||
return run_cmd(cmd)
|
||||
|
||||
|
||||
def pay_if_regtest(bolt11: str):
|
||||
async def pay_if_regtest(bolt11: str):
|
||||
if is_regtest:
|
||||
pay_real_invoice(bolt11)
|
||||
if is_fake:
|
||||
await asyncio.sleep(settings.fakewallet_delay_incoming_payment or 0)
|
||||
await asyncio.sleep(0.1)
|
||||
|
||||
292
tests/test_db.py
292
tests/test_db.py
@@ -1,15 +1,81 @@
|
||||
import asyncio
|
||||
import datetime
|
||||
import os
|
||||
import time
|
||||
from typing import List
|
||||
|
||||
import pytest
|
||||
import pytest_asyncio
|
||||
|
||||
from cashu.core import db
|
||||
from cashu.core.db import Connection, timestamp_now
|
||||
from cashu.core.db import Connection
|
||||
from cashu.core.migrations import backup_database
|
||||
from cashu.core.settings import settings
|
||||
from cashu.mint.ledger import Ledger
|
||||
from tests.helpers import is_github_actions, is_postgres
|
||||
from cashu.wallet.wallet import Wallet
|
||||
from tests.conftest import SERVER_ENDPOINT
|
||||
from tests.helpers import is_github_actions, is_postgres, pay_if_regtest
|
||||
|
||||
|
||||
async def assert_err(f, msg):
|
||||
"""Compute f() and expect an error message 'msg'."""
|
||||
try:
|
||||
await f
|
||||
except Exception as exc:
|
||||
if msg not in str(exc.args[0]):
|
||||
raise Exception(f"Expected error: {msg}, got: {exc.args[0]}")
|
||||
return
|
||||
raise Exception(f"Expected error: {msg}, got no error")
|
||||
|
||||
|
||||
async def assert_err_multiple(f, msgs: List[str]):
|
||||
"""Compute f() and expect an error message 'msg'."""
|
||||
try:
|
||||
await f
|
||||
except Exception as exc:
|
||||
for msg in msgs:
|
||||
if msg in str(exc.args[0]):
|
||||
return
|
||||
raise Exception(f"Expected error: {msgs}, got: {exc.args[0]}")
|
||||
raise Exception(f"Expected error: {msgs}, got no error")
|
||||
|
||||
|
||||
@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
|
||||
async def test_db_tables(ledger: Ledger):
|
||||
async with ledger.db.connect() as conn:
|
||||
if ledger.db.type == db.SQLITE:
|
||||
tables_res = await conn.execute(
|
||||
"SELECT name FROM sqlite_master WHERE type='table';"
|
||||
)
|
||||
elif ledger.db.type in {db.POSTGRES, db.COCKROACH}:
|
||||
tables_res = await conn.execute(
|
||||
"SELECT table_name FROM information_schema.tables WHERE table_schema ="
|
||||
" 'public';"
|
||||
)
|
||||
tables = [t[0] for t in tables_res.all()]
|
||||
tables_expected = [
|
||||
"dbversions",
|
||||
"keysets",
|
||||
"proofs_used",
|
||||
"proofs_pending",
|
||||
"melt_quotes",
|
||||
"mint_quotes",
|
||||
"mint_pubkeys",
|
||||
"promises",
|
||||
]
|
||||
for table in tables_expected:
|
||||
assert table in tables
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
@@ -27,7 +93,7 @@ async def test_backup_db_migration(ledger: Ledger):
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_timestamp_now(ledger: Ledger):
|
||||
ts = timestamp_now(ledger.db)
|
||||
ts = ledger.db.timestamp_now_str()
|
||||
if ledger.db.type == db.SQLITE:
|
||||
assert isinstance(ts, str)
|
||||
assert int(ts) <= time.time()
|
||||
@@ -37,33 +103,203 @@ async def test_timestamp_now(ledger: Ledger):
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_get_connection(ledger: Ledger):
|
||||
async def test_db_connect(ledger: Ledger):
|
||||
async with ledger.db.connect() as conn:
|
||||
assert isinstance(conn, Connection)
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_db_tables(ledger: Ledger):
|
||||
async with ledger.db.connect() as conn:
|
||||
if ledger.db.type == db.SQLITE:
|
||||
tables_res = await conn.execute(
|
||||
"SELECT name FROM sqlite_master WHERE type='table';"
|
||||
)
|
||||
elif ledger.db.type in {db.POSTGRES, db.COCKROACH}:
|
||||
tables_res = await conn.execute(
|
||||
"SELECT table_name FROM information_schema.tables WHERE table_schema ="
|
||||
" 'public';"
|
||||
)
|
||||
tables = [t[0] for t in await tables_res.fetchall()]
|
||||
tables_expected = [
|
||||
"dbversions",
|
||||
"keysets",
|
||||
"proofs_used",
|
||||
"proofs_pending",
|
||||
"melt_quotes",
|
||||
"mint_quotes",
|
||||
"mint_pubkeys",
|
||||
"promises",
|
||||
]
|
||||
for table in tables_expected:
|
||||
assert table in tables
|
||||
async def test_db_get_connection(ledger: Ledger):
|
||||
async with ledger.db.get_connection() as conn:
|
||||
assert isinstance(conn, Connection)
|
||||
|
||||
|
||||
# @pytest.mark.asyncio
|
||||
# async def test_db_get_connection_locked(wallet: Wallet, ledger: Ledger):
|
||||
# invoice = await wallet.request_mint(64)
|
||||
|
||||
# async def get_connection():
|
||||
# """This code makes sure that only the error of the second connection is raised (which we check in the assert_err)"""
|
||||
# try:
|
||||
# async with ledger.db.get_connection(lock_table="mint_quotes"):
|
||||
# try:
|
||||
# async with ledger.db.get_connection(
|
||||
# lock_table="mint_quotes", lock_timeout=0.1
|
||||
# ) as conn2:
|
||||
# # write something with conn1, we never reach this point if the lock works
|
||||
# await conn2.execute(
|
||||
# f"INSERT INTO mint_quotes (quote, amount) VALUES ('{invoice.id}', 100);"
|
||||
# )
|
||||
# except Exception as exc:
|
||||
# # this is expected to raise
|
||||
# raise Exception(f"conn2: {str(exc)}")
|
||||
|
||||
# except Exception as exc:
|
||||
# if str(exc).startswith("conn2"):
|
||||
# raise exc
|
||||
# else:
|
||||
# raise Exception("not expected to happen")
|
||||
|
||||
# await assert_err(get_connection(), "failed to acquire database lock")
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_db_get_connection_lock_row(wallet: Wallet, ledger: Ledger):
|
||||
if ledger.db.type == db.SQLITE:
|
||||
pytest.skip("SQLite does not support row locking")
|
||||
|
||||
invoice = await wallet.request_mint(64)
|
||||
|
||||
async def get_connection():
|
||||
"""This code makes sure that only the error of the second connection is raised (which we check in the assert_err)"""
|
||||
try:
|
||||
async with ledger.db.get_connection(
|
||||
lock_table="mint_quotes",
|
||||
lock_select_statement=f"quote='{invoice.id}'",
|
||||
lock_timeout=0.1,
|
||||
) as conn1:
|
||||
await conn1.execute(
|
||||
f"UPDATE mint_quotes SET amount=100 WHERE quote='{invoice.id}';"
|
||||
)
|
||||
try:
|
||||
async with ledger.db.get_connection(
|
||||
lock_table="mint_quotes",
|
||||
lock_select_statement=f"quote='{invoice.id}'",
|
||||
lock_timeout=0.1,
|
||||
) as conn2:
|
||||
# write something with conn1, we never reach this point if the lock works
|
||||
await conn2.execute(
|
||||
f"UPDATE mint_quotes SET amount=101 WHERE quote='{invoice.id}';"
|
||||
)
|
||||
except Exception as exc:
|
||||
# this is expected to raise
|
||||
raise Exception(f"conn2: {str(exc)}")
|
||||
except Exception as exc:
|
||||
if "conn2" in str(exc):
|
||||
raise exc
|
||||
else:
|
||||
raise Exception(f"not expected to happen: {str(exc)}")
|
||||
|
||||
await assert_err(get_connection(), "failed to acquire database lock")
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_db_set_proofs_pending_race_condition(wallet: Wallet, ledger: Ledger):
|
||||
# fill wallet
|
||||
invoice = await wallet.request_mint(64)
|
||||
await pay_if_regtest(invoice.bolt11)
|
||||
await wallet.mint(64, id=invoice.id)
|
||||
assert wallet.balance == 64
|
||||
|
||||
await assert_err_multiple(
|
||||
asyncio.gather(
|
||||
ledger.db_write._set_proofs_pending(wallet.proofs),
|
||||
ledger.db_write._set_proofs_pending(wallet.proofs),
|
||||
),
|
||||
[
|
||||
"failed to acquire database lock",
|
||||
"proofs are pending",
|
||||
], # depending on how fast the database is, it can be either
|
||||
)
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_db_set_proofs_pending_delayed_no_race_condition(
|
||||
wallet: Wallet, ledger: Ledger
|
||||
):
|
||||
# fill wallet
|
||||
invoice = await wallet.request_mint(64)
|
||||
await pay_if_regtest(invoice.bolt11)
|
||||
await wallet.mint(64, id=invoice.id)
|
||||
assert wallet.balance == 64
|
||||
|
||||
async def delayed_set_proofs_pending():
|
||||
await asyncio.sleep(0.1)
|
||||
await ledger.db_write._set_proofs_pending(wallet.proofs)
|
||||
|
||||
await assert_err(
|
||||
asyncio.gather(
|
||||
ledger.db_write._set_proofs_pending(wallet.proofs),
|
||||
delayed_set_proofs_pending(),
|
||||
),
|
||||
"proofs are pending",
|
||||
)
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_db_set_proofs_pending_no_race_condition_different_proofs(
|
||||
wallet: Wallet, ledger: Ledger
|
||||
):
|
||||
# fill wallet
|
||||
invoice = await wallet.request_mint(64)
|
||||
await pay_if_regtest(invoice.bolt11)
|
||||
await wallet.mint(64, id=invoice.id, split=[32, 32])
|
||||
assert wallet.balance == 64
|
||||
assert len(wallet.proofs) == 2
|
||||
|
||||
asyncio.gather(
|
||||
ledger.db_write._set_proofs_pending(wallet.proofs[:1]),
|
||||
ledger.db_write._set_proofs_pending(wallet.proofs[1:]),
|
||||
)
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_db_get_connection_lock_different_row(wallet: Wallet, ledger: Ledger):
|
||||
if ledger.db.type == db.SQLITE:
|
||||
pytest.skip("SQLite does not support row locking")
|
||||
# this should work since we lock two different rows
|
||||
invoice = await wallet.request_mint(64)
|
||||
invoice2 = await wallet.request_mint(64)
|
||||
|
||||
async def get_connection2():
|
||||
"""This code makes sure that only the error of the second connection is raised (which we check in the assert_err)"""
|
||||
try:
|
||||
async with ledger.db.get_connection(
|
||||
lock_table="mint_quotes",
|
||||
lock_select_statement=f"quote='{invoice.id}'",
|
||||
lock_timeout=0.1,
|
||||
):
|
||||
try:
|
||||
async with ledger.db.get_connection(
|
||||
lock_table="mint_quotes",
|
||||
lock_select_statement=f"quote='{invoice2.id}'",
|
||||
lock_timeout=0.1,
|
||||
) as conn2:
|
||||
# write something with conn1, this time we should reach this block with postgres
|
||||
quote = await ledger.crud.get_mint_quote(
|
||||
quote_id=invoice2.id, db=ledger.db, conn=conn2
|
||||
)
|
||||
assert quote is not None
|
||||
quote.amount = 100
|
||||
await ledger.crud.update_mint_quote(
|
||||
quote=quote, db=ledger.db, conn=conn2
|
||||
)
|
||||
|
||||
except Exception as exc:
|
||||
# this is expected to raise
|
||||
raise Exception(f"conn2: {str(exc)}")
|
||||
|
||||
except Exception as exc:
|
||||
if "conn2" in str(exc):
|
||||
raise exc
|
||||
else:
|
||||
raise Exception(f"not expected to happen: {str(exc)}")
|
||||
|
||||
await get_connection2()
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_db_lock_table(wallet: Wallet, ledger: Ledger):
|
||||
# fill wallet
|
||||
invoice = await wallet.request_mint(64)
|
||||
await pay_if_regtest(invoice.bolt11)
|
||||
|
||||
await wallet.mint(64, id=invoice.id)
|
||||
assert wallet.balance == 64
|
||||
|
||||
async with ledger.db.connect(lock_table="proofs_pending", lock_timeout=0.1) as conn:
|
||||
assert isinstance(conn, Connection)
|
||||
await assert_err(
|
||||
ledger.db_write._set_proofs_pending(wallet.proofs),
|
||||
"failed to acquire database lock",
|
||||
)
|
||||
|
||||
@@ -69,7 +69,7 @@ async def test_get_keyset(ledger: Ledger):
|
||||
@pytest.mark.asyncio
|
||||
async def test_mint(ledger: Ledger):
|
||||
quote = await ledger.mint_quote(PostMintQuoteRequest(amount=8, unit="sat"))
|
||||
pay_if_regtest(quote.request)
|
||||
await pay_if_regtest(quote.request)
|
||||
blinded_messages_mock = [
|
||||
BlindedMessage(
|
||||
amount=8,
|
||||
@@ -89,7 +89,7 @@ async def test_mint(ledger: Ledger):
|
||||
@pytest.mark.asyncio
|
||||
async def test_mint_invalid_blinded_message(ledger: Ledger):
|
||||
quote = await ledger.mint_quote(PostMintQuoteRequest(amount=8, unit="sat"))
|
||||
pay_if_regtest(quote.request)
|
||||
await pay_if_regtest(quote.request)
|
||||
blinded_messages_mock_invalid_key = [
|
||||
BlindedMessage(
|
||||
amount=8,
|
||||
|
||||
@@ -153,7 +153,7 @@ async def test_api_keyset_keys_old_keyset_id(ledger: Ledger):
|
||||
)
|
||||
async def test_split(ledger: Ledger, wallet: Wallet):
|
||||
invoice = await wallet.request_mint(64)
|
||||
pay_if_regtest(invoice.bolt11)
|
||||
await pay_if_regtest(invoice.bolt11)
|
||||
await wallet.mint(64, id=invoice.id)
|
||||
assert wallet.balance == 64
|
||||
secrets, rs, derivation_paths = await wallet.generate_n_secrets(2)
|
||||
@@ -162,7 +162,7 @@ async def test_split(ledger: Ledger, wallet: Wallet):
|
||||
inputs_payload = [p.to_dict() for p in wallet.proofs]
|
||||
outputs_payload = [o.dict() for o in outputs]
|
||||
payload = {"inputs": inputs_payload, "outputs": outputs_payload}
|
||||
response = httpx.post(f"{BASE_URL}/v1/swap", json=payload)
|
||||
response = httpx.post(f"{BASE_URL}/v1/swap", json=payload, timeout=None)
|
||||
assert response.status_code == 200, f"{response.url} {response.status_code}"
|
||||
result = response.json()
|
||||
assert len(result["signatures"]) == 2
|
||||
@@ -208,7 +208,7 @@ async def test_mint_quote(ledger: Ledger):
|
||||
assert result["expiry"] == expiry
|
||||
|
||||
# pay the invoice
|
||||
pay_if_regtest(result["request"])
|
||||
await pay_if_regtest(result["request"])
|
||||
|
||||
# get mint quote again from api
|
||||
response = httpx.get(
|
||||
@@ -234,7 +234,7 @@ async def test_mint_quote(ledger: Ledger):
|
||||
)
|
||||
async def test_mint(ledger: Ledger, wallet: Wallet):
|
||||
invoice = await wallet.request_mint(64)
|
||||
pay_if_regtest(invoice.bolt11)
|
||||
await pay_if_regtest(invoice.bolt11)
|
||||
quote_id = invoice.id
|
||||
secrets, rs, derivation_paths = await wallet.generate_secrets_from_to(10000, 10001)
|
||||
outputs, rs = wallet._construct_outputs([32, 32], secrets, rs)
|
||||
@@ -352,7 +352,7 @@ async def test_melt_quote_external(ledger: Ledger, wallet: Wallet):
|
||||
async def test_melt_internal(ledger: Ledger, wallet: Wallet):
|
||||
# internal invoice
|
||||
invoice = await wallet.request_mint(64)
|
||||
pay_if_regtest(invoice.bolt11)
|
||||
await pay_if_regtest(invoice.bolt11)
|
||||
await wallet.mint(64, id=invoice.id)
|
||||
assert wallet.balance == 64
|
||||
|
||||
@@ -411,7 +411,7 @@ async def test_melt_internal(ledger: Ledger, wallet: Wallet):
|
||||
async def test_melt_external(ledger: Ledger, wallet: Wallet):
|
||||
# internal invoice
|
||||
invoice = await wallet.request_mint(64)
|
||||
pay_if_regtest(invoice.bolt11)
|
||||
await pay_if_regtest(invoice.bolt11)
|
||||
await wallet.mint(64, id=invoice.id)
|
||||
assert wallet.balance == 64
|
||||
|
||||
@@ -439,6 +439,7 @@ async def test_melt_external(ledger: Ledger, wallet: Wallet):
|
||||
},
|
||||
timeout=None,
|
||||
)
|
||||
response.raise_for_status()
|
||||
assert response.status_code == 200, f"{response.url} {response.status_code}"
|
||||
result = response.json()
|
||||
assert result.get("payment_preimage") is not None
|
||||
@@ -486,7 +487,7 @@ async def test_api_check_state(ledger: Ledger):
|
||||
)
|
||||
async def test_api_restore(ledger: Ledger, wallet: Wallet):
|
||||
invoice = await wallet.request_mint(64)
|
||||
pay_if_regtest(invoice.bolt11)
|
||||
await pay_if_regtest(invoice.bolt11)
|
||||
await wallet.mint(64, id=invoice.id)
|
||||
assert wallet.balance == 64
|
||||
secret_counter = await bump_secret_derivation(
|
||||
|
||||
@@ -67,7 +67,7 @@ async def test_api_keyset_keys(ledger: Ledger):
|
||||
@pytest.mark.asyncio
|
||||
async def test_split(ledger: Ledger, wallet: Wallet):
|
||||
invoice = await wallet.request_mint(64)
|
||||
pay_if_regtest(invoice.bolt11)
|
||||
await pay_if_regtest(invoice.bolt11)
|
||||
await wallet.mint(64, id=invoice.id)
|
||||
assert wallet.balance == 64
|
||||
secrets, rs, derivation_paths = await wallet.generate_secrets_from_to(20000, 20001)
|
||||
@@ -88,7 +88,7 @@ async def test_split(ledger: Ledger, wallet: Wallet):
|
||||
@pytest.mark.asyncio
|
||||
async def test_split_deprecated_with_amount(ledger: Ledger, wallet: Wallet):
|
||||
invoice = await wallet.request_mint(64)
|
||||
pay_if_regtest(invoice.bolt11)
|
||||
await pay_if_regtest(invoice.bolt11)
|
||||
await wallet.mint(64, id=invoice.id)
|
||||
assert wallet.balance == 64
|
||||
secrets, rs, derivation_paths = await wallet.generate_secrets_from_to(80000, 80001)
|
||||
@@ -124,7 +124,7 @@ async def test_api_mint_validation(ledger):
|
||||
@pytest.mark.asyncio
|
||||
async def test_mint(ledger: Ledger, wallet: Wallet):
|
||||
invoice = await wallet.request_mint(64)
|
||||
pay_if_regtest(invoice.bolt11)
|
||||
await pay_if_regtest(invoice.bolt11)
|
||||
quote_id = invoice.id
|
||||
secrets, rs, derivation_paths = await wallet.generate_secrets_from_to(10000, 10001)
|
||||
outputs, rs = wallet._construct_outputs([32, 32], secrets, rs)
|
||||
@@ -148,9 +148,9 @@ async def test_mint(ledger: Ledger, wallet: Wallet):
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_melt_internal(ledger: Ledger, wallet: Wallet):
|
||||
# internal invoice
|
||||
# fill wallet
|
||||
invoice = await wallet.request_mint(64)
|
||||
pay_if_regtest(invoice.bolt11)
|
||||
await pay_if_regtest(invoice.bolt11)
|
||||
await wallet.mint(64, id=invoice.id)
|
||||
assert wallet.balance == 64
|
||||
|
||||
@@ -190,15 +190,13 @@ async def test_melt_internal_no_change_outputs(ledger: Ledger, wallet: Wallet):
|
||||
# Clients without NUT-08 will not send change outputs
|
||||
# internal invoice
|
||||
invoice = await wallet.request_mint(64)
|
||||
pay_if_regtest(invoice.bolt11)
|
||||
await pay_if_regtest(invoice.bolt11)
|
||||
await wallet.mint(64, id=invoice.id)
|
||||
assert wallet.balance == 64
|
||||
|
||||
# create invoice to melt to
|
||||
invoice = await wallet.request_mint(64)
|
||||
|
||||
invoice_payment_request = invoice.bolt11
|
||||
|
||||
quote = await wallet.melt_quote(invoice_payment_request)
|
||||
assert quote.amount == 64
|
||||
assert quote.fee_reserve == 0
|
||||
@@ -231,7 +229,7 @@ async def test_melt_internal_no_change_outputs(ledger: Ledger, wallet: Wallet):
|
||||
async def test_melt_external(ledger: Ledger, wallet: Wallet):
|
||||
# internal invoice
|
||||
invoice = await wallet.request_mint(64)
|
||||
pay_if_regtest(invoice.bolt11)
|
||||
await pay_if_regtest(invoice.bolt11)
|
||||
await wallet.mint(64, id=invoice.id)
|
||||
assert wallet.balance == 64
|
||||
|
||||
@@ -325,7 +323,7 @@ async def test_api_check_state(ledger: Ledger):
|
||||
@pytest.mark.asyncio
|
||||
async def test_api_restore(ledger: Ledger, wallet: Wallet):
|
||||
invoice = await wallet.request_mint(64)
|
||||
pay_if_regtest(invoice.bolt11)
|
||||
await pay_if_regtest(invoice.bolt11)
|
||||
await wallet.mint(64, id=invoice.id)
|
||||
assert wallet.balance == 64
|
||||
secret_counter = await bump_secret_derivation(
|
||||
|
||||
@@ -1,23 +1,18 @@
|
||||
import pytest
|
||||
import pytest_asyncio
|
||||
|
||||
from cashu.core.base import MeltQuoteState, MintQuoteState, ProofSpentState
|
||||
from cashu.core.models import PostMeltQuoteRequest
|
||||
from cashu.mint.ledger import Ledger
|
||||
from cashu.wallet.wallet import Wallet
|
||||
from cashu.wallet.wallet import Wallet as Wallet1
|
||||
from tests.conftest import SERVER_ENDPOINT
|
||||
from tests.helpers import is_postgres
|
||||
|
||||
|
||||
async def assert_err(f, msg):
|
||||
"""Compute f() and expect an error message 'msg'."""
|
||||
try:
|
||||
await f
|
||||
except Exception as exc:
|
||||
if msg not in str(exc.args[0]):
|
||||
raise Exception(f"Expected error: {msg}, got: {exc.args[0]}")
|
||||
return
|
||||
raise Exception(f"Expected error: {msg}, got no error")
|
||||
from tests.helpers import (
|
||||
assert_err,
|
||||
is_github_actions,
|
||||
is_postgres,
|
||||
pay_if_regtest,
|
||||
)
|
||||
|
||||
|
||||
@pytest_asyncio.fixture(scope="function")
|
||||
@@ -31,6 +26,35 @@ async def wallet1(ledger: Ledger):
|
||||
yield wallet1
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
@pytest.mark.skipif(is_github_actions, reason="GITHUB_ACTIONS")
|
||||
async def test_mint_proofs_pending(wallet1: Wallet, ledger: Ledger):
|
||||
invoice = await wallet1.request_mint(64)
|
||||
await pay_if_regtest(invoice.bolt11)
|
||||
await wallet1.mint(64, id=invoice.id)
|
||||
proofs = wallet1.proofs.copy()
|
||||
|
||||
proofs_states_before_split = await wallet1.check_proof_state(proofs)
|
||||
assert all(
|
||||
[s.state == ProofSpentState.unspent for s in proofs_states_before_split.states]
|
||||
)
|
||||
|
||||
await ledger.db_write._set_proofs_pending(proofs)
|
||||
|
||||
proof_states = await wallet1.check_proof_state(proofs)
|
||||
assert all([s.state == ProofSpentState.pending for s in proof_states.states])
|
||||
await assert_err(wallet1.split(wallet1.proofs, 20), "proofs are pending.")
|
||||
|
||||
await ledger.db_write._unset_proofs_pending(proofs)
|
||||
|
||||
await wallet1.split(proofs, 20)
|
||||
|
||||
proofs_states_after_split = await wallet1.check_proof_state(proofs)
|
||||
assert all(
|
||||
[s.state == ProofSpentState.spent for s in proofs_states_after_split.states]
|
||||
)
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_mint_quote(wallet1: Wallet, ledger: Ledger):
|
||||
invoice = await wallet1.request_mint(128)
|
||||
@@ -42,10 +66,63 @@ async def test_mint_quote(wallet1: Wallet, ledger: Ledger):
|
||||
assert quote.unit == "sat"
|
||||
assert not quote.paid
|
||||
assert quote.checking_id == invoice.payment_hash
|
||||
assert quote.paid_time is None
|
||||
# assert quote.paid_time is None
|
||||
assert quote.created_time
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_mint_quote_state_transitions(wallet1: Wallet, ledger: Ledger):
|
||||
invoice = await wallet1.request_mint(128)
|
||||
assert invoice is not None
|
||||
quote = await ledger.crud.get_mint_quote(quote_id=invoice.id, db=ledger.db)
|
||||
assert quote is not None
|
||||
assert quote.quote == invoice.id
|
||||
assert quote.state == MintQuoteState.unpaid
|
||||
|
||||
# set pending again
|
||||
async def set_state(quote, state):
|
||||
quote.state = state
|
||||
|
||||
# set pending
|
||||
await assert_err(
|
||||
set_state(quote, MintQuoteState.pending),
|
||||
"Cannot change state of an unpaid mint quote",
|
||||
)
|
||||
|
||||
# set unpaid
|
||||
await assert_err(
|
||||
set_state(quote, MintQuoteState.unpaid),
|
||||
"Cannot change state of an unpaid mint quote",
|
||||
)
|
||||
|
||||
# set paid
|
||||
quote.state = MintQuoteState.paid
|
||||
|
||||
# set unpaid
|
||||
await assert_err(
|
||||
set_state(quote, MintQuoteState.unpaid),
|
||||
"Cannot change state of a paid mint quote to unpaid.",
|
||||
)
|
||||
|
||||
# set pending
|
||||
quote.state = MintQuoteState.pending
|
||||
|
||||
# set paid again
|
||||
quote.state = MintQuoteState.paid
|
||||
|
||||
# set pending again
|
||||
quote.state = MintQuoteState.pending
|
||||
|
||||
# set issued
|
||||
quote.state = MintQuoteState.issued
|
||||
|
||||
# set pending again
|
||||
await assert_err(
|
||||
set_state(quote, MintQuoteState.pending),
|
||||
"Cannot change state of an issued mint quote.",
|
||||
)
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_get_mint_quote_by_request(wallet1: Wallet, ledger: Ledger):
|
||||
invoice = await wallet1.request_mint(128)
|
||||
@@ -56,7 +133,7 @@ async def test_get_mint_quote_by_request(wallet1: Wallet, ledger: Ledger):
|
||||
assert quote.amount == 128
|
||||
assert quote.unit == "sat"
|
||||
assert not quote.paid
|
||||
assert quote.paid_time is None
|
||||
# assert quote.paid_time is None
|
||||
assert quote.created_time
|
||||
|
||||
|
||||
@@ -74,10 +151,112 @@ async def test_melt_quote(wallet1: Wallet, ledger: Ledger):
|
||||
assert quote.unit == "sat"
|
||||
assert not quote.paid
|
||||
assert quote.checking_id == invoice.payment_hash
|
||||
assert quote.paid_time is None
|
||||
# assert quote.paid_time is None
|
||||
assert quote.created_time
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_melt_quote_set_pending(wallet1: Wallet, ledger: Ledger):
|
||||
invoice = await wallet1.request_mint(128)
|
||||
assert invoice is not None
|
||||
melt_quote = await ledger.melt_quote(
|
||||
PostMeltQuoteRequest(request=invoice.bolt11, unit="sat")
|
||||
)
|
||||
assert melt_quote is not None
|
||||
assert melt_quote.state == MeltQuoteState.unpaid.value
|
||||
quote = await ledger.crud.get_melt_quote(quote_id=melt_quote.quote, db=ledger.db)
|
||||
assert quote is not None
|
||||
assert quote.quote == melt_quote.quote
|
||||
assert quote.state == MeltQuoteState.unpaid
|
||||
previous_state = quote.state
|
||||
await ledger.db_write._set_melt_quote_pending(quote)
|
||||
quote = await ledger.crud.get_melt_quote(quote_id=melt_quote.quote, db=ledger.db)
|
||||
assert quote is not None
|
||||
assert quote.state == MeltQuoteState.pending
|
||||
|
||||
# set unpending
|
||||
await ledger.db_write._unset_melt_quote_pending(quote, previous_state)
|
||||
quote = await ledger.crud.get_melt_quote(quote_id=melt_quote.quote, db=ledger.db)
|
||||
assert quote is not None
|
||||
assert quote.state == previous_state
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_melt_quote_state_transitions(wallet1: Wallet, ledger: Ledger):
|
||||
invoice = await wallet1.request_mint(128)
|
||||
assert invoice is not None
|
||||
melt_quote = await ledger.melt_quote(
|
||||
PostMeltQuoteRequest(request=invoice.bolt11, unit="sat")
|
||||
)
|
||||
quote = await ledger.crud.get_melt_quote(quote_id=melt_quote.quote, db=ledger.db)
|
||||
assert quote is not None
|
||||
assert quote.quote == melt_quote.quote
|
||||
assert quote.state == MeltQuoteState.unpaid
|
||||
|
||||
# set pending
|
||||
quote.state = MeltQuoteState.pending
|
||||
|
||||
# set unpaid
|
||||
quote.state = MeltQuoteState.unpaid
|
||||
|
||||
# set paid
|
||||
quote.state = MeltQuoteState.paid
|
||||
|
||||
# set pending again
|
||||
async def set_state(quote, state):
|
||||
quote.state = state
|
||||
|
||||
await assert_err(
|
||||
set_state(quote, MeltQuoteState.pending),
|
||||
"Cannot change state of a paid melt quote.",
|
||||
)
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_mint_quote_set_pending(wallet1: Wallet, ledger: Ledger):
|
||||
invoice = await wallet1.request_mint(128)
|
||||
assert invoice is not None
|
||||
quote = await ledger.crud.get_mint_quote(quote_id=invoice.id, db=ledger.db)
|
||||
assert quote is not None
|
||||
assert quote.state == MintQuoteState.unpaid
|
||||
|
||||
# pay_if_regtest pays on regtest, get_mint_quote pays on FakeWallet
|
||||
await pay_if_regtest(invoice.bolt11)
|
||||
_ = await ledger.get_mint_quote(invoice.id)
|
||||
|
||||
quote = await ledger.crud.get_mint_quote(quote_id=invoice.id, db=ledger.db)
|
||||
assert quote is not None
|
||||
assert quote.state == MintQuoteState.paid
|
||||
|
||||
previous_state = MintQuoteState.paid
|
||||
await ledger.db_write._set_mint_quote_pending(quote.quote)
|
||||
quote = await ledger.crud.get_mint_quote(quote_id=invoice.id, db=ledger.db)
|
||||
assert quote is not None
|
||||
assert quote.state == MintQuoteState.pending
|
||||
|
||||
# try to mint while pending
|
||||
await assert_err(wallet1.mint(128, id=invoice.id), "Mint quote already pending.")
|
||||
|
||||
# set unpending
|
||||
await ledger.db_write._unset_mint_quote_pending(quote.quote, previous_state)
|
||||
|
||||
quote = await ledger.crud.get_mint_quote(quote_id=invoice.id, db=ledger.db)
|
||||
assert quote is not None
|
||||
assert quote.state == previous_state
|
||||
assert quote.state == MintQuoteState.paid
|
||||
|
||||
# # set paid and mint again
|
||||
# quote.state = MintQuoteState.paid
|
||||
# await ledger.crud.update_mint_quote(quote=quote, db=ledger.db)
|
||||
|
||||
await wallet1.mint(quote.amount, id=quote.quote)
|
||||
|
||||
# check if quote is issued
|
||||
quote = await ledger.crud.get_mint_quote(quote_id=invoice.id, db=ledger.db)
|
||||
assert quote is not None
|
||||
assert quote.state == MintQuoteState.issued
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
@pytest.mark.skipif(not is_postgres, reason="only works with Postgres")
|
||||
async def test_postgres_working():
|
||||
|
||||
@@ -49,7 +49,7 @@ def set_ledger_keyset_fees(
|
||||
@pytest.mark.asyncio
|
||||
async def test_get_fees_for_proofs(wallet1: Wallet, ledger: Ledger):
|
||||
invoice = await wallet1.request_mint(64)
|
||||
pay_if_regtest(invoice.bolt11)
|
||||
await pay_if_regtest(invoice.bolt11)
|
||||
await wallet1.mint(64, split=[1] * 64, id=invoice.id)
|
||||
|
||||
# two proofs
|
||||
@@ -115,7 +115,7 @@ async def test_split_with_fees(wallet1: Wallet, ledger: Ledger):
|
||||
# set fees to 100 ppk
|
||||
set_ledger_keyset_fees(100, ledger)
|
||||
invoice = await wallet1.request_mint(64)
|
||||
pay_if_regtest(invoice.bolt11)
|
||||
await pay_if_regtest(invoice.bolt11)
|
||||
await wallet1.mint(64, id=invoice.id)
|
||||
|
||||
send_proofs, _ = await wallet1.select_to_send(wallet1.proofs, 10)
|
||||
@@ -133,7 +133,7 @@ async def test_split_with_high_fees(wallet1: Wallet, ledger: Ledger):
|
||||
# set fees to 100 ppk
|
||||
set_ledger_keyset_fees(1234, ledger)
|
||||
invoice = await wallet1.request_mint(64)
|
||||
pay_if_regtest(invoice.bolt11)
|
||||
await pay_if_regtest(invoice.bolt11)
|
||||
await wallet1.mint(64, id=invoice.id)
|
||||
|
||||
send_proofs, _ = await wallet1.select_to_send(wallet1.proofs, 10)
|
||||
@@ -151,7 +151,7 @@ async def test_split_not_enough_fees(wallet1: Wallet, ledger: Ledger):
|
||||
# set fees to 100 ppk
|
||||
set_ledger_keyset_fees(100, ledger)
|
||||
invoice = await wallet1.request_mint(64)
|
||||
pay_if_regtest(invoice.bolt11)
|
||||
await pay_if_regtest(invoice.bolt11)
|
||||
await wallet1.mint(64, id=invoice.id)
|
||||
|
||||
send_proofs, _ = await wallet1.select_to_send(wallet1.proofs, 10)
|
||||
@@ -173,6 +173,7 @@ async def test_melt_internal(wallet1: Wallet, ledger: Ledger):
|
||||
|
||||
# mint twice so we have enough to pay the second invoice back
|
||||
invoice = await wallet1.request_mint(128)
|
||||
await pay_if_regtest(invoice.bolt11)
|
||||
await wallet1.mint(128, id=invoice.id)
|
||||
assert wallet1.balance == 128
|
||||
|
||||
@@ -217,7 +218,7 @@ async def test_melt_external_with_fees(wallet1: Wallet, ledger: Ledger):
|
||||
|
||||
# mint twice so we have enough to pay the second invoice back
|
||||
invoice = await wallet1.request_mint(128)
|
||||
pay_if_regtest(invoice.bolt11)
|
||||
await pay_if_regtest(invoice.bolt11)
|
||||
await wallet1.mint(128, id=invoice.id)
|
||||
assert wallet1.balance == 128
|
||||
|
||||
|
||||
@@ -241,7 +241,7 @@ async def test_startup_fakewallet_pending_quote_pending(ledger: Ledger):
|
||||
async def test_startup_regtest_pending_quote_pending(wallet: Wallet, ledger: Ledger):
|
||||
# fill wallet
|
||||
invoice = await wallet.request_mint(64)
|
||||
pay_if_regtest(invoice.bolt11)
|
||||
await pay_if_regtest(invoice.bolt11)
|
||||
await wallet.mint(64, id=invoice.id)
|
||||
assert wallet.balance == 64
|
||||
|
||||
@@ -286,7 +286,7 @@ async def test_startup_regtest_pending_quote_pending(wallet: Wallet, ledger: Led
|
||||
async def test_startup_regtest_pending_quote_success(wallet: Wallet, ledger: Ledger):
|
||||
# fill wallet
|
||||
invoice = await wallet.request_mint(64)
|
||||
pay_if_regtest(invoice.bolt11)
|
||||
await pay_if_regtest(invoice.bolt11)
|
||||
await wallet.mint(64, id=invoice.id)
|
||||
assert wallet.balance == 64
|
||||
|
||||
@@ -334,7 +334,7 @@ async def test_startup_regtest_pending_quote_failure(wallet: Wallet, ledger: Led
|
||||
"""Simulate a failure to pay the hodl invoice by canceling it."""
|
||||
# fill wallet
|
||||
invoice = await wallet.request_mint(64)
|
||||
pay_if_regtest(invoice.bolt11)
|
||||
await pay_if_regtest(invoice.bolt11)
|
||||
await wallet.mint(64, id=invoice.id)
|
||||
assert wallet.balance == 64
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import pytest
|
||||
import pytest_asyncio
|
||||
|
||||
from cashu.core.base import MeltQuoteState, MintQuoteState
|
||||
from cashu.core.helpers import sum_proofs
|
||||
from cashu.core.models import PostMeltQuoteRequest, PostMintQuoteRequest
|
||||
from cashu.mint.ledger import Ledger
|
||||
@@ -37,7 +38,9 @@ async def wallet1(ledger: Ledger):
|
||||
async def test_melt_internal(wallet1: Wallet, ledger: Ledger):
|
||||
# mint twice so we have enough to pay the second invoice back
|
||||
invoice = await wallet1.request_mint(128)
|
||||
await pay_if_regtest(invoice.bolt11)
|
||||
await wallet1.mint(128, id=invoice.id)
|
||||
await pay_if_regtest(invoice.bolt11)
|
||||
assert wallet1.balance == 128
|
||||
|
||||
# create a mint quote so that we can melt to it internally
|
||||
@@ -48,17 +51,21 @@ async def test_melt_internal(wallet1: Wallet, ledger: Ledger):
|
||||
PostMeltQuoteRequest(request=invoice_payment_request, unit="sat")
|
||||
)
|
||||
assert not melt_quote.paid
|
||||
assert melt_quote.state == MeltQuoteState.unpaid.value
|
||||
|
||||
assert melt_quote.amount == 64
|
||||
assert melt_quote.fee_reserve == 0
|
||||
|
||||
melt_quote_pre_payment = await ledger.get_melt_quote(melt_quote.quote)
|
||||
assert not melt_quote_pre_payment.paid, "melt quote should not be paid"
|
||||
assert melt_quote_pre_payment.state == MeltQuoteState.unpaid
|
||||
|
||||
keep_proofs, send_proofs = await wallet1.split_to_send(wallet1.proofs, 64)
|
||||
await ledger.melt(proofs=send_proofs, quote=melt_quote.quote)
|
||||
|
||||
melt_quote_post_payment = await ledger.get_melt_quote(melt_quote.quote)
|
||||
assert melt_quote_post_payment.paid, "melt quote should be paid"
|
||||
assert melt_quote_post_payment.state == MeltQuoteState.paid
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
@@ -66,7 +73,7 @@ async def test_melt_internal(wallet1: Wallet, ledger: Ledger):
|
||||
async def test_melt_external(wallet1: Wallet, ledger: Ledger):
|
||||
# mint twice so we have enough to pay the second invoice back
|
||||
invoice = await wallet1.request_mint(128)
|
||||
pay_if_regtest(invoice.bolt11)
|
||||
await pay_if_regtest(invoice.bolt11)
|
||||
await wallet1.mint(128, id=invoice.id)
|
||||
assert wallet1.balance == 128
|
||||
|
||||
@@ -74,6 +81,9 @@ async def test_melt_external(wallet1: Wallet, ledger: Ledger):
|
||||
invoice_payment_request = invoice_dict["payment_request"]
|
||||
|
||||
mint_quote = await wallet1.melt_quote(invoice_payment_request)
|
||||
assert not mint_quote.paid, "mint quote should not be paid"
|
||||
assert mint_quote.state == MeltQuoteState.unpaid.value
|
||||
|
||||
total_amount = mint_quote.amount + mint_quote.fee_reserve
|
||||
keep_proofs, send_proofs = await wallet1.split_to_send(wallet1.proofs, total_amount)
|
||||
melt_quote = await ledger.melt_quote(
|
||||
@@ -82,22 +92,25 @@ async def test_melt_external(wallet1: Wallet, ledger: Ledger):
|
||||
|
||||
melt_quote_pre_payment = await ledger.get_melt_quote(melt_quote.quote)
|
||||
assert not melt_quote_pre_payment.paid, "melt quote should not be paid"
|
||||
assert melt_quote_pre_payment.state == MeltQuoteState.unpaid
|
||||
|
||||
assert not melt_quote.paid, "melt quote should not be paid"
|
||||
await ledger.melt(proofs=send_proofs, quote=melt_quote.quote)
|
||||
|
||||
melt_quote_post_payment = await ledger.get_melt_quote(melt_quote.quote)
|
||||
assert melt_quote_post_payment.paid, "melt quote should be paid"
|
||||
assert melt_quote_post_payment.state == MeltQuoteState.paid
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
@pytest.mark.skipif(is_regtest, reason="only works with FakeWallet")
|
||||
async def test_mint_internal(wallet1: Wallet, ledger: Ledger):
|
||||
invoice = await wallet1.request_mint(128)
|
||||
|
||||
await pay_if_regtest(invoice.bolt11)
|
||||
mint_quote = await ledger.get_mint_quote(invoice.id)
|
||||
|
||||
assert mint_quote.paid, "mint quote should be paid"
|
||||
assert mint_quote.state == MintQuoteState.paid
|
||||
|
||||
output_amounts = [128]
|
||||
secrets, rs, derivation_paths = await wallet1.generate_n_secrets(
|
||||
@@ -111,24 +124,32 @@ async def test_mint_internal(wallet1: Wallet, ledger: Ledger):
|
||||
"outputs have already been signed before.",
|
||||
)
|
||||
|
||||
mint_quote_after_payment = await ledger.get_mint_quote(invoice.id)
|
||||
assert mint_quote_after_payment.paid, "mint quote should be paid"
|
||||
assert mint_quote_after_payment.state == MintQuoteState.issued
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
@pytest.mark.skipif(is_fake, reason="only works with Regtest")
|
||||
async def test_mint_external(wallet1: Wallet, ledger: Ledger):
|
||||
quote = await ledger.mint_quote(PostMintQuoteRequest(amount=128, unit="sat"))
|
||||
assert not quote.paid, "mint quote should not be paid"
|
||||
assert quote.state == MintQuoteState.unpaid
|
||||
|
||||
mint_quote = await ledger.get_mint_quote(quote.quote)
|
||||
assert not mint_quote.paid, "mint quote already paid"
|
||||
assert mint_quote.state == MintQuoteState.unpaid
|
||||
|
||||
await assert_err(
|
||||
wallet1.mint(128, id=quote.quote),
|
||||
"quote not paid",
|
||||
)
|
||||
|
||||
pay_if_regtest(quote.request)
|
||||
await pay_if_regtest(quote.request)
|
||||
|
||||
mint_quote = await ledger.get_mint_quote(quote.quote)
|
||||
assert mint_quote.paid, "mint quote should be paid"
|
||||
assert mint_quote.state == MintQuoteState.paid
|
||||
|
||||
output_amounts = [128]
|
||||
secrets, rs, derivation_paths = await wallet1.generate_n_secrets(
|
||||
@@ -137,11 +158,15 @@ async def test_mint_external(wallet1: Wallet, ledger: Ledger):
|
||||
outputs, rs = wallet1._construct_outputs(output_amounts, secrets, rs)
|
||||
await ledger.mint(outputs=outputs, quote_id=quote.quote)
|
||||
|
||||
mint_quote_after_payment = await ledger.get_mint_quote(quote.quote)
|
||||
assert mint_quote_after_payment.paid, "mint quote should be paid"
|
||||
assert mint_quote_after_payment.state == MintQuoteState.issued
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_split(wallet1: Wallet, ledger: Ledger):
|
||||
invoice = await wallet1.request_mint(64)
|
||||
pay_if_regtest(invoice.bolt11)
|
||||
await pay_if_regtest(invoice.bolt11)
|
||||
await wallet1.mint(64, id=invoice.id)
|
||||
|
||||
keep_proofs, send_proofs = await wallet1.split_to_send(wallet1.proofs, 10)
|
||||
@@ -158,7 +183,7 @@ async def test_split(wallet1: Wallet, ledger: Ledger):
|
||||
@pytest.mark.asyncio
|
||||
async def test_split_with_no_outputs(wallet1: Wallet, ledger: Ledger):
|
||||
invoice = await wallet1.request_mint(64)
|
||||
pay_if_regtest(invoice.bolt11)
|
||||
await pay_if_regtest(invoice.bolt11)
|
||||
await wallet1.mint(64, id=invoice.id)
|
||||
_, send_proofs = await wallet1.split_to_send(wallet1.proofs, 10, set_reserved=False)
|
||||
await assert_err(
|
||||
@@ -170,7 +195,7 @@ async def test_split_with_no_outputs(wallet1: Wallet, ledger: Ledger):
|
||||
@pytest.mark.asyncio
|
||||
async def test_split_with_input_less_than_outputs(wallet1: Wallet, ledger: Ledger):
|
||||
invoice = await wallet1.request_mint(64)
|
||||
pay_if_regtest(invoice.bolt11)
|
||||
await pay_if_regtest(invoice.bolt11)
|
||||
await wallet1.mint(64, id=invoice.id)
|
||||
|
||||
keep_proofs, send_proofs = await wallet1.split_to_send(
|
||||
@@ -199,7 +224,7 @@ async def test_split_with_input_less_than_outputs(wallet1: Wallet, ledger: Ledge
|
||||
@pytest.mark.asyncio
|
||||
async def test_split_with_input_more_than_outputs(wallet1: Wallet, ledger: Ledger):
|
||||
invoice = await wallet1.request_mint(128)
|
||||
pay_if_regtest(invoice.bolt11)
|
||||
await pay_if_regtest(invoice.bolt11)
|
||||
await wallet1.mint(128, id=invoice.id)
|
||||
|
||||
inputs = wallet1.proofs
|
||||
@@ -223,7 +248,7 @@ async def test_split_with_input_more_than_outputs(wallet1: Wallet, ledger: Ledge
|
||||
@pytest.mark.asyncio
|
||||
async def test_split_twice_with_same_outputs(wallet1: Wallet, ledger: Ledger):
|
||||
invoice = await wallet1.request_mint(128)
|
||||
pay_if_regtest(invoice.bolt11)
|
||||
await pay_if_regtest(invoice.bolt11)
|
||||
await wallet1.mint(128, split=[64, 64], id=invoice.id)
|
||||
inputs1 = wallet1.proofs[:1]
|
||||
inputs2 = wallet1.proofs[1:]
|
||||
@@ -258,7 +283,7 @@ async def test_split_twice_with_same_outputs(wallet1: Wallet, ledger: Ledger):
|
||||
@pytest.mark.asyncio
|
||||
async def test_mint_with_same_outputs_twice(wallet1: Wallet, ledger: Ledger):
|
||||
invoice = await wallet1.request_mint(128)
|
||||
pay_if_regtest(invoice.bolt11)
|
||||
await pay_if_regtest(invoice.bolt11)
|
||||
output_amounts = [128]
|
||||
secrets, rs, derivation_paths = await wallet1.generate_n_secrets(
|
||||
len(output_amounts)
|
||||
@@ -268,7 +293,7 @@ async def test_mint_with_same_outputs_twice(wallet1: Wallet, ledger: Ledger):
|
||||
|
||||
# now try to mint with the same outputs again
|
||||
invoice2 = await wallet1.request_mint(128)
|
||||
pay_if_regtest(invoice2.bolt11)
|
||||
await pay_if_regtest(invoice2.bolt11)
|
||||
|
||||
await assert_err(
|
||||
ledger.mint(outputs=outputs, quote_id=invoice2.id),
|
||||
@@ -279,7 +304,7 @@ async def test_mint_with_same_outputs_twice(wallet1: Wallet, ledger: Ledger):
|
||||
@pytest.mark.asyncio
|
||||
async def test_melt_with_same_outputs_twice(wallet1: Wallet, ledger: Ledger):
|
||||
invoice = await wallet1.request_mint(130)
|
||||
pay_if_regtest(invoice.bolt11)
|
||||
await pay_if_regtest(invoice.bolt11)
|
||||
await wallet1.mint(130, id=invoice.id)
|
||||
|
||||
output_amounts = [128]
|
||||
@@ -290,7 +315,7 @@ async def test_melt_with_same_outputs_twice(wallet1: Wallet, ledger: Ledger):
|
||||
|
||||
# we use the outputs once for minting
|
||||
invoice2 = await wallet1.request_mint(128)
|
||||
pay_if_regtest(invoice2.bolt11)
|
||||
await pay_if_regtest(invoice2.bolt11)
|
||||
await ledger.mint(outputs=outputs, quote_id=invoice2.id)
|
||||
|
||||
# use the same outputs for melting
|
||||
@@ -307,7 +332,7 @@ async def test_melt_with_same_outputs_twice(wallet1: Wallet, ledger: Ledger):
|
||||
@pytest.mark.asyncio
|
||||
async def test_melt_with_less_inputs_than_invoice(wallet1: Wallet, ledger: Ledger):
|
||||
invoice = await wallet1.request_mint(32)
|
||||
pay_if_regtest(invoice.bolt11)
|
||||
await pay_if_regtest(invoice.bolt11)
|
||||
await wallet1.mint(32, id=invoice.id)
|
||||
|
||||
# outputs for fee return
|
||||
@@ -336,7 +361,7 @@ async def test_melt_with_less_inputs_than_invoice(wallet1: Wallet, ledger: Ledge
|
||||
@pytest.mark.asyncio
|
||||
async def test_melt_with_more_inputs_than_invoice(wallet1: Wallet, ledger: Ledger):
|
||||
invoice = await wallet1.request_mint(130)
|
||||
pay_if_regtest(invoice.bolt11)
|
||||
await pay_if_regtest(invoice.bolt11)
|
||||
await wallet1.mint(130, split=[64, 64, 2], id=invoice.id)
|
||||
|
||||
# outputs for fee return
|
||||
@@ -368,7 +393,7 @@ async def test_melt_with_more_inputs_than_invoice(wallet1: Wallet, ledger: Ledge
|
||||
@pytest.mark.asyncio
|
||||
async def test_check_proof_state(wallet1: Wallet, ledger: Ledger):
|
||||
invoice = await wallet1.request_mint(64)
|
||||
pay_if_regtest(invoice.bolt11)
|
||||
await pay_if_regtest(invoice.bolt11)
|
||||
await wallet1.mint(64, id=invoice.id)
|
||||
|
||||
keep_proofs, send_proofs = await wallet1.split_to_send(wallet1.proofs, 10)
|
||||
@@ -385,7 +410,7 @@ async def test_check_proof_state(wallet1: Wallet, ledger: Ledger):
|
||||
# f"ws://localhost:{SERVER_PORT}/v1/quote/{invoice.id}"
|
||||
# )
|
||||
# await asyncio.sleep(0.1)
|
||||
# pay_if_regtest(invoice.bolt11)
|
||||
# await pay_if_regtest(invoice.bolt11)
|
||||
# await wallet1.mint(64, id=invoice.id)
|
||||
# await asyncio.sleep(0.1)
|
||||
# data = str(ws.recv())
|
||||
|
||||
@@ -32,7 +32,7 @@ async def wallet():
|
||||
async def test_regtest_pending_quote(wallet: Wallet, ledger: Ledger):
|
||||
# fill wallet
|
||||
invoice = await wallet.request_mint(64)
|
||||
pay_if_regtest(invoice.bolt11)
|
||||
await pay_if_regtest(invoice.bolt11)
|
||||
await wallet.mint(64, id=invoice.id)
|
||||
assert wallet.balance == 64
|
||||
|
||||
|
||||
@@ -40,6 +40,18 @@ async def assert_err(f, msg: Union[str, CashuError]):
|
||||
raise Exception(f"Expected error: {msg}, got no error")
|
||||
|
||||
|
||||
async def assert_err_multiple(f, msgs: List[str]):
|
||||
"""Compute f() and expect an error message 'msg'."""
|
||||
try:
|
||||
await f
|
||||
except Exception as exc:
|
||||
for msg in msgs:
|
||||
if msg in str(exc.args[0]):
|
||||
return
|
||||
raise Exception(f"Expected error: {msgs}, got: {exc.args[0]}")
|
||||
raise Exception(f"Expected error: {msgs}, got no error")
|
||||
|
||||
|
||||
def assert_amt(proofs: List[Proof], expected: int):
|
||||
"""Assert amounts the proofs contain."""
|
||||
assert sum([p.amount for p in proofs]) == expected
|
||||
@@ -155,7 +167,7 @@ async def test_request_mint(wallet1: Wallet):
|
||||
@pytest.mark.asyncio
|
||||
async def test_mint(wallet1: Wallet):
|
||||
invoice = await wallet1.request_mint(64)
|
||||
pay_if_regtest(invoice.bolt11)
|
||||
await pay_if_regtest(invoice.bolt11)
|
||||
expected_proof_amounts = wallet1.split_wallet_state(64)
|
||||
await wallet1.mint(64, id=invoice.id)
|
||||
assert wallet1.balance == 64
|
||||
@@ -179,7 +191,7 @@ async def test_mint_amounts(wallet1: Wallet):
|
||||
"""Mint predefined amounts"""
|
||||
amts = [1, 1, 1, 2, 2, 4, 16]
|
||||
invoice = await wallet1.request_mint(sum(amts))
|
||||
pay_if_regtest(invoice.bolt11)
|
||||
await pay_if_regtest(invoice.bolt11)
|
||||
await wallet1.mint(amount=sum(amts), split=amts, id=invoice.id)
|
||||
assert wallet1.balance == 27
|
||||
assert wallet1.proof_amounts == amts
|
||||
@@ -211,7 +223,7 @@ async def test_mint_amounts_wrong_order(wallet1: Wallet):
|
||||
@pytest.mark.asyncio
|
||||
async def test_split(wallet1: Wallet):
|
||||
invoice = await wallet1.request_mint(64)
|
||||
pay_if_regtest(invoice.bolt11)
|
||||
await pay_if_regtest(invoice.bolt11)
|
||||
await wallet1.mint(64, id=invoice.id)
|
||||
assert wallet1.balance == 64
|
||||
# the outputs we keep that we expect after the split
|
||||
@@ -231,7 +243,7 @@ async def test_split(wallet1: Wallet):
|
||||
@pytest.mark.asyncio
|
||||
async def test_split_to_send(wallet1: Wallet):
|
||||
invoice = await wallet1.request_mint(64)
|
||||
pay_if_regtest(invoice.bolt11)
|
||||
await pay_if_regtest(invoice.bolt11)
|
||||
await wallet1.mint(64, id=invoice.id)
|
||||
assert wallet1.balance == 64
|
||||
|
||||
@@ -253,7 +265,7 @@ async def test_split_to_send(wallet1: Wallet):
|
||||
@pytest.mark.asyncio
|
||||
async def test_split_more_than_balance(wallet1: Wallet):
|
||||
invoice = await wallet1.request_mint(64)
|
||||
pay_if_regtest(invoice.bolt11)
|
||||
await pay_if_regtest(invoice.bolt11)
|
||||
await wallet1.mint(64, id=invoice.id)
|
||||
await assert_err(
|
||||
wallet1.split(wallet1.proofs, 128),
|
||||
@@ -267,7 +279,7 @@ async def test_split_more_than_balance(wallet1: Wallet):
|
||||
async def test_melt(wallet1: Wallet):
|
||||
# mint twice so we have enough to pay the second invoice back
|
||||
topup_invoice = await wallet1.request_mint(128)
|
||||
pay_if_regtest(topup_invoice.bolt11)
|
||||
await pay_if_regtest(topup_invoice.bolt11)
|
||||
await wallet1.mint(128, id=topup_invoice.id)
|
||||
assert wallet1.balance == 128
|
||||
|
||||
@@ -333,7 +345,7 @@ async def test_melt(wallet1: Wallet):
|
||||
@pytest.mark.asyncio
|
||||
async def test_split_to_send_more_than_balance(wallet1: Wallet):
|
||||
invoice = await wallet1.request_mint(64)
|
||||
pay_if_regtest(invoice.bolt11)
|
||||
await pay_if_regtest(invoice.bolt11)
|
||||
await wallet1.mint(64, id=invoice.id)
|
||||
await assert_err(
|
||||
wallet1.split_to_send(wallet1.proofs, 128, set_reserved=True),
|
||||
@@ -346,7 +358,7 @@ async def test_split_to_send_more_than_balance(wallet1: Wallet):
|
||||
@pytest.mark.asyncio
|
||||
async def test_double_spend(wallet1: Wallet):
|
||||
invoice = await wallet1.request_mint(64)
|
||||
pay_if_regtest(invoice.bolt11)
|
||||
await pay_if_regtest(invoice.bolt11)
|
||||
doublespend = await wallet1.mint(64, id=invoice.id)
|
||||
await wallet1.split(wallet1.proofs, 20)
|
||||
await assert_err(
|
||||
@@ -360,7 +372,7 @@ async def test_double_spend(wallet1: Wallet):
|
||||
@pytest.mark.asyncio
|
||||
async def test_duplicate_proofs_double_spent(wallet1: Wallet):
|
||||
invoice = await wallet1.request_mint(64)
|
||||
pay_if_regtest(invoice.bolt11)
|
||||
await pay_if_regtest(invoice.bolt11)
|
||||
doublespend = await wallet1.mint(64, id=invoice.id)
|
||||
await assert_err(
|
||||
wallet1.split(wallet1.proofs + doublespend, 20),
|
||||
@@ -374,24 +386,24 @@ async def test_duplicate_proofs_double_spent(wallet1: Wallet):
|
||||
@pytest.mark.skipif(is_github_actions, reason="GITHUB_ACTIONS")
|
||||
async def test_split_race_condition(wallet1: Wallet):
|
||||
invoice = await wallet1.request_mint(64)
|
||||
pay_if_regtest(invoice.bolt11)
|
||||
await pay_if_regtest(invoice.bolt11)
|
||||
await wallet1.mint(64, id=invoice.id)
|
||||
# run two splits in parallel
|
||||
import asyncio
|
||||
|
||||
await assert_err(
|
||||
await assert_err_multiple(
|
||||
asyncio.gather(
|
||||
wallet1.split(wallet1.proofs, 20),
|
||||
wallet1.split(wallet1.proofs, 20),
|
||||
),
|
||||
"proofs are pending.",
|
||||
["proofs are pending.", "already spent."],
|
||||
)
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_send_and_redeem(wallet1: Wallet, wallet2: Wallet):
|
||||
invoice = await wallet1.request_mint(64)
|
||||
pay_if_regtest(invoice.bolt11)
|
||||
await pay_if_regtest(invoice.bolt11)
|
||||
await wallet1.mint(64, id=invoice.id)
|
||||
_, spendable_proofs = await wallet1.split_to_send(
|
||||
wallet1.proofs, 32, set_reserved=True
|
||||
@@ -410,7 +422,7 @@ async def test_send_and_redeem(wallet1: Wallet, wallet2: Wallet):
|
||||
async def test_invalidate_all_proofs(wallet1: Wallet):
|
||||
"""Try to invalidate proofs that have not been spent yet. Should not work!"""
|
||||
invoice = await wallet1.request_mint(64)
|
||||
pay_if_regtest(invoice.bolt11)
|
||||
await pay_if_regtest(invoice.bolt11)
|
||||
await wallet1.mint(64, id=invoice.id)
|
||||
await wallet1.invalidate(wallet1.proofs)
|
||||
assert wallet1.balance == 0
|
||||
@@ -420,7 +432,7 @@ async def test_invalidate_all_proofs(wallet1: Wallet):
|
||||
async def test_invalidate_unspent_proofs_with_checking(wallet1: Wallet):
|
||||
"""Try to invalidate proofs that have not been spent yet but force no check."""
|
||||
invoice = await wallet1.request_mint(64)
|
||||
pay_if_regtest(invoice.bolt11)
|
||||
await pay_if_regtest(invoice.bolt11)
|
||||
await wallet1.mint(64, id=invoice.id)
|
||||
await wallet1.invalidate(wallet1.proofs, check_spendable=True)
|
||||
assert wallet1.balance == 64
|
||||
@@ -429,7 +441,7 @@ async def test_invalidate_unspent_proofs_with_checking(wallet1: Wallet):
|
||||
@pytest.mark.asyncio
|
||||
async def test_split_invalid_amount(wallet1: Wallet):
|
||||
invoice = await wallet1.request_mint(64)
|
||||
pay_if_regtest(invoice.bolt11)
|
||||
await pay_if_regtest(invoice.bolt11)
|
||||
await wallet1.mint(64, id=invoice.id)
|
||||
await assert_err(
|
||||
wallet1.split(wallet1.proofs, -1),
|
||||
@@ -440,7 +452,7 @@ async def test_split_invalid_amount(wallet1: Wallet):
|
||||
@pytest.mark.asyncio
|
||||
async def test_token_state(wallet1: Wallet):
|
||||
invoice = await wallet1.request_mint(64)
|
||||
pay_if_regtest(invoice.bolt11)
|
||||
await pay_if_regtest(invoice.bolt11)
|
||||
await wallet1.mint(64, id=invoice.id)
|
||||
assert wallet1.balance == 64
|
||||
resp = await wallet1.check_proof_state(wallet1.proofs)
|
||||
|
||||
@@ -117,7 +117,7 @@ def test_invoice_return_immediately(mint, cli_prefix):
|
||||
assert result.exception is None
|
||||
|
||||
invoice, invoice_id = get_bolt11_and_invoice_id_from_invoice_command(result.output)
|
||||
pay_if_regtest(invoice)
|
||||
asyncio.run(pay_if_regtest(invoice))
|
||||
|
||||
result = runner.invoke(
|
||||
cli,
|
||||
@@ -146,7 +146,7 @@ def test_invoice_with_split(mint, cli_prefix):
|
||||
assert result.exception is None
|
||||
|
||||
invoice, invoice_id = get_bolt11_and_invoice_id_from_invoice_command(result.output)
|
||||
pay_if_regtest(invoice)
|
||||
asyncio.run(pay_if_regtest(invoice))
|
||||
result = runner.invoke(
|
||||
cli,
|
||||
[*cli_prefix, "invoice", "10", "-s", "1", "--id", invoice_id],
|
||||
@@ -164,7 +164,7 @@ def test_invoices_with_minting(cli_prefix):
|
||||
wallet1 = asyncio.run(init_wallet())
|
||||
asyncio.run(reset_invoices(wallet=wallet1))
|
||||
invoice = asyncio.run(wallet1.request_mint(64))
|
||||
|
||||
asyncio.run(pay_if_regtest(invoice.bolt11))
|
||||
# act
|
||||
runner = CliRunner()
|
||||
result = runner.invoke(
|
||||
|
||||
@@ -58,7 +58,7 @@ async def wallet2():
|
||||
@pytest.mark.asyncio
|
||||
async def test_create_htlc_secret(wallet1: Wallet):
|
||||
invoice = await wallet1.request_mint(64)
|
||||
pay_if_regtest(invoice.bolt11)
|
||||
await pay_if_regtest(invoice.bolt11)
|
||||
await wallet1.mint(64, id=invoice.id)
|
||||
preimage = "00000000000000000000000000000000"
|
||||
preimage_hash = hashlib.sha256(bytes.fromhex(preimage)).hexdigest()
|
||||
@@ -69,7 +69,7 @@ async def test_create_htlc_secret(wallet1: Wallet):
|
||||
@pytest.mark.asyncio
|
||||
async def test_htlc_split(wallet1: Wallet, wallet2: Wallet):
|
||||
invoice = await wallet1.request_mint(64)
|
||||
pay_if_regtest(invoice.bolt11)
|
||||
await pay_if_regtest(invoice.bolt11)
|
||||
await wallet1.mint(64, id=invoice.id)
|
||||
preimage = "00000000000000000000000000000000"
|
||||
preimage_hash = hashlib.sha256(bytes.fromhex(preimage)).hexdigest()
|
||||
@@ -82,7 +82,7 @@ async def test_htlc_split(wallet1: Wallet, wallet2: Wallet):
|
||||
@pytest.mark.asyncio
|
||||
async def test_htlc_redeem_with_preimage(wallet1: Wallet, wallet2: Wallet):
|
||||
invoice = await wallet1.request_mint(64)
|
||||
pay_if_regtest(invoice.bolt11)
|
||||
await pay_if_regtest(invoice.bolt11)
|
||||
await wallet1.mint(64, id=invoice.id)
|
||||
preimage = "00000000000000000000000000000000"
|
||||
# preimage_hash = hashlib.sha256(bytes.fromhex(preimage)).hexdigest()
|
||||
@@ -96,7 +96,7 @@ async def test_htlc_redeem_with_preimage(wallet1: Wallet, wallet2: Wallet):
|
||||
@pytest.mark.asyncio
|
||||
async def test_htlc_redeem_with_wrong_preimage(wallet1: Wallet, wallet2: Wallet):
|
||||
invoice = await wallet1.request_mint(64)
|
||||
pay_if_regtest(invoice.bolt11)
|
||||
await pay_if_regtest(invoice.bolt11)
|
||||
await wallet1.mint(64, id=invoice.id)
|
||||
preimage = "00000000000000000000000000000000"
|
||||
# preimage_hash = hashlib.sha256(bytes.fromhex(preimage)).hexdigest()
|
||||
@@ -114,7 +114,7 @@ async def test_htlc_redeem_with_wrong_preimage(wallet1: Wallet, wallet2: Wallet)
|
||||
@pytest.mark.asyncio
|
||||
async def test_htlc_redeem_with_no_signature(wallet1: Wallet, wallet2: Wallet):
|
||||
invoice = await wallet1.request_mint(64)
|
||||
pay_if_regtest(invoice.bolt11)
|
||||
await pay_if_regtest(invoice.bolt11)
|
||||
await wallet1.mint(64, id=invoice.id)
|
||||
preimage = "00000000000000000000000000000000"
|
||||
pubkey_wallet1 = await wallet1.create_p2pk_pubkey()
|
||||
@@ -134,7 +134,7 @@ async def test_htlc_redeem_with_no_signature(wallet1: Wallet, wallet2: Wallet):
|
||||
@pytest.mark.asyncio
|
||||
async def test_htlc_redeem_with_wrong_signature(wallet1: Wallet, wallet2: Wallet):
|
||||
invoice = await wallet1.request_mint(64)
|
||||
pay_if_regtest(invoice.bolt11)
|
||||
await pay_if_regtest(invoice.bolt11)
|
||||
await wallet1.mint(64, id=invoice.id)
|
||||
preimage = "00000000000000000000000000000000"
|
||||
pubkey_wallet1 = await wallet1.create_p2pk_pubkey()
|
||||
@@ -158,7 +158,7 @@ async def test_htlc_redeem_with_wrong_signature(wallet1: Wallet, wallet2: Wallet
|
||||
@pytest.mark.asyncio
|
||||
async def test_htlc_redeem_with_correct_signature(wallet1: Wallet, wallet2: Wallet):
|
||||
invoice = await wallet1.request_mint(64)
|
||||
pay_if_regtest(invoice.bolt11)
|
||||
await pay_if_regtest(invoice.bolt11)
|
||||
await wallet1.mint(64, id=invoice.id)
|
||||
preimage = "00000000000000000000000000000000"
|
||||
pubkey_wallet1 = await wallet1.create_p2pk_pubkey()
|
||||
@@ -180,7 +180,7 @@ async def test_htlc_redeem_hashlock_wrong_signature_timelock_correct_signature(
|
||||
wallet1: Wallet, wallet2: Wallet
|
||||
):
|
||||
invoice = await wallet1.request_mint(64)
|
||||
pay_if_regtest(invoice.bolt11)
|
||||
await pay_if_regtest(invoice.bolt11)
|
||||
await wallet1.mint(64, id=invoice.id)
|
||||
preimage = "00000000000000000000000000000000"
|
||||
pubkey_wallet1 = await wallet1.create_p2pk_pubkey()
|
||||
@@ -214,7 +214,7 @@ async def test_htlc_redeem_hashlock_wrong_signature_timelock_wrong_signature(
|
||||
wallet1: Wallet, wallet2: Wallet
|
||||
):
|
||||
invoice = await wallet1.request_mint(64)
|
||||
pay_if_regtest(invoice.bolt11)
|
||||
await pay_if_regtest(invoice.bolt11)
|
||||
await wallet1.mint(64, id=invoice.id)
|
||||
preimage = "00000000000000000000000000000000"
|
||||
pubkey_wallet1 = await wallet1.create_p2pk_pubkey()
|
||||
|
||||
@@ -78,7 +78,7 @@ async def test_check_invoice_external(wallet: LightningWallet):
|
||||
assert invoice.checking_id
|
||||
status = await wallet.get_invoice_status(invoice.checking_id)
|
||||
assert not status.paid
|
||||
pay_if_regtest(invoice.payment_request)
|
||||
await pay_if_regtest(invoice.payment_request)
|
||||
status = await wallet.get_invoice_status(invoice.checking_id)
|
||||
assert status.paid
|
||||
|
||||
@@ -113,7 +113,7 @@ async def test_pay_invoice_external(wallet: LightningWallet):
|
||||
invoice = await wallet.create_invoice(64)
|
||||
assert invoice.payment_request
|
||||
assert invoice.checking_id
|
||||
pay_if_regtest(invoice.payment_request)
|
||||
await pay_if_regtest(invoice.payment_request)
|
||||
status = await wallet.get_invoice_status(invoice.checking_id)
|
||||
assert status.paid
|
||||
assert wallet.available_balance >= 64
|
||||
|
||||
@@ -60,7 +60,7 @@ async def wallet2():
|
||||
@pytest.mark.asyncio
|
||||
async def test_create_p2pk_pubkey(wallet1: Wallet):
|
||||
invoice = await wallet1.request_mint(64)
|
||||
pay_if_regtest(invoice.bolt11)
|
||||
await pay_if_regtest(invoice.bolt11)
|
||||
await wallet1.mint(64, id=invoice.id)
|
||||
pubkey = await wallet1.create_p2pk_pubkey()
|
||||
PublicKey(bytes.fromhex(pubkey), raw=True)
|
||||
@@ -69,7 +69,7 @@ async def test_create_p2pk_pubkey(wallet1: Wallet):
|
||||
@pytest.mark.asyncio
|
||||
async def test_p2pk(wallet1: Wallet, wallet2: Wallet):
|
||||
invoice = await wallet1.request_mint(64)
|
||||
pay_if_regtest(invoice.bolt11)
|
||||
await pay_if_regtest(invoice.bolt11)
|
||||
await wallet1.mint(64, id=invoice.id)
|
||||
pubkey_wallet2 = await wallet2.create_p2pk_pubkey()
|
||||
# p2pk test
|
||||
@@ -93,7 +93,7 @@ async def test_p2pk(wallet1: Wallet, wallet2: Wallet):
|
||||
@pytest.mark.asyncio
|
||||
async def test_p2pk_sig_all(wallet1: Wallet, wallet2: Wallet):
|
||||
invoice = await wallet1.request_mint(64)
|
||||
pay_if_regtest(invoice.bolt11)
|
||||
await pay_if_regtest(invoice.bolt11)
|
||||
await wallet1.mint(64, id=invoice.id)
|
||||
pubkey_wallet2 = await wallet2.create_p2pk_pubkey()
|
||||
# p2pk test
|
||||
@@ -109,7 +109,7 @@ async def test_p2pk_sig_all(wallet1: Wallet, wallet2: Wallet):
|
||||
@pytest.mark.asyncio
|
||||
async def test_p2pk_receive_with_wrong_private_key(wallet1: Wallet, wallet2: Wallet):
|
||||
invoice = await wallet1.request_mint(64)
|
||||
pay_if_regtest(invoice.bolt11)
|
||||
await pay_if_regtest(invoice.bolt11)
|
||||
await wallet1.mint(64, id=invoice.id)
|
||||
pubkey_wallet2 = await wallet2.create_p2pk_pubkey() # receiver side
|
||||
# sender side
|
||||
@@ -130,7 +130,7 @@ async def test_p2pk_short_locktime_receive_with_wrong_private_key(
|
||||
wallet1: Wallet, wallet2: Wallet
|
||||
):
|
||||
invoice = await wallet1.request_mint(64)
|
||||
pay_if_regtest(invoice.bolt11)
|
||||
await pay_if_regtest(invoice.bolt11)
|
||||
await wallet1.mint(64, id=invoice.id)
|
||||
pubkey_wallet2 = await wallet2.create_p2pk_pubkey() # receiver side
|
||||
# sender side
|
||||
@@ -156,7 +156,7 @@ async def test_p2pk_short_locktime_receive_with_wrong_private_key(
|
||||
@pytest.mark.asyncio
|
||||
async def test_p2pk_locktime_with_refund_pubkey(wallet1: Wallet, wallet2: Wallet):
|
||||
invoice = await wallet1.request_mint(64)
|
||||
pay_if_regtest(invoice.bolt11)
|
||||
await pay_if_regtest(invoice.bolt11)
|
||||
await wallet1.mint(64, id=invoice.id)
|
||||
pubkey_wallet2 = await wallet2.create_p2pk_pubkey() # receiver side
|
||||
# sender side
|
||||
@@ -185,7 +185,7 @@ async def test_p2pk_locktime_with_refund_pubkey(wallet1: Wallet, wallet2: Wallet
|
||||
@pytest.mark.asyncio
|
||||
async def test_p2pk_locktime_with_wrong_refund_pubkey(wallet1: Wallet, wallet2: Wallet):
|
||||
invoice = await wallet1.request_mint(64)
|
||||
pay_if_regtest(invoice.bolt11)
|
||||
await pay_if_regtest(invoice.bolt11)
|
||||
await wallet1.mint(64, id=invoice.id)
|
||||
await wallet2.create_p2pk_pubkey() # receiver side
|
||||
# sender side
|
||||
@@ -221,7 +221,7 @@ async def test_p2pk_locktime_with_second_refund_pubkey(
|
||||
wallet1: Wallet, wallet2: Wallet
|
||||
):
|
||||
invoice = await wallet1.request_mint(64)
|
||||
pay_if_regtest(invoice.bolt11)
|
||||
await pay_if_regtest(invoice.bolt11)
|
||||
await wallet1.mint(64, id=invoice.id)
|
||||
pubkey_wallet1 = await wallet1.create_p2pk_pubkey() # receiver side
|
||||
pubkey_wallet2 = await wallet2.create_p2pk_pubkey() # receiver side
|
||||
@@ -253,7 +253,7 @@ async def test_p2pk_locktime_with_second_refund_pubkey(
|
||||
@pytest.mark.asyncio
|
||||
async def test_p2pk_multisig_2_of_2(wallet1: Wallet, wallet2: Wallet):
|
||||
invoice = await wallet1.request_mint(64)
|
||||
pay_if_regtest(invoice.bolt11)
|
||||
await pay_if_regtest(invoice.bolt11)
|
||||
await wallet1.mint(64, id=invoice.id)
|
||||
pubkey_wallet1 = await wallet1.create_p2pk_pubkey()
|
||||
pubkey_wallet2 = await wallet2.create_p2pk_pubkey()
|
||||
@@ -275,7 +275,7 @@ async def test_p2pk_multisig_2_of_2(wallet1: Wallet, wallet2: Wallet):
|
||||
@pytest.mark.asyncio
|
||||
async def test_p2pk_multisig_duplicate_signature(wallet1: Wallet, wallet2: Wallet):
|
||||
invoice = await wallet1.request_mint(64)
|
||||
pay_if_regtest(invoice.bolt11)
|
||||
await pay_if_regtest(invoice.bolt11)
|
||||
await wallet1.mint(64, id=invoice.id)
|
||||
pubkey_wallet1 = await wallet1.create_p2pk_pubkey()
|
||||
pubkey_wallet2 = await wallet2.create_p2pk_pubkey()
|
||||
@@ -299,7 +299,7 @@ async def test_p2pk_multisig_duplicate_signature(wallet1: Wallet, wallet2: Walle
|
||||
@pytest.mark.asyncio
|
||||
async def test_p2pk_multisig_quorum_not_met_1_of_2(wallet1: Wallet, wallet2: Wallet):
|
||||
invoice = await wallet1.request_mint(64)
|
||||
pay_if_regtest(invoice.bolt11)
|
||||
await pay_if_regtest(invoice.bolt11)
|
||||
await wallet1.mint(64, id=invoice.id)
|
||||
pubkey_wallet1 = await wallet1.create_p2pk_pubkey()
|
||||
pubkey_wallet2 = await wallet2.create_p2pk_pubkey()
|
||||
@@ -320,7 +320,7 @@ async def test_p2pk_multisig_quorum_not_met_1_of_2(wallet1: Wallet, wallet2: Wal
|
||||
@pytest.mark.asyncio
|
||||
async def test_p2pk_multisig_quorum_not_met_2_of_3(wallet1: Wallet, wallet2: Wallet):
|
||||
invoice = await wallet1.request_mint(64)
|
||||
pay_if_regtest(invoice.bolt11)
|
||||
await pay_if_regtest(invoice.bolt11)
|
||||
await wallet1.mint(64, id=invoice.id)
|
||||
pubkey_wallet1 = await wallet1.create_p2pk_pubkey()
|
||||
pubkey_wallet2 = await wallet2.create_p2pk_pubkey()
|
||||
@@ -345,7 +345,7 @@ async def test_p2pk_multisig_quorum_not_met_2_of_3(wallet1: Wallet, wallet2: Wal
|
||||
@pytest.mark.asyncio
|
||||
async def test_p2pk_multisig_with_duplicate_publickey(wallet1: Wallet, wallet2: Wallet):
|
||||
invoice = await wallet1.request_mint(64)
|
||||
pay_if_regtest(invoice.bolt11)
|
||||
await pay_if_regtest(invoice.bolt11)
|
||||
await wallet1.mint(64, id=invoice.id)
|
||||
pubkey_wallet2 = await wallet2.create_p2pk_pubkey()
|
||||
# p2pk test
|
||||
@@ -363,7 +363,7 @@ async def test_p2pk_multisig_with_wrong_first_private_key(
|
||||
wallet1: Wallet, wallet2: Wallet
|
||||
):
|
||||
invoice = await wallet1.request_mint(64)
|
||||
pay_if_regtest(invoice.bolt11)
|
||||
await pay_if_regtest(invoice.bolt11)
|
||||
await wallet1.mint(64, id=invoice.id)
|
||||
await wallet1.create_p2pk_pubkey()
|
||||
pubkey_wallet2 = await wallet2.create_p2pk_pubkey()
|
||||
|
||||
@@ -34,7 +34,7 @@ async def wallet():
|
||||
async def test_regtest_pending_quote(wallet: Wallet, ledger: Ledger):
|
||||
# fill wallet
|
||||
invoice = await wallet.request_mint(64)
|
||||
pay_if_regtest(invoice.bolt11)
|
||||
await pay_if_regtest(invoice.bolt11)
|
||||
await wallet.mint(64, id=invoice.id)
|
||||
assert wallet.balance == 64
|
||||
|
||||
@@ -72,7 +72,7 @@ async def test_regtest_pending_quote(wallet: Wallet, ledger: Ledger):
|
||||
async def test_regtest_failed_quote(wallet: Wallet, ledger: Ledger):
|
||||
# fill wallet
|
||||
invoice = await wallet.request_mint(64)
|
||||
pay_if_regtest(invoice.bolt11)
|
||||
await pay_if_regtest(invoice.bolt11)
|
||||
await wallet.mint(64, id=invoice.id)
|
||||
assert wallet.balance == 64
|
||||
|
||||
|
||||
@@ -38,12 +38,12 @@ async def test_regtest_pay_mpp(wallet: Wallet, ledger: Ledger):
|
||||
|
||||
# top up wallet twice so we have enough for two payments
|
||||
topup_invoice = await wallet.request_mint(128)
|
||||
pay_if_regtest(topup_invoice.bolt11)
|
||||
await pay_if_regtest(topup_invoice.bolt11)
|
||||
proofs1 = await wallet.mint(128, id=topup_invoice.id)
|
||||
assert wallet.balance == 128
|
||||
|
||||
topup_invoice = await wallet.request_mint(128)
|
||||
pay_if_regtest(topup_invoice.bolt11)
|
||||
await pay_if_regtest(topup_invoice.bolt11)
|
||||
proofs2 = await wallet.mint(128, id=topup_invoice.id)
|
||||
assert wallet.balance == 256
|
||||
|
||||
@@ -82,17 +82,17 @@ async def test_regtest_pay_mpp_incomplete_payment(wallet: Wallet, ledger: Ledger
|
||||
|
||||
# top up wallet twice so we have enough for three payments
|
||||
topup_invoice = await wallet.request_mint(128)
|
||||
pay_if_regtest(topup_invoice.bolt11)
|
||||
await pay_if_regtest(topup_invoice.bolt11)
|
||||
proofs1 = await wallet.mint(128, id=topup_invoice.id)
|
||||
assert wallet.balance == 128
|
||||
|
||||
topup_invoice = await wallet.request_mint(128)
|
||||
pay_if_regtest(topup_invoice.bolt11)
|
||||
await pay_if_regtest(topup_invoice.bolt11)
|
||||
proofs2 = await wallet.mint(128, id=topup_invoice.id)
|
||||
assert wallet.balance == 256
|
||||
|
||||
topup_invoice = await wallet.request_mint(128)
|
||||
pay_if_regtest(topup_invoice.bolt11)
|
||||
await pay_if_regtest(topup_invoice.bolt11)
|
||||
proofs3 = await wallet.mint(128, id=topup_invoice.id)
|
||||
assert wallet.balance == 384
|
||||
|
||||
|
||||
@@ -157,7 +157,7 @@ async def test_generate_secrets_from_to(wallet3: Wallet):
|
||||
async def test_restore_wallet_after_mint(wallet3: Wallet):
|
||||
await reset_wallet_db(wallet3)
|
||||
invoice = await wallet3.request_mint(64)
|
||||
pay_if_regtest(invoice.bolt11)
|
||||
await pay_if_regtest(invoice.bolt11)
|
||||
await wallet3.mint(64, id=invoice.id)
|
||||
assert wallet3.balance == 64
|
||||
await reset_wallet_db(wallet3)
|
||||
@@ -193,7 +193,7 @@ async def test_restore_wallet_after_split_to_send(wallet3: Wallet):
|
||||
await reset_wallet_db(wallet3)
|
||||
|
||||
invoice = await wallet3.request_mint(64)
|
||||
pay_if_regtest(invoice.bolt11)
|
||||
await pay_if_regtest(invoice.bolt11)
|
||||
await wallet3.mint(64, id=invoice.id)
|
||||
assert wallet3.balance == 64
|
||||
|
||||
@@ -218,7 +218,7 @@ async def test_restore_wallet_after_send_and_receive(wallet3: Wallet, wallet2: W
|
||||
)
|
||||
await reset_wallet_db(wallet3)
|
||||
invoice = await wallet3.request_mint(64)
|
||||
pay_if_regtest(invoice.bolt11)
|
||||
await pay_if_regtest(invoice.bolt11)
|
||||
await wallet3.mint(64, id=invoice.id)
|
||||
assert wallet3.balance == 64
|
||||
|
||||
@@ -261,7 +261,7 @@ async def test_restore_wallet_after_send_and_self_receive(wallet3: Wallet):
|
||||
await reset_wallet_db(wallet3)
|
||||
|
||||
invoice = await wallet3.request_mint(64)
|
||||
pay_if_regtest(invoice.bolt11)
|
||||
await pay_if_regtest(invoice.bolt11)
|
||||
await wallet3.mint(64, id=invoice.id)
|
||||
assert wallet3.balance == 64
|
||||
|
||||
@@ -290,7 +290,7 @@ async def test_restore_wallet_after_send_twice(
|
||||
await reset_wallet_db(wallet3)
|
||||
|
||||
invoice = await wallet3.request_mint(2)
|
||||
pay_if_regtest(invoice.bolt11)
|
||||
await pay_if_regtest(invoice.bolt11)
|
||||
await wallet3.mint(2, id=invoice.id)
|
||||
box.add(wallet3.proofs)
|
||||
assert wallet3.balance == 2
|
||||
@@ -349,7 +349,7 @@ async def test_restore_wallet_after_send_and_self_receive_nonquadratic_value(
|
||||
await reset_wallet_db(wallet3)
|
||||
|
||||
invoice = await wallet3.request_mint(64)
|
||||
pay_if_regtest(invoice.bolt11)
|
||||
await pay_if_regtest(invoice.bolt11)
|
||||
await wallet3.mint(64, id=invoice.id)
|
||||
box.add(wallet3.proofs)
|
||||
assert wallet3.balance == 64
|
||||
|
||||
@@ -47,7 +47,7 @@ async def test_wallet_subscription_mint(wallet: Wallet):
|
||||
asyncio.run(wallet.mint(int(invoice.amount), id=invoice.id))
|
||||
|
||||
invoice, sub = await wallet.request_mint_with_callback(128, callback=callback)
|
||||
pay_if_regtest(invoice.bolt11)
|
||||
await pay_if_regtest(invoice.bolt11)
|
||||
wait = settings.fakewallet_delay_incoming_payment or 2
|
||||
await asyncio.sleep(wait + 2)
|
||||
|
||||
@@ -70,7 +70,7 @@ async def test_wallet_subscription_swap(wallet: Wallet):
|
||||
pytest.skip("No websocket support")
|
||||
|
||||
invoice = await wallet.request_mint(64)
|
||||
pay_if_regtest(invoice.bolt11)
|
||||
await pay_if_regtest(invoice.bolt11)
|
||||
await wallet.mint(64, id=invoice.id)
|
||||
|
||||
triggered = False
|
||||
|
||||
Reference in New Issue
Block a user