diff --git a/core/base.py b/core/base.py index c718dc9..131d536 100644 --- a/core/base.py +++ b/core/base.py @@ -102,8 +102,6 @@ class SplitPayload(BaseModel): class CheckPayload(BaseModel): proofs: List[Proof] - amount: int - output_data: MintPayloads class MeltPayload(BaseModel): diff --git a/mint/app.py b/mint/app.py index 5aa4318..8610b6b 100644 --- a/mint/app.py +++ b/mint/app.py @@ -10,7 +10,7 @@ from fastapi import FastAPI from loguru import logger import core.settings as settings -from core.base import MintPayloads, SplitPayload, MeltPayload, Proof +from core.base import MintPayloads, SplitPayload, MeltPayload, CheckPayload from core.settings import MINT_PRIVATE_KEY, MINT_SERVER_HOST, MINT_SERVER_PORT from lightning import WALLET from mint.ledger import Ledger @@ -144,6 +144,11 @@ async def melt(payload: MeltPayload): """ +@app.post("/check") +async def check_spendable(payload: CheckPayload): + return {"spendable": await ledger.check_spendable(payload.proofs)} + + @app.post("/split") async def split(payload: SplitPayload): """ @@ -154,10 +159,14 @@ async def split(payload: SplitPayload): amount = payload.amount output_data = payload.output_data.blinded_messages try: - fst_promises, snd_promises = await ledger.split(proofs, amount, output_data) - return {"fst": fst_promises, "snd": snd_promises} + split_return = await ledger.split(proofs, amount, output_data) except Exception as exc: return {"error": str(exc)} + if not split_return: + """There was a problem with the split""" + raise Exception("could not split tokens.") + fst_promises, snd_promises = split_return + return {"fst": fst_promises, "snd": snd_promises} @click.command( diff --git a/mint/ledger.py b/mint/ledger.py index caab330..15c43e5 100644 --- a/mint/ledger.py +++ b/mint/ledger.py @@ -72,9 +72,13 @@ class Ledger: await store_promise(amount, B_x=B_.x, B_y=B_.y, C_x=C_.x, C_y=C_.y, db=self.db) return BlindedSignature(amount=amount, C_=BasePoint(x=C_.x, y=C_.y)) + def _check_spendable(self, proof: Proof): + """Checks whether the proof was already spent.""" + return not proof.secret in self.proofs_used + def _verify_proof(self, proof: Proof): """Verifies that the proof of promise was issued by this ledger.""" - if proof.secret in self.proofs_used: + if not self._check_spendable(proof): raise Exception(f"tokens already spent. Secret: {proof.secret}") secret_key = self.keys[proof.amount] # Get the correct key to check against C = Point(proof.C.x, proof.C.y, secp256k1) @@ -202,8 +206,9 @@ class Ledger: 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]): + if not all([self._check_spendable(p) for p in proofs]): return False + return True async def split( self, proofs: List[Proof], amount: int, output_data: List[BlindedMessage] @@ -211,7 +216,7 @@ class Ledger: """Consumes proofs and prepares new promises based on the amount split.""" self._verify_split_amount(amount) # Verify proofs are valid - if await self.check_spendable(proofs) == False: + if not all([self._verify_proof(p) for p in proofs]): return False total = sum([p["amount"] for p in proofs]) diff --git a/wallet/wallet.py b/wallet/wallet.py index 543a843..cdfb71d 100644 --- a/wallet/wallet.py +++ b/wallet/wallet.py @@ -12,6 +12,7 @@ from core.base import ( Proof, SplitPayload, BlindedSignature, + CheckPayload, ) from core.db import Database from core.split import amount_split @@ -112,11 +113,15 @@ class LedgerAPI: return fst_proofs, snd_proofs - def check_spendable(self, proofs): - promises_dict = requests.post( + async def check_spendable(self, proofs: List[Proof]): + payload = CheckPayload(proofs=proofs) + return_dict = requests.post( self.url + "/check", - json=proofs.dict(), + json=payload.dict(), ).json() + if "spendable" in return_dict and return_dict["spendable"]: + return True + return False class Wallet(LedgerAPI): @@ -178,16 +183,12 @@ class Wallet(LedgerAPI): await update_proof_reserved(proof, reserved=reserved, db=self.db) async def check_spendable(self, proofs): - await super().check_spendable(proofs) + return await super().check_spendable(proofs) async def invalidate(self, proofs): # first we make sure that the server has invalidated these proofs - try: - await self.split(proofs, sum(p["amount"] for p in proofs)) - except Exception as exc: - assert exc.args[0].startswith("Error: tokens already spent."), Exception( - "invalidating unspent tokens" - ) + if await self.check_spendable(proofs): + raise Exception("tokens not yet spent.") # TODO: check with server if they were redeemed already for proof in proofs: