[Refactor] Mint: remove output.id optional (#504)

* remove output.id optional

* asserts

* wip

* wip

* working
This commit is contained in:
callebtc
2024-04-10 12:23:53 +02:00
committed by GitHub
parent 3b2f1aa6f4
commit 19de10bfea
10 changed files with 180 additions and 125 deletions

View File

@@ -172,7 +172,7 @@ This command runs the mint on your local computer. Skip this step if you want to
## Docker
```
docker run -d -p 3338:3338 --name nutshell -e MINT_BACKEND_BOLT11_SAT=FakeWallet -e MINT_LISTEN_HOST=0.0.0.0 -e MINT_LISTEN_PORT=3338 -e MINT_PRIVATE_KEY=TEST_PRIVATE_KEY cashubtc/nutshell:0.15.2 poetry run mint
docker run -d -p 3338:3338 --name nutshell -e MINT_BACKEND_BOLT11_SAT=FakeWallet -e MINT_LISTEN_HOST=0.0.0.0 -e MINT_LISTEN_PORT=3338 -e MINT_PRIVATE_KEY=TEST_PRIVATE_KEY cashubtc/nutshell:0.15.3 poetry run mint
```
## From this repository

View File

@@ -101,12 +101,12 @@ class Proof(BaseModel):
time_created: Union[None, str] = ""
time_reserved: Union[None, str] = ""
derivation_path: Union[None, str] = "" # derivation path of the proof
mint_id: Union[None, str] = (
None # holds the id of the mint operation that created this proof
)
melt_id: Union[None, str] = (
None # holds the id of the melt operation that destroyed this proof
)
mint_id: Union[
None, str
] = None # holds the id of the mint operation that created this proof
melt_id: Union[
None, str
] = None # holds the id of the melt operation that destroyed this proof
def __init__(self, **data):
super().__init__(**data)
@@ -161,20 +161,13 @@ class Proof(BaseModel):
return HTLCWitness.from_witness(self.witness).preimage
class Proofs(BaseModel):
# NOTE: not used in Pydantic validation
__root__: List[Proof]
class BlindedMessage(BaseModel):
"""
Blinded message or blinded secret or "output" which is to be signed by the mint
"""
amount: int
id: Optional[
str
] # DEPRECATION: Only Optional for backwards compatibility with old clients < 0.15 for deprecated API route.
id: str
B_: str # Hex-encoded blinded message
witness: Union[str, None] = None # witnesses (used for P2PK with SIG_ALL)
@@ -204,11 +197,6 @@ class BlindedSignature(BaseModel):
)
class BlindedMessages(BaseModel):
# NOTE: not used in Pydantic validation
__root__: List[BlindedMessage] = []
# ------- LIGHTNING INVOICE -------
@@ -341,6 +329,19 @@ class GetInfoResponse_deprecated(BaseModel):
parameter: Optional[dict] = None
class BlindedMessage_Deprecated(BaseModel):
# Same as BlindedMessage, but without the id field
amount: int
B_: str # Hex-encoded blinded message
id: Optional[str] = None
witness: Union[str, None] = None # witnesses (used for P2PK with SIG_ALL)
@property
def p2pksigs(self) -> List[str]:
assert self.witness, "Witness missing in output"
return P2PKWitness.from_witness(self.witness).signatures
# ------- API: KEYS -------
@@ -407,7 +408,7 @@ class GetMintResponse_deprecated(BaseModel):
class PostMintRequest_deprecated(BaseModel):
outputs: List[BlindedMessage] = Field(
outputs: List[BlindedMessage_Deprecated] = Field(
..., max_items=settings.mint_max_request_length
)
@@ -454,7 +455,7 @@ class PostMeltResponse(BaseModel):
class PostMeltRequest_deprecated(BaseModel):
proofs: List[Proof] = Field(..., max_items=settings.mint_max_request_length)
pr: str = Field(..., max_length=settings.mint_max_request_length)
outputs: Union[List[BlindedMessage], None] = Field(
outputs: Union[List[BlindedMessage_Deprecated], None] = Field(
None, max_items=settings.mint_max_request_length
)
@@ -483,7 +484,7 @@ class PostSplitResponse(BaseModel):
class PostSplitRequest_Deprecated(BaseModel):
proofs: List[Proof] = Field(..., max_items=settings.mint_max_request_length)
amount: Optional[int] = None
outputs: List[BlindedMessage] = Field(
outputs: List[BlindedMessage_Deprecated] = Field(
..., max_items=settings.mint_max_request_length
)

View File

@@ -8,7 +8,7 @@ from pydantic import BaseSettings, Extra, Field
env = Env()
VERSION = "0.15.2"
VERSION = "0.15.3"
def find_env_file():
@@ -58,7 +58,7 @@ class MintSettings(CashuSettings):
mint_database: str = Field(default="data/mint")
mint_test_database: str = Field(default="test_data/test_mint")
mint_duplicate_keysets: bool = Field(
mint_duplicate_old_keysets: bool = Field(
default=True,
title="Duplicate keysets",
description=(

View File

@@ -34,6 +34,7 @@ from ..core.crypto.keys import (
from ..core.crypto.secp import PrivateKey, PublicKey
from ..core.db import Connection, Database, get_db_connection
from ..core.errors import (
CashuError,
KeysetError,
KeysetNotFoundError,
LightningError,
@@ -72,7 +73,8 @@ class Ledger(LedgerVerification, LedgerSpendingConditions):
derivation_path="",
crud=LedgerCrudSqlite(),
):
assert seed, "seed not set"
if not seed:
raise Exception("seed not set")
# decrypt seed if seed_decryption_key is set
try:
@@ -189,7 +191,8 @@ class Ledger(LedgerVerification, LedgerSpendingConditions):
Returns:
MintKeyset: Keyset
"""
assert derivation_path, "derivation path not set"
if not derivation_path:
raise Exception("derivation path not set")
seed = seed or self.seed
tmp_keyset_local = MintKeyset(
seed=seed,
@@ -230,7 +233,8 @@ class Ledger(LedgerVerification, LedgerSpendingConditions):
# BEGIN BACKWARDS COMPATIBILITY < 0.15.0
# set the deprecated id
assert keyset.public_keys
if not keyset.public_keys:
raise KeysetError("no public keys for this keyset")
keyset.duplicate_keyset_id = derive_keyset_id_deprecated(keyset.public_keys)
# END BACKWARDS COMPATIBILITY < 0.15.0
@@ -268,17 +272,22 @@ class Ledger(LedgerVerification, LedgerSpendingConditions):
logger.info(f"Current keyset: {self.keyset.id}")
# check that we have a least one active keyset
assert any([k.active for k in self.keysets.values()]), "No active keyset found."
if not any([k.active for k in self.keysets.values()]):
raise KeysetError("No active keyset found.")
# BEGIN BACKWARDS COMPATIBILITY < 0.15.0
# we duplicate new keysets and compute their old keyset id, and
# we duplicate old keysets and compute their new keyset id
if (
duplicate_keysets is None and settings.mint_duplicate_keysets
) or duplicate_keysets:
if duplicate_keysets is not False and (
settings.mint_duplicate_old_keysets or duplicate_keysets
):
for _, keyset in copy.copy(self.keysets).items():
# if keyset.version_tuple >= (0, 15, 3) and not duplicate_keysets:
# # we do not duplicate keysets from version 0.15.3 and above if not forced by duplicate_keysets
# continue
keyset_copy = copy.copy(keyset)
assert keyset_copy.public_keys
if not keyset_copy.public_keys:
raise KeysetError("no public keys for this keyset")
if keyset.version_tuple >= (0, 15):
keyset_copy.id = derive_keyset_id_deprecated(
keyset_copy.public_keys
@@ -296,7 +305,8 @@ class Ledger(LedgerVerification, LedgerSpendingConditions):
if keyset_id and keyset_id not in self.keysets:
raise KeysetNotFoundError()
keyset = self.keysets[keyset_id] if keyset_id else self.keyset
assert keyset.public_keys, KeysetError("no public keys for this keyset")
if not keyset.public_keys:
raise KeysetError("no public keys for this keyset")
return {a: p.serialize().hex() for a, p in keyset.public_keys.items()}
async def get_balance(self) -> int:
@@ -400,7 +410,8 @@ class Ledger(LedgerVerification, LedgerSpendingConditions):
MintQuote: Mint quote object.
"""
logger.trace("called request_mint")
assert quote_request.amount > 0, "amount must be positive"
if not quote_request.amount > 0:
raise TransactionError("amount must be positive")
if settings.mint_max_peg_in and quote_request.amount > settings.mint_max_peg_in:
raise NotAllowedError(
f"Maximum mint amount is {settings.mint_max_peg_in} sat."
@@ -426,9 +437,8 @@ class Ledger(LedgerVerification, LedgerSpendingConditions):
f" {invoice_response.checking_id}"
)
assert (
invoice_response.payment_request and invoice_response.checking_id
), LightningError("could not fetch bolt11 payment request from backend")
if not (invoice_response.payment_request and invoice_response.checking_id):
raise LightningError("could not fetch bolt11 payment request from backend")
# get invoice expiry time
invoice_obj = bolt11.decode(invoice_response.payment_request)
@@ -478,7 +488,8 @@ class Ledger(LedgerVerification, LedgerSpendingConditions):
unit, method = self._verify_and_get_unit_method(quote.unit, quote.method)
if not quote.paid:
assert quote.checking_id, "quote has no checking id"
if not quote.checking_id:
raise CashuError("quote has no checking id")
logger.trace(f"Lightning: checking invoice {quote.checking_id}")
status: PaymentStatus = await self.backends[method][
unit
@@ -518,18 +529,27 @@ class Ledger(LedgerVerification, LedgerSpendingConditions):
await self._verify_outputs(outputs)
sum_amount_outputs = sum([b.amount for b in outputs])
output_units = set([k.unit for k in [self.keysets[o.id] for o in outputs]])
if not len(output_units) == 1:
raise TransactionError("outputs have different units")
output_unit = list(output_units)[0]
self.locks[quote_id] = (
self.locks.get(quote_id) or asyncio.Lock()
) # create a new lock if it doesn't exist
async with self.locks[quote_id]:
quote = await self.get_mint_quote(quote_id=quote_id)
assert quote.paid, QuoteNotPaidError()
assert not quote.issued, "quote already issued"
assert (
quote.amount == sum_amount_outputs
), "amount to mint does not match quote amount"
if quote.expiry:
assert quote.expiry > int(time.time()), "quote expired"
if not quote.paid:
raise QuoteNotPaidError()
if quote.issued:
raise TransactionError("quote already issued")
if not quote.unit == output_unit.name:
raise TransactionError("quote unit does not match output unit")
if not quote.amount == sum_amount_outputs:
raise TransactionError("amount to mint does not match quote amount")
if quote.expiry and quote.expiry > int(time.time()):
raise TransactionError("quote expired")
promises = await self._generate_promises(outputs)
logger.trace("generated promises")
@@ -571,12 +591,19 @@ class Ledger(LedgerVerification, LedgerSpendingConditions):
request=request, db=self.db
)
if mint_quote:
assert request == mint_quote.request, "bolt11 requests do not match"
assert mint_quote.unit == melt_quote.unit, "units do not match"
assert mint_quote.method == method.name, "methods do not match"
assert not mint_quote.paid, "mint quote already paid"
assert not mint_quote.issued, "mint quote already issued"
assert mint_quote.checking_id, "mint quote has no checking id"
if not request == mint_quote.request:
raise TransactionError("bolt11 requests do not match")
if not mint_quote.unit == melt_quote.unit:
raise TransactionError("units do not match")
if not mint_quote.method == method.name:
raise TransactionError("methods do not match")
if mint_quote.paid:
raise TransactionError("mint quote already paid")
if mint_quote.issued:
raise TransactionError("mint quote already issued")
if not mint_quote.checking_id:
raise TransactionError("mint quote has no checking id")
payment_quote = PaymentQuoteResponse(
checking_id=mint_quote.checking_id,
amount=Amount(unit, mint_quote.amount),
@@ -589,20 +616,20 @@ class Ledger(LedgerVerification, LedgerSpendingConditions):
else:
# not internal, get payment quote by backend
payment_quote = await self.backends[method][unit].get_payment_quote(request)
assert payment_quote.checking_id, "quote has no checking id"
if not payment_quote.checking_id:
raise TransactionError("quote has no checking id")
# make sure the backend returned the amount with a correct unit
assert (
payment_quote.amount.unit == unit
), "payment quote amount units do not match"
if not payment_quote.amount.unit == unit:
raise TransactionError("payment quote amount units do not match")
# fee from the backend must be in the same unit as the amount
assert (
payment_quote.fee.unit == unit
), "payment quote fee units do not match"
if not payment_quote.fee.unit == unit:
raise TransactionError("payment quote fee units do not match")
# We assume that the request is a bolt11 invoice, this works since we
# support only the bol11 method for now.
invoice_obj = bolt11.decode(melt_quote.request)
assert invoice_obj.amount_msat, "invoice has no amount."
if not invoice_obj.amount_msat:
raise TransactionError("invoice has no amount.")
# we set the expiry of this quote to the expiry of the bolt11 invoice
expiry = None
if invoice_obj.expiry is not None:
@@ -703,23 +730,28 @@ class Ledger(LedgerVerification, LedgerSpendingConditions):
if not mint_quote:
return melt_quote
# we settle the transaction internally
assert not melt_quote.paid, "melt quote already paid"
if melt_quote.paid:
raise TransactionError("melt quote already paid")
# verify amounts from bolt11 invoice
bolt11_request = melt_quote.request
invoice_obj = bolt11.decode(bolt11_request)
assert invoice_obj.amount_msat, "invoice has no amount."
# invoice_amount_sat = math.ceil(invoice_obj.amount_msat / 1000)
# assert (
# Amount(Unit[melt_quote.unit], mint_quote.amount).to(Unit.sat).amount
# == invoice_amount_sat
# ), "amounts do not match"
assert mint_quote.amount == melt_quote.amount, "amounts do not match"
assert bolt11_request == mint_quote.request, "bolt11 requests do not match"
assert mint_quote.unit == melt_quote.unit, "units do not match"
assert mint_quote.method == melt_quote.method, "methods do not match"
assert not mint_quote.paid, "mint quote already paid"
assert not mint_quote.issued, "mint quote already issued"
if not invoice_obj.amount_msat:
raise TransactionError("invoice has no amount.")
if not mint_quote.amount == melt_quote.amount:
raise TransactionError("amounts do not match")
if not bolt11_request == mint_quote.request:
raise TransactionError("bolt11 requests do not match")
if not mint_quote.unit == melt_quote.unit:
raise TransactionError("units do not match")
if not mint_quote.method == melt_quote.method:
raise TransactionError("methods do not match")
if mint_quote.paid:
raise TransactionError("mint quote already paid")
if mint_quote.issued:
raise TransactionError("mint quote already issued")
logger.info(
f"Settling bolt11 payment internally: {melt_quote.quote} ->"
f" {mint_quote.quote} ({melt_quote.amount} {melt_quote.unit})"
@@ -764,25 +796,25 @@ class Ledger(LedgerVerification, LedgerSpendingConditions):
melt_quote.unit, melt_quote.method
)
assert not melt_quote.paid, "melt quote already paid"
if melt_quote.paid:
raise TransactionError("melt quote already paid")
# make sure that the outputs (for fee return) are in the same unit as the quote
if outputs:
await self._verify_outputs(outputs, skip_amount_check=True)
assert outputs[0].id, "output id not set"
outputs_unit = self.keysets[outputs[0].id].unit
assert melt_quote.unit == outputs_unit.name, (
f"output unit {outputs_unit.name} does not match quote unit"
f" {melt_quote.unit}"
)
if not melt_quote.unit == outputs_unit.name:
raise TransactionError(
f"output unit {outputs_unit.name} does not match quote unit {melt_quote.unit}"
)
# verify that the amount of the input proofs is equal to the amount of the quote
total_provided = sum_proofs(proofs)
total_needed = melt_quote.amount + (melt_quote.fee_reserve or 0)
assert total_provided >= total_needed, (
f"not enough inputs provided for melt. Provided: {total_provided}, needed:"
f" {total_needed}"
)
if not total_provided >= total_needed:
raise TransactionError(
f"not enough inputs provided for melt. Provided: {total_provided}, needed: {total_needed}"
)
# verify that the amount of the proofs is not larger than the maximum allowed
if settings.mint_max_peg_out and total_provided > settings.mint_max_peg_out:
@@ -831,7 +863,6 @@ class Ledger(LedgerVerification, LedgerSpendingConditions):
# prepare change to compensate wallet for overpaid fees
return_promises: List[BlindedSignature] = []
if outputs:
assert outputs[0].id, "output id not set"
return_promises = await self._generate_change_promises(
input_amount=total_provided,
output_amount=melt_quote.amount,
@@ -871,22 +902,21 @@ class Ledger(LedgerVerification, LedgerSpendingConditions):
Tuple[List[BlindSignature],List[BlindSignature]]: Promises on both sides of the split.
"""
logger.trace("split called")
# explicitly check that amount of inputs is equal to amount of outputs
# note: we check this again in verify_inputs_and_outputs but only if any
# outputs are provided at all. To make sure of that before calling
# verify_inputs_and_outputs, we check it here.
self._verify_equation_balanced(proofs, outputs)
# verify spending inputs, outputs, and spending conditions
await self.verify_inputs_and_outputs(proofs=proofs, outputs=outputs)
await self._set_proofs_pending(proofs)
try:
# explicitly check that amount of inputs is equal to amount of outputs
# note: we check this again in verify_inputs_and_outputs but only if any
# outputs are provided at all. To make sure of that before calling
# verify_inputs_and_outputs, we check it here.
self._verify_equation_balanced(proofs, outputs)
# verify spending inputs, outputs, and spending conditions
await self.verify_inputs_and_outputs(proofs=proofs, outputs=outputs)
# Mark proofs as used and prepare new promises
async with get_db_connection(self.db) as conn:
# we do this in a single db transaction
promises = await self._generate_promises(outputs, keyset, conn)
await self._invalidate_proofs(proofs=proofs, conn=conn)
promises = await self._generate_promises(outputs, keyset, conn)
except Exception as e:
logger.trace(f"split failed: {e}")
@@ -949,15 +979,16 @@ class Ledger(LedgerVerification, LedgerSpendingConditions):
] = []
for output in outputs:
B_ = PublicKey(bytes.fromhex(output.B_), raw=True)
assert output.id, "output id not set"
keyset = keyset or self.keysets[output.id]
assert output.id in self.keysets, f"keyset {output.id} not found"
assert output.id in [
if output.id not in self.keysets:
raise TransactionError(f"keyset {output.id} not found")
if output.id not in [
keyset.id,
keyset.duplicate_keyset_id,
], "keyset id does not match output id"
assert keyset.active, "keyset is not active"
]:
raise TransactionError("keyset id does not match output id")
if not keyset.active:
raise TransactionError("keyset is not active")
keyset_id = output.id
logger.trace(f"Generating promise with keyset {keyset_id}.")
private_key_amount = keyset.private_keys[output.amount]
@@ -995,7 +1026,8 @@ class Ledger(LedgerVerification, LedgerSpendingConditions):
async def load_used_proofs(self) -> None:
"""Load all used proofs from database."""
assert settings.mint_cache_secrets, "MINT_CACHE_SECRETS must be set to TRUE"
if not settings.mint_cache_secrets:
raise Exception("MINT_CACHE_SECRETS must be set to TRUE")
logger.debug("Loading used proofs into memory")
spent_proofs_list = await self.crud.get_spent_proofs(db=self.db) or []
logger.debug(f"Loaded {len(spent_proofs_list)} used proofs")
@@ -1082,11 +1114,12 @@ class Ledger(LedgerVerification, LedgerSpendingConditions):
Raises:
Exception: At least one of the proofs is in the pending table.
"""
assert (
if not (
len(
await self.crud.get_proofs_pending(
Ys=[p.Y for p in proofs], db=self.db, conn=conn
)
)
== 0
), TransactionError("proofs are pending.")
):
raise TransactionError("proofs are pending.")

View File

@@ -4,6 +4,7 @@ from fastapi import APIRouter, Request
from loguru import logger
from ..core.base import (
BlindedMessage,
BlindedSignature,
CheckFeesRequest_deprecated,
CheckFeesResponse_deprecated,
@@ -177,10 +178,14 @@ async def mint_deprecated(
# BEGIN BACKWARDS COMPATIBILITY < 0.15
# Mint expects "id" in outputs to know which keyset to use to sign them.
for output in payload.outputs:
if not output.id:
# use the deprecated version of the current keyset
output.id = ledger.keyset.duplicate_keyset_id
# use the deprecated version of the current keyset
assert ledger.keyset.duplicate_keyset_id
outputs: list[BlindedMessage] = [
BlindedMessage(
id=o.id or ledger.keyset.duplicate_keyset_id, **o.dict(exclude={"id"})
)
for o in payload.outputs
]
# END BACKWARDS COMPATIBILITY < 0.15
# BEGIN: backwards compatibility < 0.12 where we used to lookup payments with payment_hash
@@ -189,7 +194,7 @@ async def mint_deprecated(
assert hash, "hash must be set."
# END: backwards compatibility < 0.12
promises = await ledger.mint(outputs=payload.outputs, quote_id=hash)
promises = await ledger.mint(outputs=outputs, quote_id=hash)
blinded_signatures = PostMintResponse_deprecated(promises=promises)
logger.trace(f"< POST /mint: {blinded_signatures}")
@@ -221,15 +226,18 @@ async def melt_deprecated(
logger.trace(f"> POST /melt: {payload}")
# BEGIN BACKWARDS COMPATIBILITY < 0.14: add "id" to outputs
if payload.outputs:
for output in payload.outputs:
if not output.id:
output.id = ledger.keyset.id
outputs: list[BlindedMessage] = [
BlindedMessage(id=o.id or ledger.keyset.id, **o.dict(exclude={"id"}))
for o in payload.outputs
]
else:
outputs = []
# END BACKWARDS COMPATIBILITY < 0.14
quote = await ledger.melt_quote(
PostMeltQuoteRequest(request=payload.pr, unit="sat")
)
preimage, change_promises = await ledger.melt(
proofs=payload.proofs, quote=quote.quote, outputs=payload.outputs
proofs=payload.proofs, quote=quote.quote, outputs=outputs
)
resp = PostMeltResponse_deprecated(
paid=True, preimage=preimage, change=change_promises
@@ -290,12 +298,12 @@ async def split_deprecated(
logger.trace(f"> POST /split: {payload}")
assert payload.outputs, Exception("no outputs provided.")
# BEGIN BACKWARDS COMPATIBILITY < 0.14: add "id" to outputs
if payload.outputs:
for output in payload.outputs:
if not output.id:
output.id = ledger.keyset.id
outputs: list[BlindedMessage] = [
BlindedMessage(id=o.id or ledger.keyset.id, **o.dict(exclude={"id"}))
for o in payload.outputs
]
# END BACKWARDS COMPATIBILITY < 0.14
promises = await ledger.split(proofs=payload.proofs, outputs=payload.outputs)
promises = await ledger.split(proofs=payload.proofs, outputs=outputs)
if payload.amount:
# BEGIN backwards compatibility < 0.13

View File

@@ -8,6 +8,7 @@ from loguru import logger
from ..core.base import (
BlindedMessage,
BlindedMessage_Deprecated,
BlindedSignature,
CheckFeesRequest_deprecated,
CheckFeesResponse_deprecated,
@@ -271,7 +272,8 @@ class LedgerAPIDeprecated(SupportsHttpxClient, SupportsMintURL):
Raises:
Exception: If the minting fails
"""
outputs_payload = PostMintRequest_deprecated(outputs=outputs)
outputs_deprecated = [BlindedMessage_Deprecated(**o.dict()) for o in outputs]
outputs_payload = PostMintRequest_deprecated(outputs=outputs_deprecated)
def _mintrequest_include_fields(outputs: List[BlindedMessage]):
"""strips away fields from the model that aren't necessary for the /mint"""
@@ -307,7 +309,14 @@ class LedgerAPIDeprecated(SupportsHttpxClient, SupportsMintURL):
Accepts proofs and a lightning invoice to pay in exchange.
"""
logger.warning("Using deprecated API call: POST /melt")
payload = PostMeltRequest_deprecated(proofs=proofs, pr=invoice, outputs=outputs)
outputs_deprecated = (
[BlindedMessage_Deprecated(**o.dict()) for o in outputs]
if outputs
else None
)
payload = PostMeltRequest_deprecated(
proofs=proofs, pr=invoice, outputs=outputs_deprecated
)
def _meltrequest_include_fields(proofs: List[Proof]):
"""strips away fields from the model that aren't necessary for the /melt"""
@@ -336,7 +345,10 @@ class LedgerAPIDeprecated(SupportsHttpxClient, SupportsMintURL):
) -> List[BlindedSignature]:
"""Consume proofs and create new promises based on amount split."""
logger.warning("Using deprecated API call: Calling split. POST /split")
split_payload = PostSplitRequest_Deprecated(proofs=proofs, outputs=outputs)
outputs_deprecated = [BlindedMessage_Deprecated(**o.dict()) for o in outputs]
split_payload = PostSplitRequest_Deprecated(
proofs=proofs, outputs=outputs_deprecated
)
# construct payload
def _splitrequest_include_fields(proofs: List[Proof]):
@@ -403,7 +415,8 @@ class LedgerAPIDeprecated(SupportsHttpxClient, SupportsMintURL):
Asks the mint to restore promises corresponding to outputs.
"""
logger.warning("Using deprecated API call: POST /restore")
payload = PostMintRequest_deprecated(outputs=outputs)
outputs_deprecated = [BlindedMessage_Deprecated(**o.dict()) for o in outputs]
payload = PostMintRequest_deprecated(outputs=outputs_deprecated)
resp = await self.httpx.post(join(self.url, "/restore"), json=payload.dict())
self.raise_on_error(resp)
response_dict = resp.json()

View File

@@ -1,6 +1,6 @@
[tool.poetry]
name = "cashu"
version = "0.15.2"
version = "0.15.3"
description = "Ecash wallet and mint"
authors = ["calle <callebtc@protonmail.com>"]
license = "MIT"

View File

@@ -13,7 +13,7 @@ entry_points = {"console_scripts": ["cashu = cashu.wallet.cli.cli:cli"]}
setuptools.setup(
name="cashu",
version="0.15.2",
version="0.15.3",
description="Ecash wallet and mint",
long_description=long_description,
long_description_content_type="text/markdown",

View File

@@ -65,7 +65,7 @@ async def test_init_keysets_with_duplicates(ledger: Ledger):
@pytest.mark.asyncio
async def test_init_keysets_with_duplicates_via_settings(ledger: Ledger):
ledger.keysets = {}
settings.mint_duplicate_keysets = True
settings.mint_duplicate_old_keysets = True
await ledger.init_keysets()
assert len(ledger.keysets) == 2
@@ -80,7 +80,7 @@ async def test_init_keysets_without_duplicates(ledger: Ledger):
@pytest.mark.asyncio
async def test_init_keysets_without_duplicates_via_settings(ledger: Ledger):
ledger.keysets = {}
settings.mint_duplicate_keysets = False
settings.mint_duplicate_old_keysets = False
await ledger.init_keysets()
assert len(ledger.keysets) == 1

View File

@@ -355,7 +355,7 @@ async def test_duplicate_proofs_double_spent(wallet1: Wallet):
doublespend = await wallet1.mint(64, id=invoice.id)
await assert_err(
wallet1.split(wallet1.proofs + doublespend, 20),
"Mint Error: Failed to set proofs pending.",
"Mint Error: duplicate proofs.",
)
assert wallet1.balance == 64
assert wallet1.available_balance == 64