Files
nutshell/cashu/mint/db/read.py
callebtc 6a0a370ba5 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
2024-07-08 18:05:57 +02:00

79 lines
3.2 KiB
Python

from typing import Dict, List, Optional
from ...core.base import Proof, ProofSpentState, ProofState
from ...core.db import Connection, Database
from ..crud import LedgerCrud
class DbReadHelper:
db: Database
crud: LedgerCrud
def __init__(self, db: Database, crud: LedgerCrud) -> None:
self.db = db
self.crud = crud
async def _get_proofs_pending(
self, Ys: List[str], conn: Optional[Connection] = None
) -> Dict[str, Proof]:
"""Returns a dictionary of only those proofs that are pending.
The key is the Y=h2c(secret) and the value is the proof.
"""
async with self.db.get_connection(conn) as conn:
proofs_pending = await self.crud.get_proofs_pending(
Ys=Ys, db=self.db, conn=conn
)
proofs_pending_dict = {p.Y: p for p in proofs_pending}
return proofs_pending_dict
async def _get_proofs_spent(
self, Ys: List[str], conn: Optional[Connection] = None
) -> Dict[str, Proof]:
"""Returns a dictionary of all proofs that are spent.
The key is the Y=h2c(secret) and the value is the proof.
"""
proofs_spent_dict: Dict[str, Proof] = {}
# check used secrets in database
async with self.db.get_connection(conn) as conn:
for Y in Ys:
spent_proof = await self.crud.get_proof_used(db=self.db, Y=Y, conn=conn)
if spent_proof:
proofs_spent_dict[Y] = spent_proof
return proofs_spent_dict
async def get_proofs_states(
self, Ys: List[str], conn: Optional[Connection] = None
) -> List[ProofState]:
"""Checks if provided proofs are spend or are pending.
Used by wallets to check if their proofs have been redeemed by a receiver or they are still in-flight in a transaction.
Returns two lists that are in the same order as the provided proofs. Wallet must match the list
to the proofs they have provided in order to figure out which proof is spendable or pending
and which isn't.
Args:
Ys (List[str]): List of Y's of proofs to check
Returns:
List[bool]: List of which proof is still spendable (True if still spendable, else False)
List[bool]: List of which proof are pending (True if pending, else False)
"""
states: List[ProofState] = []
async with self.db.get_connection(conn) as conn:
proofs_spent = await self._get_proofs_spent(Ys, conn)
proofs_pending = await self._get_proofs_pending(Ys, conn)
for Y in Ys:
if Y not in proofs_spent and Y not in proofs_pending:
states.append(ProofState(Y=Y, state=ProofSpentState.unspent))
elif Y not in proofs_spent and Y in proofs_pending:
states.append(ProofState(Y=Y, state=ProofSpentState.pending))
else:
states.append(
ProofState(
Y=Y,
state=ProofSpentState.spent,
witness=proofs_spent[Y].witness,
)
)
return states