diff --git a/cashu/mint/ledger.py b/cashu/mint/ledger.py index f736f828..27afde9d 100644 --- a/cashu/mint/ledger.py +++ b/cashu/mint/ledger.py @@ -302,6 +302,8 @@ async def mint( logger.trace("called mint") amount_outputs = sum([b.amount for b in B_s]) + await self._verify_outputs(B_s) + if settings.lightning: if not id: raise NotAllowedError("no id provided.") @@ -317,8 +319,6 @@ async def mint( await self.crud.update_lightning_invoice(id=id, issued=True, db=self.db) del self.locks[id] - await self._verify_outputs(B_s) - promises = await self._generate_promises(B_s, keyset) logger.trace("generated promises") return promises @@ -368,6 +368,12 @@ async def melt( f" {total_provided}, needed: {invoice_amount + reserve_fees_sat}" ) + if outputs: + # verify the outputs. note: we don't verify inputs + # and outputs simultaneously with verify_inputs_and_outputs() as we do + # in split() because we do not expect the amounts to be equal here. + await self._verify_outputs(outputs) + # verify spending inputs and their spending conditions await self.verify_inputs_and_outputs(proofs) diff --git a/tests/test_mint_operations.py b/tests/test_mint_operations.py index b2aef3ef..1c8e2752 100644 --- a/tests/test_mint_operations.py +++ b/tests/test_mint_operations.py @@ -37,19 +37,19 @@ async def test_melt(wallet1: Wallet, ledger: Ledger): invoice = await wallet1.request_mint(64) pay_if_regtest(invoice.bolt11) await wallet1.mint(64, id=invoice.id) - invoice = await wallet1.request_mint(64) - pay_if_regtest(invoice.bolt11) - await wallet1.mint(64, id=invoice.id) + invoice2 = await wallet1.request_mint(64) + pay_if_regtest(invoice2.bolt11) + await wallet1.mint(64, id=invoice2.id) assert wallet1.balance == 128 total_amount, fee_reserve_sat = await wallet1.get_pay_amount_with_fees( - invoice.bolt11 + invoice2.bolt11 ) - mint_fees = await ledger.get_melt_fees(invoice.bolt11) - assert mint_fees == fee_reserve_sat + melt_fees = await ledger.get_melt_fees(invoice2.bolt11) + assert melt_fees == fee_reserve_sat keep_proofs, send_proofs = await wallet1.split_to_send(wallet1.proofs, total_amount) - await ledger.melt(send_proofs, invoice.bolt11, outputs=None) + await ledger.melt(send_proofs, invoice2.bolt11, outputs=None) @pytest.mark.asyncio @@ -176,6 +176,31 @@ async def test_mint_with_same_outputs_twice(wallet1: Wallet, ledger: Ledger): ) +@pytest.mark.asyncio +async def test_melt_with_same_outputs_twice(wallet1: Wallet, ledger: Ledger): + invoice = await wallet1.request_mint(130) + pay_if_regtest(invoice.bolt11) + await wallet1.mint(130, id=invoice.id) + + output_amounts = [128] + secrets, rs, derivation_paths = await wallet1.generate_n_secrets( + len(output_amounts) + ) + outputs, rs = wallet1._construct_outputs(output_amounts, secrets, rs) + + # we use the outputs once for minting + invoice2 = await wallet1.request_mint(128) + pay_if_regtest(invoice2.bolt11) + await ledger.mint(outputs, id=invoice2.id) + + # use the same outputs for melting + invoice3 = await wallet1.request_mint(128) + await assert_err( + ledger.melt(wallet1.proofs, invoice3.bolt11, outputs=outputs), + "outputs have already been signed before.", + ) + + @pytest.mark.asyncio async def test_check_proof_state(wallet1: Wallet, ledger: Ledger): invoice = await wallet1.request_mint(64)