fix: recognize 'Unknown quote' mint error as definitively unpaid

This commit is contained in:
thefux
2026-08-18 22:07:51 +02:00
committed by 9qeklajc
parent dab13c71a1
commit 50cf1942af
2 changed files with 65 additions and 1 deletions
+13 -1
View File
@@ -601,8 +601,20 @@ async def check_invoice_payment(
def _is_quote_not_found(error: BaseException) -> bool:
"""Check if the error indicates the mint no longer has this quote."""
"""Check if the error indicates the mint no longer has this quote.
Recognised variants:
- ``Mint Error: quote not found (Code: 0)`` (legacy wording) — treated as
definitive only with the exact ``0`` code, because some mints reuse the
``quote not found`` wording for ambiguous states.
- ``Mint Error: Unknown quote (Code: 50000)`` — reported by some mint
implementations when the quote id was never issued or was dropped. The
wording itself is definitive (the mint has no record of the quote), and
the numeric code varies (seen as ``50000``), so no code check is applied.
"""
message = str(error)
if re.search(r"\bunknown\s+quote\b", message, re.IGNORECASE):
return True
return bool(
re.search(r"\bquote\s+not\s+found\b", message, re.IGNORECASE)
and re.search(r"\bcode\s*:?\s*0\b", message, re.IGNORECASE)
+52
View File
@@ -217,6 +217,58 @@ async def test_quote_not_found_case_insensitive() -> None:
assert result is True
@pytest.mark.asyncio
async def test_unknown_quote_is_definitively_unpaid() -> None:
"""Some mints report a dropped quote as 'Unknown quote (Code: 50000)'."""
_invoice_settlement_locks.clear()
invoice = _invoice(status="pending", expires_at=0)
session = AsyncMock()
wallet = Mock(
get_mint_quote=AsyncMock(
side_effect=Exception("Mint Error: Unknown quote (Code: 50000)")
)
)
with (
patch("routstr.lightning.get_wallet", AsyncMock(return_value=wallet)),
patch("routstr.lightning._reload_invoice_view", AsyncMock()),
):
result = await check_invoice_payment(invoice, session) # type: ignore[arg-type]
assert result is True
@pytest.mark.parametrize(
"message",
[
# legacy wording must still require the exact code 0
"Mint Error: quote not found (Code: 10000)",
"Mint Error: quote not found (Code: 50000)",
# not actually referring to a mint quote id
"Mint Error: unknown request",
"connection error: quote endpoint unreachable",
],
)
def test_unknown_quote_only_matches_real_quote_missing_errors(message: str) -> None:
from routstr.lightning import _is_quote_not_found
assert not _is_quote_not_found(Exception(message))
@pytest.mark.parametrize(
"message",
[
"Mint Error: Unknown quote (Code: 50000)",
"MINT ERROR: UNKNOWN QUOTE (CODE 50000)",
"Mint Error: unknown quote (Code: 11000)",
],
)
def test_unknown_quote_wording_is_recognized(message: str) -> None:
from routstr.lightning import _is_quote_not_found
assert _is_quote_not_found(Exception(message))
@pytest.mark.asyncio
async def test_credited_invoice_is_not_minted() -> None:
_invoice_settlement_locks.clear()