mirror of
https://github.com/aljazceru/nutshell.git
synced 2025-12-22 11:24:19 +01:00
* fix keys * fix tests * backwards compatible api upgrade * upgrade seems to work * fix tests * add deprecated api functions * add more tests of backwards compat * add test serialization for nut00 * remove a redundant test * move mint and melt to new api * mypy works * CI: mypy --check-untyped-defs * add deprecated router * add hints and remove logs * fix tests * cleanup * use new mint and melt endpoints * tests passing? * fix mypy * make format * make format * make format * commit * errors gone * save * adjust the API * store quotes in db * make mypy happy * add fakewallet settings * remove LIGHTNING=True and pass quote id for melt * format * tests passing * add CoreLightningRestWallet * add macaroon loader * add correct config * preimage -> proof * move wallet.status() to cli.helpers.print_status() * remove statuses from tests * remove * make format * Use httpx in deprecated wallet * fix cln interface * create invoice before quote * internal transactions and deprecated api testing * fix tests * add deprecated API tests * fastapi type hints break things * fix duplicate wallet error * make format * update poetry in CI to 1.7.1 * precommit restore * remove bolt11 * oops * default poetry * store fee reserve for melt quotes and refactor melt() * works? * make format * test * finally * fix deprecated models * rename v1 endpoints to bolt11 * raise restore and check to v1, bump version to 0.15.0 * add version byte to keyset id * remove redundant fields in json * checks * generate bip32 keyset wip * migrate old keysets * load duplicate keys * duplicate old keysets * revert router changes * add deprecated /check and /restore endpoints * try except invalidate * parse unit from derivation path, adjust keyset id calculation with bytes * remove keyest id from functions again and rely on self.keyset_id * mosts tests work * mint loads multiple derivation paths * make format * properly print units * fix tests * wallet works with multiple units * add strike wallet and choose backend dynamically * fix mypy * add get_payment_quote to lightning backends * make format * fix startup * fix lnbitswallet * fix tests * LightningWallet -> LightningBackend * remove comments * make format * remove msat conversion * add Amount type * fix regtest * use melt_quote as argument for pay_invoice * test old api * fees in sats * fix deprecated fees * fixes * print balance correctly * internally index keyset response by int * add pydantic validation to input models * add timestamps to mint db * store timestamps for invoices, promises, proofs_used * fix wallet migration * rotate keys correctly for testing * remove print * update latest keyset * fix tests * fix test * make format * make format with correct black version * remove nsat and cheese * test against deprecated mint * fix tests? * actually use env var * mint run with env vars * moar test * cleanup * simplify tests, load all keys * try out testing with internal invoices * fix internal melt test * fix test * deprecated checkfees expects appropriate fees * adjust comment * drop lightning table * split migration for testing for now, remove it later * remove unused lightning table * skip_private_key -> skip_db_read * throw error on migration error * reorder * fix migrations * fix lnbits fee return value negative * fix typo * comments * add type * make format * split must use correct amount * fix tests * test deprecated api with internal/external melts * do not split if not necessary * refactor * fix test * make format with new black * cleanup and add comments * add quote state check endpoints * fix deprecated wallet response * split -> swap endpoint * make format * add expiry to quotes, get quote endpoints, and adjust to nut review comments * allow overpayment of melt * add lightning wallet tests * commiting to save * fix tests a bit * make format * remove comments * get mint info * check_spendable default False, and return payment quote checking id * make format * bump version in pyproject * update to /v1/checkstate * make format * fix mint api checks * return witness on /v1/checkstate * no failfast * try fail-fast: false in ci.yaml * fix db lookup * clean up literals
185 lines
4.8 KiB
Python
185 lines
4.8 KiB
Python
import hashlib
|
|
import importlib
|
|
import json
|
|
import os
|
|
import random
|
|
import string
|
|
import time
|
|
from subprocess import PIPE, Popen, TimeoutExpired
|
|
from typing import Tuple
|
|
|
|
from loguru import logger
|
|
|
|
from cashu.core.settings import settings
|
|
|
|
|
|
def get_random_string(N: int = 10):
|
|
return "".join(
|
|
random.SystemRandom().choice(string.ascii_uppercase + string.digits)
|
|
for _ in range(N)
|
|
)
|
|
|
|
|
|
async def get_random_invoice_data():
|
|
return {"out": False, "amount": 10, "memo": f"test_memo_{get_random_string(10)}"}
|
|
|
|
|
|
wallets_module = importlib.import_module("cashu.lightning")
|
|
wallet_class = getattr(wallets_module, settings.mint_lightning_backend)
|
|
WALLET = wallet_class()
|
|
is_fake: bool = WALLET.__class__.__name__ == "FakeWallet"
|
|
is_regtest: bool = not is_fake
|
|
is_deprecated_api_only = settings.debug_mint_only_deprecated
|
|
|
|
docker_lightning_cli = [
|
|
"docker",
|
|
"exec",
|
|
"cashu-lnd-1-1",
|
|
"lncli",
|
|
"--network",
|
|
"regtest",
|
|
"--rpcserver=lnd-1",
|
|
]
|
|
|
|
docker_bitcoin_cli = [
|
|
"docker",
|
|
"exec",
|
|
"cashu-bitcoind-1-1bitcoin-cli",
|
|
"-rpcuser=lnbits",
|
|
"-rpcpassword=lnbits",
|
|
"-regtest",
|
|
]
|
|
|
|
|
|
docker_lightning_unconnected_cli = [
|
|
"docker",
|
|
"exec",
|
|
"cashu-lnd-2-1",
|
|
"lncli",
|
|
"--network",
|
|
"regtest",
|
|
"--rpcserver=lnd-2",
|
|
]
|
|
|
|
|
|
def run_cmd(cmd: list) -> str:
|
|
timeout = 20
|
|
process = Popen(cmd, stdout=PIPE, stderr=PIPE)
|
|
|
|
def process_communication(comm):
|
|
stdout, stderr = comm
|
|
output = stdout.decode("utf-8").strip()
|
|
error = stderr.decode("utf-8").strip()
|
|
return output, error
|
|
|
|
try:
|
|
now = time.time()
|
|
output, error = process_communication(process.communicate(timeout=timeout))
|
|
took = time.time() - now
|
|
logger.debug(f"ran command output: {output}, error: {error}, took: {took}s")
|
|
return output
|
|
except TimeoutExpired:
|
|
process.kill()
|
|
output, error = process_communication(process.communicate())
|
|
logger.error(f"timeout command: {cmd}, output: {output}, error: {error}")
|
|
raise
|
|
|
|
|
|
def run_cmd_json(cmd: list) -> dict:
|
|
output = run_cmd(cmd)
|
|
try:
|
|
return json.loads(output) if output else {}
|
|
except json.decoder.JSONDecodeError:
|
|
logger.error(f"failed to decode json from cmd `{cmd}`: {output}")
|
|
raise
|
|
|
|
|
|
def get_hold_invoice(sats: int) -> Tuple[str, dict]:
|
|
preimage = os.urandom(32)
|
|
preimage_hash = hashlib.sha256(preimage).hexdigest()
|
|
cmd = docker_lightning_cli.copy()
|
|
cmd.extend(["addholdinvoice", preimage_hash, str(sats)])
|
|
json = run_cmd_json(cmd)
|
|
return preimage.hex(), json
|
|
|
|
|
|
def settle_invoice(preimage: str) -> str:
|
|
cmd = docker_lightning_cli.copy()
|
|
cmd.extend(["settleinvoice", preimage])
|
|
return run_cmd(cmd)
|
|
|
|
|
|
def cancel_invoice(preimage_hash: str) -> str:
|
|
cmd = docker_lightning_cli.copy()
|
|
cmd.extend(["cancelinvoice", preimage_hash])
|
|
return run_cmd(cmd)
|
|
|
|
|
|
def get_real_invoice(sats: int) -> dict:
|
|
cmd = docker_lightning_cli.copy()
|
|
cmd.extend(["addinvoice", str(sats)])
|
|
return run_cmd_json(cmd)
|
|
|
|
|
|
def pay_real_invoice(invoice: str) -> str:
|
|
cmd = docker_lightning_cli.copy()
|
|
cmd.extend(["payinvoice", "--force", invoice])
|
|
return run_cmd(cmd)
|
|
|
|
|
|
def mine_blocks(blocks: int = 1) -> str:
|
|
cmd = docker_bitcoin_cli.copy()
|
|
cmd.extend(["-generate", str(blocks)])
|
|
return run_cmd(cmd)
|
|
|
|
|
|
def get_unconnected_node_uri() -> str:
|
|
cmd = docker_lightning_unconnected_cli.copy()
|
|
cmd.append("getinfo")
|
|
info = run_cmd_json(cmd)
|
|
pubkey = info["identity_pubkey"]
|
|
return f"{pubkey}@lnd-2:9735"
|
|
|
|
|
|
def create_onchain_address(address_type: str = "bech32") -> str:
|
|
cmd = docker_bitcoin_cli.copy()
|
|
cmd.extend(["getnewaddress", address_type])
|
|
return run_cmd(cmd)
|
|
|
|
|
|
def pay_onchain(address: str, sats: int) -> str:
|
|
btc = sats * 0.00000001
|
|
cmd = docker_bitcoin_cli.copy()
|
|
cmd.extend(["sendtoaddress", address, str(btc)])
|
|
return run_cmd(cmd)
|
|
|
|
|
|
# def clean_database(settings):
|
|
# if DB_TYPE == POSTGRES:
|
|
# db_url = make_url(settings.lnbits_database_url)
|
|
|
|
# conn = psycopg2.connect(settings.lnbits_database_url)
|
|
# conn.autocommit = True
|
|
# with conn.cursor() as cur:
|
|
# try:
|
|
# cur.execute("DROP DATABASE lnbits_test")
|
|
# except psycopg2.errors.InvalidCatalogName:
|
|
# pass
|
|
# cur.execute("CREATE DATABASE lnbits_test")
|
|
|
|
# db_url.database = "lnbits_test"
|
|
# settings.lnbits_database_url = str(db_url)
|
|
|
|
# core.db.__init__("database")
|
|
|
|
# conn.close()
|
|
# else:
|
|
# # FIXME: do this once mock data is removed from test data folder
|
|
# # os.remove(settings.lnbits_data_folder + "/database.sqlite3")
|
|
# pass
|
|
|
|
|
|
def pay_if_regtest(bolt11: str):
|
|
if is_regtest:
|
|
pay_real_invoice(bolt11)
|