This commit is contained in:
callebtc
2022-10-09 17:51:37 +02:00
parent b7361145e0
commit e4747910c9
5 changed files with 28 additions and 24 deletions

View File

@@ -1,9 +1,15 @@
import asyncio import asyncio
from functools import partial, wraps from functools import partial, wraps
from typing import List
from cashu.core.base import Proof
from cashu.core.settings import LIGHTNING_FEE_PERCENT, LIGHTNING_RESERVE_FEE_MIN from cashu.core.settings import LIGHTNING_FEE_PERCENT, LIGHTNING_RESERVE_FEE_MIN
def sum_proofs(proofs: List[Proof]):
return sum([p.amount for p in proofs])
def async_wrap(func): def async_wrap(func):
@wraps(func) @wraps(func)
async def run(*args, loop=None, executor=None, **kwargs): async def run(*args, loop=None, executor=None, **kwargs):

View File

@@ -19,7 +19,7 @@ from cashu.core.base import (
) )
from cashu.core.crypto import derive_keys, derive_keyset_id, derive_pubkeys from cashu.core.crypto import derive_keys, derive_keyset_id, derive_pubkeys
from cashu.core.db import Database from cashu.core.db import Database
from cashu.core.helpers import fee_reserve from cashu.core.helpers import fee_reserve, sum_proofs
from cashu.core.script import verify_script from cashu.core.script import verify_script
from cashu.core.secp import PublicKey from cashu.core.secp import PublicKey
from cashu.core.settings import LIGHTNING, MAX_ORDER from cashu.core.settings import LIGHTNING, MAX_ORDER
@@ -45,6 +45,7 @@ class Ledger:
self.db: Database = Database("mint", db) self.db: Database = Database("mint", db)
async def load_used_proofs(self): async def load_used_proofs(self):
"""Load all used proofs from database."""
self.proofs_used = set(await get_proofs_used(db=self.db)) self.proofs_used = set(await get_proofs_used(db=self.db))
async def init_keysets(self): async def init_keysets(self):
@@ -93,12 +94,8 @@ class Ledger:
"""Checks whether the proof was already spent.""" """Checks whether the proof was already spent."""
return not proof.secret in self.proofs_used return not proof.secret in self.proofs_used
def _verify_secret_or_script(self, proof: Proof):
if proof.secret and proof.script:
raise Exception("secret and script present at the same time.")
return True
def _verify_secret_criteria(self, proof: Proof): def _verify_secret_criteria(self, proof: Proof):
"""Verifies that a secret is present"""
if proof.secret is None or proof.secret == "": if proof.secret is None or proof.secret == "":
raise Exception("no secret in proof.") raise Exception("no secret in proof.")
return True return True
@@ -213,7 +210,7 @@ class Ledger:
invoice: Invoice = await get_lightning_invoice(payment_hash, db=self.db) invoice: Invoice = await get_lightning_invoice(payment_hash, db=self.db)
if invoice.issued: if invoice.issued:
raise Exception("tokens already issued for this invoice.") raise Exception("tokens already issued for this invoice.")
total_requested = sum([amount for amount in amounts]) total_requested = sum(amounts)
if total_requested > invoice.amount: if total_requested > invoice.amount:
raise Exception( raise Exception(
f"Requested amount too high: {total_requested}. Invoice amount: {invoice.amount}" f"Requested amount too high: {total_requested}. Invoice amount: {invoice.amount}"
@@ -287,7 +284,7 @@ class Ledger:
if not all([self._verify_proof(p) for p in proofs]): if not all([self._verify_proof(p) for p in proofs]):
raise Exception("could not verify proofs.") raise Exception("could not verify proofs.")
total_provided = sum([p["amount"] for p in proofs]) total_provided = sum_proofs(proofs)
invoice_obj = bolt11.decode(invoice) invoice_obj = bolt11.decode(invoice)
amount = math.ceil(invoice_obj.amount_msat / 1000) amount = math.ceil(invoice_obj.amount_msat / 1000)
fees_msat = await self.check_fees(invoice) fees_msat = await self.check_fees(invoice)
@@ -319,7 +316,7 @@ class Ledger:
self, proofs: List[Proof], amount: int, outputs: List[BlindedMessage] self, proofs: List[Proof], amount: int, outputs: List[BlindedMessage]
): ):
"""Consumes proofs and prepares new promises based on the amount split.""" """Consumes proofs and prepares new promises based on the amount split."""
total = sum([p.amount for p in proofs]) total = sum_proofs(proofs)
# verify that amount is kosher # verify that amount is kosher
self._verify_split_amount(amount) self._verify_split_amount(amount)

View File

@@ -81,11 +81,17 @@ async def melt(payload: MeltRequest):
@router.post("/check") @router.post("/check")
async def check_spendable(payload: CheckRequest): async def check_spendable(payload: CheckRequest):
"""Check whether a secret has been spent already or not."""
return await ledger.check_spendable(payload.proofs) return await ledger.check_spendable(payload.proofs)
@router.post("/checkfees") @router.post("/checkfees")
async def check_fees(payload: CheckFeesRequest): async def check_fees(payload: CheckFeesRequest):
"""
Responds with the fees necessary to pay a Lightning invoice.
Used by wallets for figuring out the fees they need to supply.
This is can be useful for checking whether an invoice is internal (Cashu-to-Cashu).
"""
fees_msat = await ledger.check_fees(payload.pr) fees_msat = await ledger.check_fees(payload.pr)
return CheckFeesResponse(fee=fees_msat / 1000) return CheckFeesResponse(fee=fees_msat / 1000)

View File

@@ -18,7 +18,7 @@ from loguru import logger
import cashu.core.bolt11 as bolt11 import cashu.core.bolt11 as bolt11
from cashu.core.base import Proof from cashu.core.base import Proof
from cashu.core.bolt11 import Invoice, decode from cashu.core.bolt11 import Invoice, decode
from cashu.core.helpers import fee_reserve from cashu.core.helpers import fee_reserve, sum_proofs
from cashu.core.migrations import migrate_databases from cashu.core.migrations import migrate_databases
from cashu.core.settings import CASHU_DIR, DEBUG, ENV_FILE, LIGHTNING, MINT_URL, VERSION from cashu.core.settings import CASHU_DIR, DEBUG, ENV_FILE, LIGHTNING, MINT_URL, VERSION
from cashu.wallet import migrations from cashu.wallet import migrations
@@ -267,7 +267,7 @@ async def pending(ctx):
int(grouped_proofs[0].time_reserved) int(grouped_proofs[0].time_reserved)
).strftime("%Y-%m-%d %H:%M:%S") ).strftime("%Y-%m-%d %H:%M:%S")
print( print(
f"#{i} Amount: {sum([p['amount'] for p in grouped_proofs])} sat Time: {reserved_date} ID: {key}\n" f"#{i} Amount: {sum_proofs(grouped_proofs)} sat Time: {reserved_date} ID: {key}\n"
) )
print(f"With secret: {coin}\n\nSecretless: {coin_hidden_secret}\n") print(f"With secret: {coin}\n\nSecretless: {coin_hidden_secret}\n")
print(f"--------------------------\n") print(f"--------------------------\n")

View File

@@ -22,6 +22,7 @@ from cashu.core.base import (
WalletKeyset, WalletKeyset,
) )
from cashu.core.db import Database from cashu.core.db import Database
from cashu.core.helpers import sum_proofs
from cashu.core.script import ( from cashu.core.script import (
step0_carol_checksig_redeemscrip, step0_carol_checksig_redeemscrip,
step0_carol_privkey, step0_carol_privkey,
@@ -190,7 +191,7 @@ class LedgerAPI:
If scnd_secret is provided, the wallet will create blinded secrets with those to attach a If scnd_secret is provided, the wallet will create blinded secrets with those to attach a
predefined spending condition to the tokens they want to send.""" predefined spending condition to the tokens they want to send."""
total = sum([p["amount"] for p in proofs]) total = sum_proofs(proofs)
frst_amt, scnd_amt = total - amount, amount frst_amt, scnd_amt = total - amount, amount
frst_outputs = amount_split(frst_amt) frst_outputs = amount_split(frst_amt)
scnd_outputs = amount_split(scnd_amt) scnd_outputs = amount_split(scnd_amt)
@@ -312,12 +313,6 @@ class Wallet(LedgerAPI):
for proof in proofs: for proof in proofs:
await store_proof(proof, db=self.db) await store_proof(proof, db=self.db)
@staticmethod
def _sum_proofs(proofs: List[Proof], available_only=False):
if available_only:
return sum([p.amount for p in proofs if not p.reserved])
return sum([p.amount for p in proofs])
@staticmethod @staticmethod
def _get_proofs_per_keyset(proofs: List[Proof]): def _get_proofs_per_keyset(proofs: List[Proof]):
return {key: list(group) for key, group in groupby(proofs, lambda p: p.id)} return {key: list(group) for key, group in groupby(proofs, lambda p: p.id)}
@@ -345,7 +340,7 @@ class Wallet(LedgerAPI):
# attach unlock scripts to proofs # attach unlock scripts to proofs
for p in proofs: for p in proofs:
p.script = P2SHScript(script=scnd_script, signature=scnd_siganture) p.script = P2SHScript(script=scnd_script, signature=scnd_siganture)
return await self.split(proofs, sum(p["amount"] for p in proofs)) return await self.split(proofs, sum_proofs(proofs))
async def split( async def split(
self, self,
@@ -405,7 +400,7 @@ class Wallet(LedgerAPI):
if scnd_secret: if scnd_secret:
logger.debug(f"Spending conditions: {scnd_secret}") logger.debug(f"Spending conditions: {scnd_secret}")
spendable_proofs = await self._get_spendable_proofs(proofs) spendable_proofs = await self._get_spendable_proofs(proofs)
if sum([p.amount for p in spendable_proofs]) < amount: if sum_proofs(spendable_proofs) < amount:
raise Exception("balance too low.") raise Exception("balance too low.")
return await self.split( return await self.split(
[p for p in spendable_proofs if not p.reserved], amount, scnd_secret [p for p in spendable_proofs if not p.reserved], amount, scnd_secret
@@ -453,11 +448,11 @@ class Wallet(LedgerAPI):
@property @property
def balance(self): def balance(self):
return sum(p["amount"] for p in self.proofs) return sum_proofs(self.proofs)
@property @property
def available_balance(self): def available_balance(self):
return sum(p["amount"] for p in self.proofs if not p.reserved) return sum_proofs([p for p in self.proofs if not p.reserved])
def status(self): def status(self):
print( print(
@@ -467,8 +462,8 @@ class Wallet(LedgerAPI):
def balance_per_keyset(self): def balance_per_keyset(self):
return { return {
key: { key: {
"balance": self._sum_proofs(proofs), "balance": sum_proofs(proofs),
"available": self._sum_proofs(proofs, available_only=True), "available": sum_proofs([p for p in proofs if not p.reserved]),
} }
for key, proofs in self._get_proofs_per_keyset(self.proofs).items() for key, proofs in self._get_proofs_per_keyset(self.proofs).items()
} }