burn all spent tokens with cashu burn -a

This commit is contained in:
callebtc
2022-09-17 23:26:51 +03:00
parent fac578b956
commit f02ac8d3ee
5 changed files with 57 additions and 25 deletions

View File

@@ -144,7 +144,7 @@ async def melt(payload: MeltPayload):
@app.post("/check") @app.post("/check")
async def check_spendable(payload: CheckPayload): async def check_spendable(payload: CheckPayload):
return {"spendable": await ledger.check_spendable(payload.proofs)} return await ledger.check_spendable(payload.proofs)
@app.post("/split") @app.post("/split")

View File

@@ -13,9 +13,14 @@ from core.secp import PrivateKey, PublicKey
from core.settings import LIGHTNING, MAX_ORDER from core.settings import LIGHTNING, MAX_ORDER
from core.split import amount_split from core.split import amount_split
from lightning import WALLET from lightning import WALLET
from mint.crud import (get_lightning_invoice, get_proofs_used, from mint.crud import (
invalidate_proof, store_lightning_invoice, get_lightning_invoice,
store_promise, update_lightning_invoice) get_proofs_used,
invalidate_proof,
store_lightning_invoice,
store_promise,
update_lightning_invoice,
)
class Ledger: class Ledger:
@@ -219,9 +224,7 @@ class Ledger:
async def check_spendable(self, proofs: List[Proof]): async def check_spendable(self, proofs: List[Proof]):
"""Checks if all provided proofs are valid and still spendable (i.e. have not been spent).""" """Checks if all provided proofs are valid and still spendable (i.e. have not been spent)."""
if not all([self._check_spendable(p) for p in proofs]): return {i: self._check_spendable(p) for i, p in enumerate(proofs)}
return False
return True
async def split( async def split(
self, proofs: List[Proof], amount: int, output_data: List[BlindedMessage] self, proofs: List[Proof], amount: int, output_data: List[BlindedMessage]

View File

@@ -16,6 +16,7 @@ from core.helpers import fee_reserve
from core.migrations import migrate_databases from core.migrations import migrate_databases
from core.settings import LIGHTNING, MINT_URL from core.settings import LIGHTNING, MINT_URL
from wallet import migrations from wallet import migrations
from wallet.crud import get_reserved_proofs
from wallet.wallet import Wallet as Wallet from wallet.wallet import Wallet as Wallet
@@ -121,14 +122,23 @@ async def receive(ctx, token: str):
@cli.command("burn", help="Burn spent tokens.") @cli.command("burn", help="Burn spent tokens.")
@click.argument("token", type=str) @click.argument("token", required=False, type=str)
@click.option("--all", "-a", default=False, is_flag=True, help="Burn all spent tokens.")
@click.pass_context @click.pass_context
@coro @coro
async def burn(ctx, token: str): async def burn(ctx, token: str, all: bool):
wallet: Wallet = ctx.obj["WALLET"] wallet: Wallet = ctx.obj["WALLET"]
await init_wallet(wallet) await init_wallet(wallet)
if not (all or token) or (token and all):
print("Error: enter a token or use --all to burn all pending tokens.")
return
if all:
proofs = await get_reserved_proofs(wallet.db)
else:
proofs = [
Proof.from_dict(p) for p in json.loads(base64.urlsafe_b64decode(token))
]
wallet.status() wallet.status()
proofs = [Proof.from_dict(p) for p in json.loads(base64.urlsafe_b64decode(token))]
await wallet.invalidate(proofs) await wallet.invalidate(proofs)
wallet.status() wallet.status()

View File

@@ -38,6 +38,20 @@ async def get_proofs(
return [Proof.from_row(r) for r in rows] return [Proof.from_row(r) for r in rows]
async def get_reserved_proofs(
db: Database,
conn: Optional[Connection] = None,
):
rows = await (conn or db).fetchall(
"""
SELECT * from proofs
WHERE reserved
"""
)
return [Proof.from_row(r) for r in rows]
async def invalidate_proof( async def invalidate_proof(
proof: Proof, proof: Proof,
db: Database, db: Database,

View File

@@ -4,13 +4,19 @@ from typing import List
import requests import requests
import core.b_dhke as b_dhke import core.b_dhke as b_dhke
from core.base import (BlindedMessage, BlindedSignature, CheckPayload, from core.base import (
MeltPayload, MintPayloads, Proof, SplitPayload) BlindedMessage,
BlindedSignature,
CheckPayload,
MeltPayload,
MintPayloads,
Proof,
SplitPayload,
)
from core.db import Database from core.db import Database
from core.secp import PublicKey from core.secp import PublicKey
from core.split import amount_split from core.split import amount_split
from wallet.crud import (get_proofs, invalidate_proof, store_proof, from wallet.crud import get_proofs, invalidate_proof, store_proof, update_proof_reserved
update_proof_reserved)
class LedgerAPI: class LedgerAPI:
@@ -113,9 +119,8 @@ class LedgerAPI:
self.url + "/check", self.url + "/check",
json=payload.dict(), json=payload.dict(),
).json() ).json()
if "spendable" in return_dict and return_dict["spendable"]:
return True return return_dict
return False
async def pay_lightning(self, proofs: List[Proof], amount: int, invoice: str): async def pay_lightning(self, proofs: List[Proof], amount: int, invoice: str):
payload = MeltPayload(proofs=proofs, amount=amount, invoice=invoice) payload = MeltPayload(proofs=proofs, amount=amount, invoice=invoice)
@@ -197,14 +202,14 @@ class Wallet(LedgerAPI):
return await super().check_spendable(proofs) return await super().check_spendable(proofs)
async def invalidate(self, proofs): async def invalidate(self, proofs):
# first we make sure that the server has invalidated these proofs """Invalidates all spendable tokens supplied in proofs."""
if await self.check_spendable(proofs): spendables = await self.check_spendable(proofs)
raise Exception("tokens not yet spent.") invalidated_proofs = []
for idx, spendable in spendables.items():
# TODO: check with server if they were redeemed already if not spendable:
for proof in proofs: invalidated_proofs.append(proofs[int(idx)])
await invalidate_proof(proof, db=self.db) await invalidate_proof(proofs[int(idx)], db=self.db)
invalidate_secrets = [p["secret"] for p in proofs] invalidate_secrets = [p["secret"] for p in invalidated_proofs]
self.proofs = list( self.proofs = list(
filter(lambda p: p["secret"] not in invalidate_secrets, self.proofs) filter(lambda p: p["secret"] not in invalidate_secrets, self.proofs)
) )