mirror of
https://github.com/aljazceru/nutshell.git
synced 2025-12-21 11:04:19 +01:00
* `_set_proofs_pending` performs DB related "proofs are spendable" check inside the lock. * move _verify_spent_proofs_and_set_pending to write.py * edit logging --------- Co-authored-by: callebtc <93376500+callebtc@users.noreply.github.com>
94 lines
3.8 KiB
Python
94 lines
3.8 KiB
Python
from typing import Dict, List, Optional
|
|
|
|
from ...core.base import Proof, ProofSpentState, ProofState
|
|
from ...core.db import Connection, Database
|
|
from ...core.errors import TokenAlreadySpentError
|
|
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:
|
|
spent_proofs = await self.crud.get_proofs_used(db=self.db, Ys=Ys, conn=conn)
|
|
proofs_spent_dict = {p.Y: p for p in spent_proofs}
|
|
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
|
|
|
|
async def _verify_proofs_spendable(
|
|
self, proofs: List[Proof], conn: Optional[Connection] = None
|
|
):
|
|
"""Checks the database to see if any of the proofs are already spent.
|
|
|
|
Args:
|
|
proofs (List[Proof]): Proofs to verify
|
|
conn (Optional[Connection]): Database connection to use. Defaults to None.
|
|
|
|
Raises:
|
|
TokenAlreadySpentError: If any of the proofs are already spent
|
|
"""
|
|
async with self.db.get_connection(conn) as conn:
|
|
if not len(await self._get_proofs_spent([p.Y for p in proofs], conn)) == 0:
|
|
raise TokenAlreadySpentError()
|