diff --git a/core/base.py b/core/base.py index 3e717a0..c718dc9 100644 --- a/core/base.py +++ b/core/base.py @@ -100,6 +100,12 @@ class SplitPayload(BaseModel): output_data: MintPayloads +class CheckPayload(BaseModel): + proofs: List[Proof] + amount: int + output_data: MintPayloads + + class MeltPayload(BaseModel): proofs: List[Proof] amount: int diff --git a/core/db.py b/core/db.py index c691ca5..dc7fb9d 100644 --- a/core/db.py +++ b/core/db.py @@ -119,14 +119,7 @@ class Database(Compat): psycopg2.extensions.register_type( psycopg2.extensions.new_type( - (1184, 1114), - "TIMESTAMP2INT", - _parse_timestamp - # lambda value, curs: time.mktime( - # datetime.datetime.strptime( - # value, "%Y-%m-%d %H:%M:%S.%f" - # ).timetuple() - # ), + (1184, 1114), "TIMESTAMP2INT", _parse_timestamp ) ) else: diff --git a/mint/ledger.py b/mint/ledger.py index b0d3795..caab330 100644 --- a/mint/ledger.py +++ b/mint/ledger.py @@ -13,7 +13,7 @@ from core.base import Proof, BlindedMessage, BlindedSignature, BasePoint import core.b_dhke as b_dhke from core.base import Invoice from core.db import Database -from core.settings import MAX_ORDER +from core.settings import MAX_ORDER, LIGHTNING from core.split import amount_split from lightning import WALLET from mint.crud import ( @@ -179,7 +179,9 @@ class Ledger: async def mint(self, B_s, amounts, payment_hash=None): """Mints a promise for coins for B_.""" # check if lightning invoice was paid - if payment_hash and not await self._check_lightning_invoice(payment_hash): + if LIGHTNING and ( + payment_hash and not await self._check_lightning_invoice(payment_hash) + ): raise Exception("Lightning invoice not paid yet.") for amount in amounts: @@ -192,13 +194,24 @@ class Ledger: promises += [await self._generate_promise(amount, B_) for a in split] return promises + async def melt(self, proofs: List[Proof], amount: int, invoice: str): + """Invalidates proofs and pays a Lightning invoice.""" + if not LIGHTNING: + raise Exception("Lightning is not active.") + return 0 + + async def check_spendable(self, proofs: List[Proof]): + """Checks if all provided proofs are valid and still spendable (i.e. have not been spent).""" + if not all([self._verify_proof(p) for p in proofs]): + return False + async def split( self, proofs: List[Proof], amount: int, output_data: List[BlindedMessage] ): """Consumes proofs and prepares new promises based on the amount split.""" self._verify_split_amount(amount) # Verify proofs are valid - if not all([self._verify_proof(p) for p in proofs]): + if await self.check_spendable(proofs) == False: return False total = sum([p["amount"] for p in proofs]) diff --git a/tests/test_wallet.py b/tests/test_wallet.py index c5cd4bd..c7cd235 100644 --- a/tests/test_wallet.py +++ b/tests/test_wallet.py @@ -52,10 +52,6 @@ async def run_test(): wallet1.status() # Error: We try to double-spend by providing a valid proof twice - # try: - # await wallet1.split(wallet1.proofs + proofs, 20), - # except Exception as exc: - # print(exc.args[0]) await assert_err( wallet1.split(wallet1.proofs + proofs, 20), f"Error: tokens already spent. Secret: {proofs[0]['secret']}", diff --git a/wallet/cashu.py b/wallet/cashu.py index 45298cf..d753f17 100755 --- a/wallet/cashu.py +++ b/wallet/cashu.py @@ -122,7 +122,7 @@ async def receive(ctx, token: str): @click.argument("token", type=str) @click.pass_context @coro -async def receive(ctx, token: str): +async def burn(ctx, token: str): wallet: Wallet = ctx.obj["WALLET"] await init_wallet(wallet) wallet.status() diff --git a/wallet/wallet.py b/wallet/wallet.py index 81621c2..543a843 100644 --- a/wallet/wallet.py +++ b/wallet/wallet.py @@ -112,6 +112,12 @@ class LedgerAPI: return fst_proofs, snd_proofs + def check_spendable(self, proofs): + promises_dict = requests.post( + self.url + "/check", + json=proofs.dict(), + ).json() + class Wallet(LedgerAPI): """Minimal wallet wrapper.""" @@ -154,10 +160,9 @@ class Wallet(LedgerAPI): filter(lambda p: p["secret"] not in used_secrets, self.proofs) ) self.proofs += fst_proofs + snd_proofs - + await self._store_proofs(fst_proofs + snd_proofs) for proof in proofs: await invalidate_proof(proof, db=self.db) - await self._store_proofs(fst_proofs + snd_proofs) return fst_proofs, snd_proofs async def split_to_send(self, proofs: List[Proof], amount): @@ -172,6 +177,9 @@ class Wallet(LedgerAPI): proof.reserved = True await update_proof_reserved(proof, reserved=reserved, db=self.db) + async def check_spendable(self, proofs): + await super().check_spendable(proofs) + async def invalidate(self, proofs): # first we make sure that the server has invalidated these proofs try: