From d0283670d361d5e5b50654ba3718ad0fb365c315 Mon Sep 17 00:00:00 2001 From: callebtc <93376500+callebtc@users.noreply.github.com> Date: Mon, 15 May 2023 22:15:56 +0200 Subject: [PATCH] Refactor Compat and Database for LNbits comaptibility (#219) * remove changes to Compat and Database so its compatible with the classes from LNbits * ledger.py: Annotate Connection type * fix invoice memp --- cashu/core/db.py | 36 +++++++++++++++++++++--------------- cashu/core/migrations.py | 6 +----- cashu/mint/crud.py | 3 +-- cashu/mint/ledger.py | 24 ++++++++++++++---------- cashu/mint/migrations.py | 5 ++--- 5 files changed, 39 insertions(+), 35 deletions(-) diff --git a/cashu/core/db.py b/cashu/core/db.py index c086664..2fe9839 100644 --- a/cashu/core/db.py +++ b/cashu/core/db.py @@ -49,15 +49,6 @@ class Compat: return "" return "" - def lock_table(self, table: str) -> str: - if self.type == POSTGRES: - return f"LOCK TABLE {table} IN EXCLUSIVE MODE;" - elif self.type == COCKROACH: - return f"LOCK TABLE {table};" - elif self.type == SQLITE: - return "BEGIN EXCLUSIVE TRANSACTION;" - return "" - class Connection(Compat): def __init__(self, conn: AsyncConnection, txn, typ, name, schema): @@ -109,15 +100,15 @@ class Database(Compat): f = "%Y-%m-%d %H:%M:%S" return time.mktime(datetime.datetime.strptime(value, f).timetuple()) - psycopg2.extensions.register_type( - psycopg2.extensions.new_type( - psycopg2.extensions.DECIMAL.values, + psycopg2.extensions.register_type( # type: ignore + psycopg2.extensions.new_type( # type: ignore + psycopg2.extensions.DECIMAL.values, # type: ignore "DEC2FLOAT", lambda value, curs: float(value) if value is not None else None, ) ) - psycopg2.extensions.register_type( - psycopg2.extensions.new_type( + psycopg2.extensions.register_type( # type: ignore + psycopg2.extensions.new_type( # type: ignore (1082, 1083, 1266), "DATE2INT", lambda value, curs: time.mktime(value.timetuple()) @@ -152,7 +143,7 @@ class Database(Compat): async def connect(self): await self.lock.acquire() try: - async with self.engine.connect() as conn: + async with self.engine.connect() as conn: # type: ignore async with conn.begin() as txn: wconn = Connection(conn, txn, self.type, self.name, self.schema) @@ -189,3 +180,18 @@ class Database(Compat): @asynccontextmanager async def reuse_conn(self, conn: Connection): yield conn + + +# public functions for LNbits to use (we don't want to change the Database or Compat classes above) +def table_with_schema(db: Database, table: str): + return f"{db.references_schema if db.schema else ''}{table}" + + +def lock_table(db: Database, table: str) -> str: + if db.type == POSTGRES: + return f"LOCK TABLE {table_with_schema(db, table)} IN EXCLUSIVE MODE;" + elif db.type == COCKROACH: + return f"LOCK TABLE {table};" + elif db.type == SQLITE: + return "BEGIN EXCLUSIVE TRANSACTION;" + return "" diff --git a/cashu/core/migrations.py b/cashu/core/migrations.py index 6ca2644..4889943 100644 --- a/cashu/core/migrations.py +++ b/cashu/core/migrations.py @@ -1,10 +1,6 @@ import re -from ..core.db import COCKROACH, POSTGRES, SQLITE, Database - - -def table_with_schema(db, table: str): - return f"{db.references_schema if db.schema else ''}{table}" +from ..core.db import COCKROACH, POSTGRES, SQLITE, Database, table_with_schema async def migrate_databases(db: Database, migrations_module): diff --git a/cashu/mint/crud.py b/cashu/mint/crud.py index 8907aa3..0d3116b 100644 --- a/cashu/mint/crud.py +++ b/cashu/mint/crud.py @@ -2,8 +2,7 @@ import time from typing import Any, List, Optional from ..core.base import Invoice, MintKeyset, Proof -from ..core.db import Connection, Database -from ..core.migrations import table_with_schema +from ..core.db import Connection, Database, table_with_schema class LedgerCrud: diff --git a/cashu/mint/ledger.py b/cashu/mint/ledger.py index 9b9f941..dfa1404 100644 --- a/cashu/mint/ledger.py +++ b/cashu/mint/ledger.py @@ -15,7 +15,7 @@ from ..core.base import ( from ..core.crypto import b_dhke from ..core.crypto.keys import derive_pubkey, random_hash from ..core.crypto.secp import PublicKey -from ..core.db import Database +from ..core.db import Connection, Database, lock_table from ..core.helpers import fee_reserve, sum_proofs from ..core.script import verify_script from ..core.settings import settings @@ -305,14 +305,14 @@ class Ledger: checking_id, payment_request, error_message, - ) = await self.lightning.create_invoice(amount, "cashu deposit") + ) = await self.lightning.create_invoice(amount, "Cashu deposit") logger.trace( f"_request_lightning_invoice: Lightning invoice: {payment_request}" ) return payment_request, checking_id async def _check_lightning_invoice( - self, amount: int, hash: str, conn + self, amount: int, hash: str, conn: Optional[Connection] = None ) -> Literal[True]: """Checks with the Lightning backend whether an invoice stored with `hash` was paid. @@ -419,7 +419,9 @@ class Ledger: await self.crud.invalidate_proof(proof=p, db=self.db) logger.trace(f"crud: stored proofs") - async def _set_proofs_pending(self, proofs: List[Proof], conn): + async def _set_proofs_pending( + self, proofs: List[Proof], conn: Optional[Connection] = None + ): """If none of the proofs is in the pending table (_validate_proofs_pending), adds proofs to the list of pending proofs or removes them. Used as a mutex for proofs. @@ -443,7 +445,9 @@ class Ledger: except: raise Exception("proofs already pending.") - async def _unset_proofs_pending(self, proofs: List[Proof], conn): + async def _unset_proofs_pending( + self, proofs: List[Proof], conn: Optional[Connection] = None + ): """Deletes proofs from pending table. Args: @@ -638,7 +642,7 @@ class Ledger: amount = sum(amounts) async with self.db.connect() as conn: logger.trace("attempting lock table invoice") - await conn.execute(self.db.lock_table("invoices")) + await conn.execute(lock_table(self.db, "invoices")) logger.trace("locked table invoice") # check if lightning invoice was paid if settings.lightning: @@ -682,7 +686,7 @@ class Ledger: async with self.db.connect() as conn: logger.trace("attempting lock table proofs_pending") - await conn.execute(self.db.lock_table("proofs_pending")) + await conn.execute(lock_table(self.db, "proofs_pending")) logger.trace("locked table proofs_pending") # validate and set proofs as pending logger.trace("setting proofs pending") @@ -745,7 +749,7 @@ class Ledger: # delete proofs from pending list async with self.db.connect() as conn: logger.trace("attempting lock table proofs_pending") - await conn.execute(self.db.lock_table("proofs_pending")) + await conn.execute(lock_table(self.db, "proofs_pending")) logger.trace("locked table proofs_pending") logger.trace("unsetting proofs as pending") await self._unset_proofs_pending(proofs, conn) @@ -823,7 +827,7 @@ class Ledger: # set proofs as pending async with self.db.connect() as conn: logger.trace("attempting lock table proofs_pending") - await conn.execute(self.db.lock_table("proofs_pending")) + await conn.execute(lock_table(self.db, "proofs_pending")) logger.trace("locked table proofs_pending") # validate and set proofs as pending logger.trace("setting proofs pending") @@ -856,7 +860,7 @@ class Ledger: # delete proofs from pending list async with self.db.connect() as conn: logger.trace("attempting lock table proofs_pending") - await conn.execute(self.db.lock_table("proofs_pending")) + await conn.execute(lock_table(self.db, "proofs_pending")) logger.trace("locked table proofs_pending") logger.trace("unsetting proofs as pending") await self._unset_proofs_pending(proofs, conn) diff --git a/cashu/mint/migrations.py b/cashu/mint/migrations.py index 627681a..793dfb2 100644 --- a/cashu/mint/migrations.py +++ b/cashu/mint/migrations.py @@ -1,8 +1,7 @@ -from ..core.db import Database -from ..core.migrations import table_with_schema +from ..core.db import Database, table_with_schema -async def m000_create_migrations_table(db): +async def m000_create_migrations_table(db: Database): await db.execute( f""" CREATE TABLE IF NOT EXISTS {table_with_schema(db, 'dbversions')} (