mirror of
https://github.com/aljazceru/nutshell.git
synced 2026-02-03 07:44:21 +01:00
CLN multinut test fix (#602)
This commit is contained in:
@@ -29,7 +29,7 @@ from .base import (
|
||||
class CLNRestWallet(LightningBackend):
|
||||
supported_units = set([Unit.sat, Unit.msat])
|
||||
unit = Unit.sat
|
||||
supports_mpp = False # settings.mint_clnrest_enable_mpp
|
||||
supports_mpp = settings.mint_clnrest_enable_mpp
|
||||
supports_incoming_payment_stream: bool = True
|
||||
|
||||
def __init__(self, unit: Unit = Unit.sat, **kwargs):
|
||||
@@ -195,11 +195,14 @@ class CLNRestWallet(LightningBackend):
|
||||
}
|
||||
|
||||
# Handle Multi-Mint payout where we must only pay part of the invoice amount
|
||||
logger.trace(f"{quote_amount_msat = }, {invoice.amount_msat = }")
|
||||
if quote_amount_msat != invoice.amount_msat:
|
||||
logger.trace("Detected Multi-Nut payment")
|
||||
if self.supports_mpp:
|
||||
post_data["partial_msat"] = quote_amount_msat
|
||||
else:
|
||||
error_message = "mint does not support MPP"
|
||||
logger.error(error_message)
|
||||
return PaymentResponse(
|
||||
ok=False,
|
||||
checking_id=None,
|
||||
|
||||
@@ -96,6 +96,16 @@ docker_lightning_unconnected_cli = [
|
||||
"--rpcserver=lnd-2",
|
||||
]
|
||||
|
||||
def docker_clightning_cli(index):
|
||||
return [
|
||||
"docker",
|
||||
"exec",
|
||||
f"cashu-clightning-{index}-1",
|
||||
"lightning-cli",
|
||||
"--network",
|
||||
"regtest",
|
||||
"--keywords",
|
||||
]
|
||||
|
||||
def run_cmd(cmd: list) -> str:
|
||||
timeout = 20
|
||||
@@ -161,6 +171,10 @@ def pay_real_invoice(invoice: str) -> str:
|
||||
cmd.extend(["payinvoice", "--force", invoice])
|
||||
return run_cmd(cmd)
|
||||
|
||||
def partial_pay_real_invoice(invoice: str, amount: int, node: int) -> str:
|
||||
cmd = docker_clightning_cli(node)
|
||||
cmd.extend(["pay", f"bolt11={invoice}", f"partial_msat={amount*1000}"])
|
||||
return run_cmd(cmd)
|
||||
|
||||
def mine_blocks(blocks: int = 1) -> str:
|
||||
cmd = docker_bitcoin_cli.copy()
|
||||
|
||||
@@ -1,16 +1,19 @@
|
||||
import asyncio
|
||||
import threading
|
||||
from typing import List
|
||||
|
||||
import pytest
|
||||
import pytest_asyncio
|
||||
|
||||
from cashu.core.base import Method, Proof
|
||||
from cashu.lightning.clnrest import CLNRestWallet
|
||||
from cashu.mint.ledger import Ledger
|
||||
from cashu.wallet.wallet import Wallet
|
||||
from tests.conftest import SERVER_ENDPOINT
|
||||
from tests.helpers import (
|
||||
get_real_invoice,
|
||||
is_fake,
|
||||
partial_pay_real_invoice,
|
||||
pay_if_regtest,
|
||||
)
|
||||
|
||||
@@ -42,32 +45,33 @@ async def test_regtest_pay_mpp(wallet: Wallet, ledger: Ledger):
|
||||
proofs1 = await wallet.mint(128, id=topup_invoice.id)
|
||||
assert wallet.balance == 128
|
||||
|
||||
topup_invoice = await wallet.request_mint(128)
|
||||
await pay_if_regtest(topup_invoice.bolt11)
|
||||
proofs2 = await wallet.mint(128, id=topup_invoice.id)
|
||||
assert wallet.balance == 256
|
||||
|
||||
# this is the invoice we want to pay in two parts
|
||||
invoice_dict = get_real_invoice(64)
|
||||
invoice_payment_request = invoice_dict["payment_request"]
|
||||
|
||||
async def pay_mpp(amount: int, proofs: List[Proof], delay: float = 0.0):
|
||||
await asyncio.sleep(delay)
|
||||
async def _mint_pay_mpp(invoice: str, amount: int, proofs: List[Proof]):
|
||||
# wallet pays 32 sat of the invoice
|
||||
quote = await wallet.melt_quote(invoice_payment_request, amount=amount)
|
||||
quote = await wallet.melt_quote(invoice, amount=amount)
|
||||
assert quote.amount == amount
|
||||
await wallet.melt(
|
||||
proofs,
|
||||
invoice_payment_request,
|
||||
invoice,
|
||||
fee_reserve_sat=quote.fee_reserve,
|
||||
quote_id=quote.quote,
|
||||
)
|
||||
def mint_pay_mpp(invoice: str, amount: int, proofs: List[Proof]):
|
||||
asyncio.run(_mint_pay_mpp(invoice, amount, proofs))
|
||||
|
||||
# call pay_mpp twice in parallel to pay the full invoice
|
||||
# we delay the second payment so that the wallet doesn't derive the same blindedmessages twice due to a race condition
|
||||
await asyncio.gather(pay_mpp(32, proofs1), pay_mpp(32, proofs2, delay=0.5))
|
||||
t1 = threading.Thread(target=mint_pay_mpp, args=(invoice_payment_request, 32, proofs1))
|
||||
t2 = threading.Thread(target=partial_pay_real_invoice, args=(invoice_payment_request, 32, 1))
|
||||
|
||||
assert wallet.balance <= 256 - 64
|
||||
t1.start()
|
||||
t2.start()
|
||||
t1.join()
|
||||
t2.join()
|
||||
|
||||
assert wallet.balance <= 256 - 32
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
@@ -76,6 +80,11 @@ async def test_regtest_pay_mpp_incomplete_payment(wallet: Wallet, ledger: Ledger
|
||||
# make sure that mpp is supported by the bolt11-sat backend
|
||||
if not ledger.backends[Method["bolt11"]][wallet.unit].supports_mpp:
|
||||
pytest.skip("backend does not support mpp")
|
||||
|
||||
# This test cannot be done with CLN because we only have one mint
|
||||
# and CLN hates multiple partial payment requests
|
||||
if isinstance(ledger.backends[Method["bolt11"]][wallet.unit], CLNRestWallet):
|
||||
pytest.skip("CLN cannot perform this test")
|
||||
|
||||
# make sure wallet knows the backend supports mpp
|
||||
assert wallet.mint_info.supports_mpp("bolt11", wallet.unit)
|
||||
|
||||
Reference in New Issue
Block a user