mirror of
https://github.com/aljazceru/nutshell.git
synced 2025-12-22 11:24:19 +01:00
[PATCH] LND use_mission_control + exclude failing channels (#738)
* lnd_grpc multinut patch * lndrest multinut patch * mypy fixes * fixes non escaped double quotes in error messages formats * fix * fix debug log with correct hops number * correctly escape "hops" * remove `ignored_pairs` constraint * Apply suggestions from code review change some error logs to debug * add tests and some cleanup --------- Co-authored-by: callebtc <93376500+callebtc@users.noreply.github.com>
This commit is contained in:
@@ -2,17 +2,21 @@ import asyncio
|
||||
import threading
|
||||
from typing import List
|
||||
|
||||
import bolt11
|
||||
import pytest
|
||||
import pytest_asyncio
|
||||
|
||||
from cashu.core.base import Method, Proof
|
||||
from cashu.core.base import MeltQuote, MeltQuoteState, Method, Proof
|
||||
from cashu.lightning.base import PaymentResponse
|
||||
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 (
|
||||
SLEEP_TIME,
|
||||
assert_err,
|
||||
get_real_invoice,
|
||||
cancel_invoice,
|
||||
get_hold_invoice,
|
||||
is_fake,
|
||||
partial_pay_real_invoice,
|
||||
pay_if_regtest,
|
||||
@@ -47,12 +51,12 @@ async def test_regtest_pay_mpp(wallet: Wallet, ledger: Ledger):
|
||||
assert wallet.balance == 128
|
||||
|
||||
# this is the invoice we want to pay in two parts
|
||||
invoice_dict = get_real_invoice(64)
|
||||
invoice_payment_request = invoice_dict["payment_request"]
|
||||
preimage, invoice_dict = get_hold_invoice(64)
|
||||
invoice_payment_request = str(invoice_dict["payment_request"])
|
||||
|
||||
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, amount_msat=amount*1000)
|
||||
quote = await wallet.melt_quote(invoice, amount_msat=amount * 1000)
|
||||
assert quote.amount == amount
|
||||
await wallet.melt(
|
||||
proofs,
|
||||
@@ -112,13 +116,15 @@ async def test_regtest_pay_mpp_incomplete_payment(wallet: Wallet, ledger: Ledger
|
||||
assert wallet.balance == 384
|
||||
|
||||
# this is the invoice we want to pay in two parts
|
||||
invoice_dict = get_real_invoice(64)
|
||||
invoice_payment_request = invoice_dict["payment_request"]
|
||||
preimage, invoice_dict = get_hold_invoice(64)
|
||||
invoice_payment_request = str(invoice_dict["payment_request"])
|
||||
|
||||
async def pay_mpp(amount: int, proofs: List[Proof], delay: float = 0.0):
|
||||
await asyncio.sleep(delay)
|
||||
# wallet pays 32 sat of the invoice
|
||||
quote = await wallet.melt_quote(invoice_payment_request, amount_msat=amount*1000)
|
||||
quote = await wallet.melt_quote(
|
||||
invoice_payment_request, amount_msat=amount * 1000
|
||||
)
|
||||
assert quote.amount == amount
|
||||
await wallet.melt(
|
||||
proofs,
|
||||
@@ -154,5 +160,112 @@ async def test_regtest_internal_mpp_melt_quotes(wallet: Wallet, ledger: Ledger):
|
||||
|
||||
# try and create a multi-part melt quote
|
||||
await assert_err(
|
||||
wallet.melt_quote(mint_quote.request, 100*1000), "internal mpp not allowed"
|
||||
wallet.melt_quote(mint_quote.request, 100 * 1000), "internal mpp not allowed"
|
||||
)
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
@pytest.mark.skipif(is_fake, reason="only regtest")
|
||||
async def test_regtest_pay_mpp_cancel_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")
|
||||
|
||||
# make sure wallet knows the backend supports mpp
|
||||
assert wallet.mint_info.supports_mpp("bolt11", wallet.unit)
|
||||
|
||||
# top up wallet so we have enough for the payment
|
||||
topup_mint_quote = await wallet.request_mint(128)
|
||||
await pay_if_regtest(topup_mint_quote.request)
|
||||
proofs1 = await wallet.mint(128, quote_id=topup_mint_quote.quote)
|
||||
assert wallet.balance == 128
|
||||
|
||||
# create a hold invoice that we can cancel
|
||||
preimage, invoice_dict = get_hold_invoice(64)
|
||||
invoice_payment_request = str(invoice_dict.get("payment_request", ""))
|
||||
invoice_obj = bolt11.decode(invoice_payment_request)
|
||||
payment_hash = invoice_obj.payment_hash
|
||||
|
||||
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, amount_msat=amount * 1000)
|
||||
assert quote.amount == amount
|
||||
await wallet.melt(
|
||||
proofs,
|
||||
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))
|
||||
|
||||
# start the MPP payment
|
||||
t1 = threading.Thread(
|
||||
target=mint_pay_mpp, args=(invoice_payment_request, 32, proofs1)
|
||||
)
|
||||
t1.start()
|
||||
await asyncio.sleep(SLEEP_TIME)
|
||||
|
||||
# cancel the invoice
|
||||
cancel_invoice(payment_hash)
|
||||
await asyncio.sleep(SLEEP_TIME)
|
||||
|
||||
# check the payment status
|
||||
status = await ledger.backends[Method["bolt11"]][wallet.unit].get_payment_status(
|
||||
payment_hash
|
||||
)
|
||||
assert status.failed # some backends return unknown instead of failed
|
||||
assert not status.preimage # no preimage since payment failed
|
||||
|
||||
# check that the proofs are unspent since payment failed
|
||||
states = await wallet.check_proof_state(proofs1)
|
||||
assert all([s.unspent for s in states.states])
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
@pytest.mark.skipif(is_fake, reason="only regtest")
|
||||
async def test_regtest_pay_mpp_cancel_payment_pay_partial_invoice(
|
||||
wallet: Wallet, ledger: Ledger
|
||||
):
|
||||
# create a hold invoice that we can cancel
|
||||
preimage, invoice_dict = get_hold_invoice(64)
|
||||
invoice_payment_request = str(invoice_dict.get("payment_request", ""))
|
||||
invoice_obj = bolt11.decode(invoice_payment_request)
|
||||
payment_hash = invoice_obj.payment_hash
|
||||
|
||||
# Use a shared container to store the result
|
||||
result_container = []
|
||||
|
||||
async def _mint_pay_mpp(invoice: str, amount: int) -> PaymentResponse:
|
||||
ret = await ledger.backends[Method["bolt11"]][wallet.unit].pay_invoice(
|
||||
MeltQuote(
|
||||
request=invoice,
|
||||
amount=amount,
|
||||
fee_reserve=0,
|
||||
quote="",
|
||||
method="bolt11",
|
||||
checking_id="",
|
||||
unit=wallet.unit.name,
|
||||
state=MeltQuoteState.pending,
|
||||
),
|
||||
0,
|
||||
)
|
||||
return ret
|
||||
|
||||
# Create a wrapper function that will store the result
|
||||
def thread_func():
|
||||
result = asyncio.run(_mint_pay_mpp(invoice_payment_request, 32))
|
||||
result_container.append(result)
|
||||
|
||||
t1 = threading.Thread(target=thread_func)
|
||||
t1.start()
|
||||
await asyncio.sleep(SLEEP_TIME)
|
||||
|
||||
# cancel the invoice
|
||||
cancel_invoice(payment_hash)
|
||||
await asyncio.sleep(SLEEP_TIME)
|
||||
|
||||
t1.join()
|
||||
# Get the result from the container
|
||||
assert result_container[0].failed
|
||||
|
||||
Reference in New Issue
Block a user