lnworker: fix todo, collect failed htlcs in payment
This makes `LNWallet.pay_to_node()` wait `PaySession.TIMEOUT_WAIT_FOR_NEXT_RESOLVED_HTLC` (0.5 sec) for another htlc to get resolved after receiving a htlc failure during a payment attempt. This seems to make payments more reliable in scenarios where we receive multiple htlc failures closely after each other as `create_route_for_payment` then has access to the failed routes/failure information of all these htlcs when trying to re-split the outstanding amount.
This commit is contained in:
@@ -710,6 +710,10 @@ class LNGossip(LNWorker):
|
|||||||
|
|
||||||
|
|
||||||
class PaySession(Logger):
|
class PaySession(Logger):
|
||||||
|
|
||||||
|
# how long we wait for another htlc to resolve after receiving a failure for one sent htlc.
|
||||||
|
TIMEOUT_WAIT_FOR_NEXT_RESOLVED_HTLC = 0.5
|
||||||
|
|
||||||
def __init__(
|
def __init__(
|
||||||
self,
|
self,
|
||||||
*,
|
*,
|
||||||
@@ -754,6 +758,10 @@ class PaySession(Logger):
|
|||||||
pkey = sha256(self.payment_key)
|
pkey = sha256(self.payment_key)
|
||||||
return f"{self.payment_hash[:4].hex()}-{pkey[:2].hex()}"
|
return f"{self.payment_hash[:4].hex()}-{pkey[:2].hex()}"
|
||||||
|
|
||||||
|
@property
|
||||||
|
def number_htlcs_inflight(self) -> int:
|
||||||
|
return self._nhtlcs_inflight
|
||||||
|
|
||||||
def maybe_raise_trampoline_fee(self, htlc_log: HtlcLog):
|
def maybe_raise_trampoline_fee(self, htlc_log: HtlcLog):
|
||||||
if htlc_log.trampoline_fee_level == self.trampoline_fee_level:
|
if htlc_log.trampoline_fee_level == self.trampoline_fee_level:
|
||||||
self.trampoline_fee_level += 1
|
self.trampoline_fee_level += 1
|
||||||
@@ -1709,8 +1717,9 @@ class LNWallet(LNWorker):
|
|||||||
# It is also triggered here to update progress for a lightning payment in the GUI
|
# It is also triggered here to update progress for a lightning payment in the GUI
|
||||||
# (e.g. attempt counter)
|
# (e.g. attempt counter)
|
||||||
util.trigger_callback('invoice_status', self.wallet, payment_hash.hex(), PR_INFLIGHT)
|
util.trigger_callback('invoice_status', self.wallet, payment_hash.hex(), PR_INFLIGHT)
|
||||||
# 3. await a queue
|
# 3. await a queue, collect resolved htlcs
|
||||||
htlc_log = await paysession.wait_for_one_htlc_to_resolve() # TODO maybe wait a bit, more failures might come
|
htlc_log = await paysession.wait_for_one_htlc_to_resolve()
|
||||||
|
while True:
|
||||||
log.append(htlc_log)
|
log.append(htlc_log)
|
||||||
if htlc_log.success:
|
if htlc_log.success:
|
||||||
if self.network.path_finder:
|
if self.network.path_finder:
|
||||||
@@ -1749,6 +1758,16 @@ class LNWallet(LNWorker):
|
|||||||
else:
|
else:
|
||||||
self.handle_error_code_from_failed_htlc(
|
self.handle_error_code_from_failed_htlc(
|
||||||
route=route, sender_idx=sender_idx, failure_msg=failure_msg, amount=htlc_log.amount_msat)
|
route=route, sender_idx=sender_idx, failure_msg=failure_msg, amount=htlc_log.amount_msat)
|
||||||
|
if paysession.number_htlcs_inflight < 1:
|
||||||
|
break
|
||||||
|
# wait a bit, more failures might come
|
||||||
|
try:
|
||||||
|
htlc_log = await util.wait_for2(
|
||||||
|
paysession.wait_for_one_htlc_to_resolve(),
|
||||||
|
timeout=paysession.TIMEOUT_WAIT_FOR_NEXT_RESOLVED_HTLC)
|
||||||
|
except asyncio.TimeoutError:
|
||||||
|
break
|
||||||
|
|
||||||
# max attempts or timeout
|
# max attempts or timeout
|
||||||
if (attempts is not None and len(log) >= attempts) or (attempts is None and time.time() - paysession.start_time > self.PAYMENT_TIMEOUT):
|
if (attempts is not None and len(log) >= attempts) or (attempts is None and time.time() - paysession.start_time > self.PAYMENT_TIMEOUT):
|
||||||
raise PaymentFailure('Giving up after %d attempts'%len(log))
|
raise PaymentFailure('Giving up after %d attempts'%len(log))
|
||||||
|
|||||||
Reference in New Issue
Block a user