mirror of
https://github.com/Routstr/routstr-core.git
synced 2026-10-05 20:28:23 +00:00
fix: recognize 'Unknown quote' mint error as definitively unpaid
This commit is contained in:
+13
-1
@@ -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)
|
||||
|
||||
@@ -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()
|
||||
|
||||
Reference in New Issue
Block a user