mirror of
https://github.com/LBRYFoundation/LBRY-Vault.git
synced 2025-08-23 17:47:31 +00:00
qt: pay_lightning_invoice - attempt paying multiple times in case of failure
This commit is contained in:
parent
4d1785799b
commit
b85aea1541
4 changed files with 39 additions and 11 deletions
|
@ -1664,13 +1664,37 @@ class ElectrumWindow(QMainWindow, MessageBoxMixin, Logger):
|
||||||
self.do_send(preview = True)
|
self.do_send(preview = True)
|
||||||
|
|
||||||
def pay_lightning_invoice(self, invoice):
|
def pay_lightning_invoice(self, invoice):
|
||||||
try:
|
amount = self.amount_e.get_amount()
|
||||||
amount = self.amount_e.get_amount()
|
LN_NUM_PAYMENT_ATTEMPTS = 1 # TODO increase
|
||||||
f = self.wallet.lnworker.pay(invoice, amount_sat=amount)
|
|
||||||
except InvoiceError as e:
|
def on_success(result):
|
||||||
self.show_error(str(e))
|
self.print_error('ln payment success', result)
|
||||||
else:
|
|
||||||
self.do_clear()
|
self.do_clear()
|
||||||
|
def on_failure(exc_info):
|
||||||
|
type_, e, traceback = exc_info
|
||||||
|
if isinstance(e, PaymentFailure):
|
||||||
|
self.show_error(_('Payment failed. Tried {} times:\n{}')
|
||||||
|
.format(LN_NUM_PAYMENT_ATTEMPTS, e))
|
||||||
|
elif isinstance(e, InvoiceError):
|
||||||
|
self.show_error(_('InvoiceError: {}').format(e))
|
||||||
|
else:
|
||||||
|
raise e
|
||||||
|
def task():
|
||||||
|
failure_list = []
|
||||||
|
for i in range(LN_NUM_PAYMENT_ATTEMPTS):
|
||||||
|
try:
|
||||||
|
future = self.wallet.lnworker.pay(invoice, amount_sat=amount)
|
||||||
|
future.result()
|
||||||
|
break
|
||||||
|
except PaymentFailure as e:
|
||||||
|
failure_list.append(e)
|
||||||
|
# try again
|
||||||
|
else:
|
||||||
|
msg = '\n'.join(str(e) for e in failure_list)
|
||||||
|
raise PaymentFailure(msg)
|
||||||
|
|
||||||
|
msg = _('Sending lightning payment...')
|
||||||
|
WaitingDialog(self, msg, task, on_success, on_failure)
|
||||||
|
|
||||||
def do_send(self, preview = False):
|
def do_send(self, preview = False):
|
||||||
if self.payto_e.is_lightning:
|
if self.payto_e.is_lightning:
|
||||||
|
|
|
@ -248,7 +248,9 @@ class LnAddr(object):
|
||||||
", ".join([k + '=' + str(v) for k, v in self.tags])
|
", ".join([k + '=' + str(v) for k, v in self.tags])
|
||||||
)
|
)
|
||||||
|
|
||||||
def lndecode(a, verbose=False, expected_hrp=constants.net.SEGWIT_HRP):
|
def lndecode(a, verbose=False, expected_hrp=None):
|
||||||
|
if expected_hrp is None:
|
||||||
|
expected_hrp = constants.net.SEGWIT_HRP
|
||||||
hrp, data = bech32_decode(a, ignore_long_length=True)
|
hrp, data = bech32_decode(a, ignore_long_length=True)
|
||||||
if not hrp:
|
if not hrp:
|
||||||
raise ValueError("Bad bech32 checksum")
|
raise ValueError("Bad bech32 checksum")
|
||||||
|
|
|
@ -511,10 +511,12 @@ class HTLCStateMachine(PrintError):
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def htlcs_in_local(self):
|
def htlcs_in_local(self):
|
||||||
|
"""in the local log. 'offered by us'"""
|
||||||
return self.gen_htlc_indices("local")
|
return self.gen_htlc_indices("local")
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def htlcs_in_remote(self):
|
def htlcs_in_remote(self):
|
||||||
|
"""in the remote log. 'offered by them'"""
|
||||||
return self.gen_htlc_indices("remote")
|
return self.gen_htlc_indices("remote")
|
||||||
|
|
||||||
def settle_htlc(self, preimage, htlc_id):
|
def settle_htlc(self, preimage, htlc_id):
|
||||||
|
|
|
@ -16,7 +16,8 @@ from .lnbase import Peer, privkey_to_pubkey, aiosafe
|
||||||
from .lnaddr import lnencode, LnAddr, lndecode
|
from .lnaddr import lnencode, LnAddr, lndecode
|
||||||
from .ecc import der_sig_from_sig_string
|
from .ecc import der_sig_from_sig_string
|
||||||
from .lnhtlc import HTLCStateMachine
|
from .lnhtlc import HTLCStateMachine
|
||||||
from .lnutil import Outpoint, calc_short_channel_id, LNPeerAddr, get_compressed_pubkey_from_bech32
|
from .lnutil import (Outpoint, calc_short_channel_id, LNPeerAddr, get_compressed_pubkey_from_bech32,
|
||||||
|
PaymentFailure)
|
||||||
from .lnwatcher import LNChanCloseHandler
|
from .lnwatcher import LNChanCloseHandler
|
||||||
from .i18n import _
|
from .i18n import _
|
||||||
|
|
||||||
|
@ -175,7 +176,6 @@ class LNWorker(PrintError):
|
||||||
return asyncio.run_coroutine_threadsafe(coro, self.network.asyncio_loop)
|
return asyncio.run_coroutine_threadsafe(coro, self.network.asyncio_loop)
|
||||||
|
|
||||||
def pay(self, invoice, amount_sat=None):
|
def pay(self, invoice, amount_sat=None):
|
||||||
# TODO try some number of paths (e.g. 10) in case of failures
|
|
||||||
addr = lndecode(invoice, expected_hrp=constants.net.SEGWIT_HRP)
|
addr = lndecode(invoice, expected_hrp=constants.net.SEGWIT_HRP)
|
||||||
payment_hash = addr.paymenthash
|
payment_hash = addr.paymenthash
|
||||||
invoice_pubkey = addr.pubkey.serialize()
|
invoice_pubkey = addr.pubkey.serialize()
|
||||||
|
@ -185,7 +185,7 @@ class LNWorker(PrintError):
|
||||||
amount_msat = int(amount_sat * 1000)
|
amount_msat = int(amount_sat * 1000)
|
||||||
path = self.network.path_finder.find_path_for_payment(self.pubkey, invoice_pubkey, amount_msat)
|
path = self.network.path_finder.find_path_for_payment(self.pubkey, invoice_pubkey, amount_msat)
|
||||||
if path is None:
|
if path is None:
|
||||||
raise Exception("No path found")
|
raise PaymentFailure(_("No path found"))
|
||||||
node_id, short_channel_id = path[0]
|
node_id, short_channel_id = path[0]
|
||||||
peer = self.peers[node_id]
|
peer = self.peers[node_id]
|
||||||
with self.lock:
|
with self.lock:
|
||||||
|
@ -194,7 +194,7 @@ class LNWorker(PrintError):
|
||||||
if chan.short_channel_id == short_channel_id:
|
if chan.short_channel_id == short_channel_id:
|
||||||
break
|
break
|
||||||
else:
|
else:
|
||||||
raise Exception("ChannelDB returned path with short_channel_id that is not in channel list")
|
raise Exception("ChannelDB returned path with short_channel_id {} that is not in channel list".format(bh2u(short_channel_id)))
|
||||||
coro = peer.pay(path, chan, amount_msat, payment_hash, invoice_pubkey, addr.min_final_cltv_expiry)
|
coro = peer.pay(path, chan, amount_msat, payment_hash, invoice_pubkey, addr.min_final_cltv_expiry)
|
||||||
return asyncio.run_coroutine_threadsafe(coro, self.network.asyncio_loop)
|
return asyncio.run_coroutine_threadsafe(coro, self.network.asyncio_loop)
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue