mirror of
https://github.com/aljazceru/nutshell.git
synced 2025-12-20 18:44:20 +01:00
* wip adding states, tests failing * add state field to quotes * responses from quotes * store correct state * cleaner test * fix swap check * oops
98 lines
3.7 KiB
Python
98 lines
3.7 KiB
Python
import asyncio
|
|
from typing import List, Optional
|
|
|
|
from loguru import logger
|
|
|
|
from ...core.base import Proof, ProofSpentState, ProofState
|
|
from ...core.db import Connection, Database, get_db_connection
|
|
from ...core.errors import (
|
|
TransactionError,
|
|
)
|
|
from ..crud import LedgerCrud
|
|
from ..events.events import LedgerEventManager
|
|
|
|
|
|
class DbWriteHelper:
|
|
db: Database
|
|
crud: LedgerCrud
|
|
events: LedgerEventManager
|
|
proofs_pending_lock: asyncio.Lock = (
|
|
asyncio.Lock()
|
|
) # holds locks for proofs_pending database
|
|
|
|
def __init__(
|
|
self, db: Database, crud: LedgerCrud, events: LedgerEventManager
|
|
) -> None:
|
|
self.db = db
|
|
self.crud = crud
|
|
self.events = events
|
|
|
|
async def _set_proofs_pending(
|
|
self, proofs: List[Proof], quote_id: Optional[str] = None
|
|
) -> 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.
|
|
|
|
Args:
|
|
proofs (List[Proof]): Proofs to add to pending table.
|
|
quote_id (Optional[str]): Melt quote ID. If it is not set, we assume the pending tokens to be from a swap.
|
|
|
|
Raises:
|
|
Exception: At least one proof already in pending table.
|
|
"""
|
|
# first we check whether these proofs are pending already
|
|
async with self.proofs_pending_lock:
|
|
async with get_db_connection(self.db) as conn:
|
|
await self._validate_proofs_pending(proofs, conn)
|
|
try:
|
|
for p in proofs:
|
|
await self.crud.set_proof_pending(
|
|
proof=p, db=self.db, quote_id=quote_id, conn=conn
|
|
)
|
|
await self.events.submit(
|
|
ProofState(Y=p.Y, state=ProofSpentState.pending)
|
|
)
|
|
except Exception as e:
|
|
logger.error(f"Failed to set proofs pending: {e}")
|
|
raise TransactionError("Failed to set proofs pending.")
|
|
|
|
async def _unset_proofs_pending(self, proofs: List[Proof], spent=True) -> None:
|
|
"""Deletes proofs from pending table.
|
|
|
|
Args:
|
|
proofs (List[Proof]): Proofs to delete.
|
|
spent (bool): Whether the proofs have been spent or not. Defaults to True.
|
|
This should be False if the proofs were NOT invalidated before calling this function.
|
|
It is used to emit the unspent state for the proofs (otherwise the spent state is emitted
|
|
by the _invalidate_proofs function when the proofs are spent).
|
|
"""
|
|
async with self.proofs_pending_lock:
|
|
async with get_db_connection(self.db) as conn:
|
|
for p in proofs:
|
|
await self.crud.unset_proof_pending(proof=p, db=self.db, conn=conn)
|
|
if not spent:
|
|
await self.events.submit(
|
|
ProofState(Y=p.Y, state=ProofSpentState.unspent)
|
|
)
|
|
|
|
async def _validate_proofs_pending(
|
|
self, proofs: List[Proof], conn: Optional[Connection] = None
|
|
) -> None:
|
|
"""Checks if any of the provided proofs is in the pending proofs table.
|
|
|
|
Args:
|
|
proofs (List[Proof]): Proofs to check.
|
|
|
|
Raises:
|
|
Exception: At least one of the proofs is in the pending table.
|
|
"""
|
|
if not (
|
|
len(
|
|
await self.crud.get_proofs_pending(
|
|
Ys=[p.Y for p in proofs], db=self.db, conn=conn
|
|
)
|
|
)
|
|
== 0
|
|
):
|
|
raise TransactionError("proofs are pending.")
|