mirror of
https://github.com/aljazceru/nutshell.git
synced 2025-12-20 18:44:20 +01:00
Balance Views Grouped By Keyset (#652)
* balance view per keyset + relative changes.
Still lacking: settings changes
* import unit
* fix 0 balance
* settings
---------
Co-authored-by: callebtc <93376500+callebtc@users.noreply.github.com>
This commit is contained in:
@@ -119,6 +119,7 @@ class LedgerCrud(ABC):
|
|||||||
@abstractmethod
|
@abstractmethod
|
||||||
async def get_balance(
|
async def get_balance(
|
||||||
self,
|
self,
|
||||||
|
keyset: MintKeyset,
|
||||||
db: Database,
|
db: Database,
|
||||||
conn: Optional[Connection] = None,
|
conn: Optional[Connection] = None,
|
||||||
) -> int: ...
|
) -> int: ...
|
||||||
@@ -668,15 +669,22 @@ class LedgerCrudSqlite(LedgerCrud):
|
|||||||
|
|
||||||
async def get_balance(
|
async def get_balance(
|
||||||
self,
|
self,
|
||||||
|
keyset: MintKeyset,
|
||||||
db: Database,
|
db: Database,
|
||||||
conn: Optional[Connection] = None,
|
conn: Optional[Connection] = None,
|
||||||
) -> int:
|
) -> int:
|
||||||
row = await (conn or db).fetchone(
|
row = await (conn or db).fetchone(
|
||||||
f"""
|
f"""
|
||||||
SELECT * from {db.table_with_schema('balance')}
|
SELECT balance FROM {db.table_with_schema('balance')}
|
||||||
"""
|
WHERE keyset = :keyset
|
||||||
|
""",
|
||||||
|
{
|
||||||
|
"keyset": keyset.id,
|
||||||
|
},
|
||||||
)
|
)
|
||||||
assert row, "Balance not found"
|
|
||||||
|
if row is None:
|
||||||
|
return 0
|
||||||
|
|
||||||
# sqlalchemy index of first element
|
# sqlalchemy index of first element
|
||||||
key = next(iter(row))
|
key = next(iter(row))
|
||||||
|
|||||||
@@ -322,9 +322,9 @@ class Ledger(LedgerVerification, LedgerSpendingConditions, LedgerTasks, LedgerFe
|
|||||||
raise KeysetError("no public keys for this keyset")
|
raise KeysetError("no public keys for this keyset")
|
||||||
return {a: p.serialize().hex() for a, p in keyset.public_keys.items()}
|
return {a: p.serialize().hex() for a, p in keyset.public_keys.items()}
|
||||||
|
|
||||||
async def get_balance(self) -> int:
|
async def get_balance(self, keyset: MintKeyset) -> int:
|
||||||
"""Returns the balance of the mint."""
|
"""Returns the balance of the mint."""
|
||||||
return await self.crud.get_balance(db=self.db)
|
return await self.crud.get_balance(keyset=keyset, db=self.db)
|
||||||
|
|
||||||
# ------- ECASH -------
|
# ------- ECASH -------
|
||||||
|
|
||||||
@@ -451,8 +451,13 @@ class Ledger(LedgerVerification, LedgerSpendingConditions, LedgerTasks, LedgerFe
|
|||||||
):
|
):
|
||||||
raise NotAllowedError("Backend does not support descriptions.")
|
raise NotAllowedError("Backend does not support descriptions.")
|
||||||
|
|
||||||
if settings.mint_max_balance:
|
# MINT_MAX_BALANCE refers to sat (for now)
|
||||||
balance = await self.get_balance()
|
if settings.mint_max_balance and unit == Unit.sat:
|
||||||
|
# get next active keyset for unit
|
||||||
|
active_keyset: MintKeyset = next(
|
||||||
|
filter(lambda k: k.active and k.unit == unit, self.keysets.values())
|
||||||
|
)
|
||||||
|
balance = await self.get_balance(active_keyset)
|
||||||
if balance + quote_request.amount > settings.mint_max_balance:
|
if balance + quote_request.amount > settings.mint_max_balance:
|
||||||
raise NotAllowedError("Mint has reached maximum balance.")
|
raise NotAllowedError("Mint has reached maximum balance.")
|
||||||
|
|
||||||
|
|||||||
@@ -868,3 +868,43 @@ async def m025_add_amounts_to_keysets(db: Database):
|
|||||||
await conn.execute(
|
await conn.execute(
|
||||||
f"UPDATE {db.table_with_schema('keysets')} SET amounts = '[]'"
|
f"UPDATE {db.table_with_schema('keysets')} SET amounts = '[]'"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
async def m026_keyset_specific_balance_views(db: Database):
|
||||||
|
async with db.connect() as conn:
|
||||||
|
await drop_balance_views(db, conn)
|
||||||
|
await conn.execute(
|
||||||
|
f"""
|
||||||
|
CREATE VIEW {db.table_with_schema('balance_issued')} AS
|
||||||
|
SELECT id AS keyset, COALESCE(s, 0) AS balance FROM (
|
||||||
|
SELECT id, SUM(amount) AS s
|
||||||
|
FROM {db.table_with_schema('promises')}
|
||||||
|
WHERE amount > 0
|
||||||
|
GROUP BY id
|
||||||
|
);
|
||||||
|
"""
|
||||||
|
)
|
||||||
|
await conn.execute(
|
||||||
|
f"""
|
||||||
|
CREATE VIEW {db.table_with_schema('balance_redeemed')} AS
|
||||||
|
SELECT id AS keyset, COALESCE(s, 0) AS balance FROM (
|
||||||
|
SELECT id, SUM(amount) AS s
|
||||||
|
FROM {db.table_with_schema('proofs_used')}
|
||||||
|
WHERE amount > 0
|
||||||
|
GROUP BY id
|
||||||
|
);
|
||||||
|
"""
|
||||||
|
)
|
||||||
|
await conn.execute(
|
||||||
|
f"""
|
||||||
|
CREATE VIEW {db.table_with_schema('balance')} AS
|
||||||
|
SELECT keyset, s_issued - s_used AS balance FROM (
|
||||||
|
SELECT bi.keyset AS keyset,
|
||||||
|
bi.balance AS s_issued,
|
||||||
|
COALESCE(bu.balance, 0) AS s_used
|
||||||
|
FROM {db.table_with_schema('balance_issued')} bi
|
||||||
|
LEFT OUTER JOIN {db.table_with_schema('balance_redeemed')} bu
|
||||||
|
ON bi.keyset = bu.keyset
|
||||||
|
);
|
||||||
|
"""
|
||||||
|
)
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ from typing import List
|
|||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
from cashu.core.base import BlindedMessage, Proof
|
from cashu.core.base import BlindedMessage, MintKeyset, Proof, Unit
|
||||||
from cashu.core.crypto.b_dhke import step1_alice
|
from cashu.core.crypto.b_dhke import step1_alice
|
||||||
from cashu.core.helpers import calculate_number_of_blank_outputs
|
from cashu.core.helpers import calculate_number_of_blank_outputs
|
||||||
from cashu.core.models import PostMintQuoteRequest
|
from cashu.core.models import PostMintQuoteRequest
|
||||||
@@ -218,7 +218,11 @@ async def test_generate_change_promises_returns_empty_if_no_outputs(ledger: Ledg
|
|||||||
|
|
||||||
@pytest.mark.asyncio
|
@pytest.mark.asyncio
|
||||||
async def test_get_balance(ledger: Ledger):
|
async def test_get_balance(ledger: Ledger):
|
||||||
balance = await ledger.get_balance()
|
unit = Unit["sat"]
|
||||||
|
active_keyset: MintKeyset = next(
|
||||||
|
filter(lambda k: k.active and k.unit == unit, ledger.keysets.values())
|
||||||
|
)
|
||||||
|
balance = await ledger.get_balance(active_keyset)
|
||||||
assert balance == 0
|
assert balance == 0
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user