LNWorker: give up payment after timeout, not number of attempts.
Limiting attempts may interrupt a MPP before we receive a MPP_timeout The attempts parameter is still used in unit tests.
This commit is contained in:
@@ -1103,12 +1103,12 @@ class Commands:
|
||||
return invoice.to_debug_json()
|
||||
|
||||
@command('wnl')
|
||||
async def lnpay(self, invoice, attempts=1, timeout=30, wallet: Abstract_Wallet = None):
|
||||
async def lnpay(self, invoice, timeout=120, wallet: Abstract_Wallet = None):
|
||||
lnworker = wallet.lnworker
|
||||
lnaddr = lnworker._check_invoice(invoice)
|
||||
payment_hash = lnaddr.paymenthash
|
||||
wallet.save_invoice(Invoice.from_bech32(invoice))
|
||||
success, log = await lnworker.pay_invoice(invoice, attempts=attempts)
|
||||
success, log = await lnworker.pay_invoice(invoice)
|
||||
return {
|
||||
'payment_hash': payment_hash.hex(),
|
||||
'success': success,
|
||||
@@ -1347,7 +1347,6 @@ command_options = {
|
||||
'domain': ("-D", "List of addresses"),
|
||||
'memo': ("-m", "Description of the request"),
|
||||
'expiration': (None, "Time in seconds"),
|
||||
'attempts': (None, "Number of payment attempts"),
|
||||
'timeout': (None, "Timeout in seconds"),
|
||||
'force': (None, "Create new address beyond gap limit, if no more addresses are available."),
|
||||
'pending': (None, "Show only pending requests."),
|
||||
@@ -1394,7 +1393,6 @@ arg_types = {
|
||||
'encrypt_file': eval_bool,
|
||||
'rbf': eval_bool,
|
||||
'timeout': float,
|
||||
'attempts': int,
|
||||
}
|
||||
|
||||
config_variables = {
|
||||
|
||||
@@ -361,7 +361,7 @@ class SendScreen(CScreen, Logger):
|
||||
amount_msat = invoice.get_amount_msat()
|
||||
def pay_thread():
|
||||
try:
|
||||
coro = self.app.wallet.lnworker.pay_invoice(invoice.lightning_invoice, amount_msat=amount_msat, attempts=10)
|
||||
coro = self.app.wallet.lnworker.pay_invoice(invoice.lightning_invoice, amount_msat=amount_msat)
|
||||
fut = asyncio.run_coroutine_threadsafe(coro, self.app.network.asyncio_loop)
|
||||
fut.result()
|
||||
except Exception as e:
|
||||
|
||||
@@ -1724,7 +1724,7 @@ class ElectrumWindow(QMainWindow, MessageBoxMixin, Logger):
|
||||
if not self.question(msg):
|
||||
return
|
||||
self.save_pending_invoice()
|
||||
coro = self.wallet.lnworker.pay_invoice(invoice.lightning_invoice, amount_msat=amount_msat, attempts=LN_NUM_PAYMENT_ATTEMPTS)
|
||||
coro = self.wallet.lnworker.pay_invoice(invoice.lightning_invoice, amount_msat=amount_msat)
|
||||
self.run_coroutine_from_thread(coro)
|
||||
|
||||
def on_request_status(self, wallet, key, status):
|
||||
|
||||
@@ -607,6 +607,7 @@ class LNWallet(LNWorker):
|
||||
lnwatcher: Optional['LNWalletWatcher']
|
||||
MPP_EXPIRY = 120
|
||||
TIMEOUT_SHUTDOWN_FAIL_PENDING_HTLCS = 3 # seconds
|
||||
PAYMENT_TIMEOUT = 120
|
||||
|
||||
def __init__(self, wallet: 'Abstract_Wallet', xprv):
|
||||
self.wallet = wallet
|
||||
@@ -1091,7 +1092,7 @@ class LNWallet(LNWorker):
|
||||
async def _pay_scheduled_invoices(self):
|
||||
for invoice in self.wallet.get_scheduled_invoices():
|
||||
if invoice.is_lightning() and self.can_pay_invoice(invoice):
|
||||
await self.pay_invoice(invoice.lightning_invoice, attempts=10)
|
||||
await self.pay_invoice(invoice.lightning_invoice)
|
||||
|
||||
def can_pay_invoice(self, invoice: Invoice) -> bool:
|
||||
assert invoice.is_lightning()
|
||||
@@ -1131,7 +1132,7 @@ class LNWallet(LNWorker):
|
||||
async def pay_invoice(
|
||||
self, invoice: str, *,
|
||||
amount_msat: int = None,
|
||||
attempts: int = 1,
|
||||
attempts: int = None, # used only in unit tests
|
||||
full_path: LNPaymentPath = None) -> Tuple[bool, List[HtlcLog]]:
|
||||
|
||||
lnaddr = self._check_invoice(invoice, amount_msat=amount_msat)
|
||||
@@ -1192,7 +1193,7 @@ class LNWallet(LNWorker):
|
||||
min_cltv_expiry: int,
|
||||
r_tags,
|
||||
invoice_features: int,
|
||||
attempts: int = 1,
|
||||
attempts: int = None,
|
||||
full_path: LNPaymentPath = None,
|
||||
fwd_trampoline_onion=None,
|
||||
fwd_trampoline_fee=None,
|
||||
@@ -1213,7 +1214,7 @@ class LNWallet(LNWorker):
|
||||
use_two_trampolines = True
|
||||
|
||||
trampoline_fee_level = self.INITIAL_TRAMPOLINE_FEE_LEVEL
|
||||
|
||||
start_time = time.time()
|
||||
amount_inflight = 0 # what we sent in htlcs (that receiver gets, without fees)
|
||||
while True:
|
||||
amount_to_send = amount_to_pay - amount_inflight
|
||||
@@ -1269,7 +1270,7 @@ class LNWallet(LNWorker):
|
||||
self.network.path_finder.update_inflight_htlcs(htlc_log.route, add_htlcs=False)
|
||||
return
|
||||
# htlc failed
|
||||
if len(log) >= attempts:
|
||||
if (attempts is not None and len(log) >= attempts) or (attempts is None and time.time() - start_time > self.PAYMENT_TIMEOUT):
|
||||
raise PaymentFailure('Giving up after %d attempts'%len(log))
|
||||
# if we get a tmp channel failure, it might work to split the amount and try more routes
|
||||
# if we get a channel update, we might retry the same route and amount
|
||||
|
||||
@@ -117,6 +117,7 @@ class MockWallet:
|
||||
|
||||
class MockLNWallet(Logger, NetworkRetryManager[LNPeerAddr]):
|
||||
MPP_EXPIRY = 2 # HTLC timestamps are cast to int, so this cannot be 1
|
||||
PAYMENT_TIMEOUT = 120
|
||||
TIMEOUT_SHUTDOWN_FAIL_PENDING_HTLCS = 0
|
||||
INITIAL_TRAMPOLINE_FEE_LEVEL = 0
|
||||
|
||||
|
||||
Reference in New Issue
Block a user