Backend: Unstuck outgoing payments (#857)

* first attempts

* lndrest works

* fix details

* optional fee update

* use base64.urlsafe_b64encode

* return paymentstatus

* CLN: return pending for pending invoices

* grpc wip

* lndgrpc works

* cln: return pending for pending invoices really this time

* retry wallet out of exception

* wip eclair

* take all routines into try except

* cliche: return error

* rename payment.check_pending() to payment.check_status()

* rename payment.check_pending() to payment.check_status()

* eclair: works

* eclair: better error check

* opennode: works

* check payment.checking_id istead of payment.ok

* payment.ok check as well

* cln: works?

* cln: works

* lntxbot: works

* lnbits/wallets/lnpay.py

* cln: error handling

* make format

* lndhub full detail update

* spark: wip

* error to False

* wallets: return clean PaymentResponse

* opennode: strict error

* cliche: works

* lnbits: works

* cln: dont throw error

* preimage not error

* fix cln

* do not add duplicate payments

* revert cln

* extra safety for cln

* undo crud changes until tests work

* tasks: better logging and 0.5s sleep for regular status check

* 0.1 s

* check if wallet exists

* lnbits unhashed description

* remove sleep

* revert app.py

* cleanup

* add check

* clean error

* readd app.py

* fix eclaid
This commit is contained in:
calle
2022-08-30 13:28:58 +02:00
committed by GitHub
parent 78a98ca97d
commit 2ee10e28c5
18 changed files with 384 additions and 194 deletions
+50 -32
View File
@@ -81,31 +81,41 @@ class ClicheWallet(Wallet):
data["result"]["invoice"],
)
else:
return InvoiceResponse(
False, checking_id, payment_request, "Could not get payment hash"
)
return InvoiceResponse(False, None, None, "Could not get payment hash")
return InvoiceResponse(True, checking_id, payment_request, error_message)
async def pay_invoice(self, bolt11: str, fee_limit_msat: int) -> PaymentResponse:
ws = create_connection(self.endpoint)
ws.send(f"pay-invoice --invoice {bolt11}")
r = ws.recv()
data = json.loads(r)
checking_id = None
error_message = None
for _ in range(2):
r = ws.recv()
data = json.loads(r)
checking_id, fee_msat, preimage, error_message, payment_ok = (
None,
None,
None,
None,
None,
)
if data.get("error") is not None and data["error"].get("message"):
logger.error(data["error"]["message"])
error_message = data["error"]["message"]
return PaymentResponse(False, None, 0, error_message)
if data.get("error") is not None:
error_message = data["error"].get("message")
return PaymentResponse(False, None, None, None, error_message)
if data.get("result") is not None and data["result"].get("payment_hash"):
checking_id = data["result"]["payment_hash"]
else:
return PaymentResponse(False, checking_id, 0, "Could not get payment hash")
if data.get("method") == "payment_succeeded":
payment_ok = True
checking_id = data["params"]["payment_hash"]
fee_msat = data["params"]["fee_msatoshi"]
preimage = data["params"]["preimage"]
continue
return PaymentResponse(True, checking_id, 0, error_message)
if data.get("result") is None:
return PaymentResponse(None)
return PaymentResponse(
payment_ok, checking_id, fee_msat, preimage, error_message
)
async def get_invoice_status(self, checking_id: str) -> PaymentStatus:
ws = create_connection(self.endpoint)
@@ -129,22 +139,30 @@ class ClicheWallet(Wallet):
if data.get("error") is not None and data["error"].get("message"):
logger.error(data["error"]["message"])
return PaymentStatus(None)
payment = data["result"]
statuses = {"pending": None, "complete": True, "failed": False}
return PaymentStatus(statuses[data["result"]["status"]])
return PaymentStatus(
statuses[payment["status"]],
payment.get("fee_msatoshi"),
payment.get("preimage"),
)
async def paid_invoices_stream(self) -> AsyncGenerator[str, None]:
try:
ws = await create_connection(self.endpoint)
while True:
r = await ws.recv()
data = json.loads(r)
try:
if data["result"]["status"]:
yield data["result"]["payment_hash"]
except:
continue
except:
pass
logger.error("lost connection to cliche's websocket, retrying in 5 seconds")
await asyncio.sleep(5)
while True:
try:
ws = await create_connection(self.endpoint)
while True:
r = await ws.recv()
data = json.loads(r)
print(data)
try:
if data["result"]["status"]:
yield data["result"]["payment_hash"]
except:
continue
except Exception as exc:
logger.error(
f"lost connection to cliche's invoices stream: '{exc}', retrying in 5 seconds"
)
await asyncio.sleep(5)
continue