Browse Source

remove scheduled invoices: bad UX. better expect the user to retry later.

patch-4
ThomasV 3 years ago
parent
commit
917f256e33
  1. 4
      electrum/gui/qt/invoice_list.py
  2. 15
      electrum/gui/qt/main_window.py
  3. 3
      electrum/gui/qt/util.py
  4. 3
      electrum/invoices.py
  5. 4
      electrum/lnpeer.py
  6. 18
      electrum/lnworker.py
  7. 6
      electrum/wallet.py

4
electrum/gui/qt/invoice_list.py

@ -33,7 +33,7 @@ from PyQt5.QtWidgets import QMenu, QVBoxLayout, QTreeWidget, QTreeWidgetItem, QH
from electrum.i18n import _
from electrum.util import format_time
from electrum.invoices import Invoice, PR_UNPAID, PR_PAID, PR_INFLIGHT, PR_FAILED, PR_SCHEDULED
from electrum.invoices import Invoice, PR_UNPAID, PR_PAID, PR_INFLIGHT, PR_FAILED
from electrum.lnutil import HtlcLog
from .util import MyTreeView, read_QIcon, MySortModel, pr_icons
@ -160,8 +160,6 @@ class InvoiceList(MyTreeView):
status = wallet.get_invoice_status(invoice)
if status == PR_UNPAID:
menu.addAction(_("Pay") + "...", lambda: self.parent.do_pay_invoice(invoice))
if status == PR_SCHEDULED:
menu.addAction(_("Cancel") + "...", lambda: self.parent.cancel_scheduled_invoice(key))
if status == PR_FAILED:
menu.addAction(_("Retry"), lambda: self.parent.do_pay_invoice(invoice))
if self.parent.wallet.lnworker:

15
electrum/gui/qt/main_window.py

@ -67,7 +67,7 @@ from electrum.util import (format_time,
AddTransactionException, BITCOIN_BIP21_URI_SCHEME,
InvoiceError, parse_max_spend)
from electrum.invoices import PR_DEFAULT_EXPIRATION_WHEN_CREATING, Invoice
from electrum.invoices import PR_PAID, PR_UNPAID, PR_FAILED, PR_SCHEDULED, pr_expiration_values, Invoice
from electrum.invoices import PR_PAID, PR_UNPAID, PR_FAILED, pr_expiration_values, Invoice
from electrum.transaction import (Transaction, PartialTxInput,
PartialTransaction, PartialTxOutput)
from electrum.wallet import (Multisig_Wallet, CannotBumpFee, Abstract_Wallet,
@ -1702,13 +1702,13 @@ class ElectrumWindow(QMainWindow, MessageBoxMixin, Logger):
if can_pay_with_new_channel:
msg = ''.join([
_('Open a new channel'), '\n',
_('Your payment will be scheduled for when the channel is open.')
_('You will be able to pay once the channel is open.')
])
choices[1] = msg
if can_pay_with_swap:
msg = ''.join([
_('Rebalance your channels with a submarine swap'), '\n',
_('Your payment will be scheduled after the swap is confirmed.')
_('You will be able to pay once the swap is confirmed.')
])
choices[2] = msg
if not choices:
@ -1722,11 +1722,9 @@ class ElectrumWindow(QMainWindow, MessageBoxMixin, Logger):
if r == 0:
self.pay_onchain_dialog(coins, invoice.get_outputs())
elif r == 1:
if self.channels_list.new_channel_dialog(amount_sat=channel_funding_sat):
self.wallet.lnworker.set_invoice_status(key, PR_SCHEDULED)
self.channels_list.new_channel_dialog(amount_sat=channel_funding_sat)
elif r == 2:
if self.run_swap_dialog(is_reverse=False, recv_amount_sat=swap_recv_amount_sat):
self.wallet.lnworker.set_invoice_status(key, PR_SCHEDULED)
self.run_swap_dialog(is_reverse=False, recv_amount_sat=swap_recv_amount_sat)
return
# FIXME this is currently lying to user as we truncate to satoshis
@ -1852,9 +1850,6 @@ class ElectrumWindow(QMainWindow, MessageBoxMixin, Logger):
else:
self.pay_onchain_dialog(self.get_coins(), invoice.outputs)
def cancel_scheduled_invoice(self, key):
self.wallet.lnworker.set_invoice_status(key, PR_UNPAID)
def get_coins(self, *, nonlocal_only=False) -> Sequence[PartialTxInput]:
coins = self.get_manually_selected_coins()
if coins is not None:

3
electrum/gui/qt/util.py

@ -28,7 +28,7 @@ from PyQt5.QtWidgets import (QPushButton, QLabel, QMessageBox, QHBoxLayout,
from electrum.i18n import _, languages
from electrum.util import FileImportFailed, FileExportFailed, make_aiohttp_session, resource_path
from electrum.invoices import PR_UNPAID, PR_PAID, PR_EXPIRED, PR_INFLIGHT, PR_UNKNOWN, PR_FAILED, PR_ROUTING, PR_UNCONFIRMED, PR_SCHEDULED
from electrum.invoices import PR_UNPAID, PR_PAID, PR_EXPIRED, PR_INFLIGHT, PR_UNKNOWN, PR_FAILED, PR_ROUTING, PR_UNCONFIRMED
from electrum.logging import Logger
if TYPE_CHECKING:
@ -56,7 +56,6 @@ pr_icons = {
PR_FAILED:"warning.png",
PR_ROUTING:"unconfirmed.png",
PR_UNCONFIRMED:"unconfirmed.png",
PR_SCHEDULED:"unconfirmed.png",
}

3
electrum/invoices.py

@ -28,7 +28,6 @@ PR_INFLIGHT = 4 # only for LN. payment attempt in progress
PR_FAILED = 5 # only for LN. we attempted to pay it, but all attempts failed
PR_ROUTING = 6 # only for LN. *unused* atm.
PR_UNCONFIRMED = 7 # only onchain. invoice is satisfied but tx is not mined yet.
PR_SCHEDULED = 8 # lightning invoice will be paid once channel liquidity is available
pr_color = {
@ -40,7 +39,6 @@ pr_color = {
PR_FAILED: (.9, .2, .2, 1),
PR_ROUTING: (.9, .6, .3, 1),
PR_UNCONFIRMED: (.9, .6, .3, 1),
PR_SCHEDULED: (.9, .6, .3, 1),
}
pr_tooltips = {
@ -52,7 +50,6 @@ pr_tooltips = {
PR_FAILED:_('Failed'),
PR_ROUTING: _('Computing route...'),
PR_UNCONFIRMED: _('Unconfirmed'),
PR_SCHEDULED: _('Scheduled'),
}
PR_DEFAULT_EXPIRATION_WHEN_CREATING = 24*60*60 # 1 day

4
electrum/lnpeer.py

@ -1336,8 +1336,6 @@ class Peer(Logger):
# only allow state transition from "FUNDED" to "OPEN"
old_state = chan.get_state()
if old_state == ChannelState.OPEN:
if self.lnworker:
self.lnworker.pay_scheduled_invoices()
return
if old_state != ChannelState.FUNDED:
self.logger.info(f"cannot mark open ({chan.get_id_for_log()}), current state: {repr(old_state)}")
@ -1357,8 +1355,6 @@ class Peer(Logger):
self.logger.info(f"sending channel update for outgoing edge ({chan.get_id_for_log()})")
chan_upd = chan.get_outgoing_gossip_channel_update()
self.transport.send_bytes(chan_upd)
if self.lnworker:
self.lnworker.pay_scheduled_invoices()
def send_announcement_signatures(self, chan: Channel):
chan_ann = chan.construct_channel_announcement_without_sigs()

18
electrum/lnworker.py

@ -28,7 +28,7 @@ from aiorpcx import run_in_thread, NetAddress, ignore_after
from . import constants, util
from . import keystore
from .util import profiler, chunks, OldTaskGroup
from .invoices import Invoice, PR_UNPAID, PR_EXPIRED, PR_PAID, PR_INFLIGHT, PR_FAILED, PR_ROUTING, PR_SCHEDULED, LN_EXPIRY_NEVER
from .invoices import Invoice, PR_UNPAID, PR_EXPIRED, PR_PAID, PR_INFLIGHT, PR_FAILED, PR_ROUTING, LN_EXPIRY_NEVER
from .util import NetworkRetryManager, JsonRPCClient
from .lnutil import LN_MAX_FUNDING_SAT
from .keystore import BIP32_KeyStore
@ -90,7 +90,7 @@ if TYPE_CHECKING:
from .simple_config import SimpleConfig
SAVED_PR_STATUS = [PR_PAID, PR_UNPAID, PR_SCHEDULED] # status that are persisted
SAVED_PR_STATUS = [PR_PAID, PR_UNPAID] # status that are persisted
NUM_PEERS_TARGET = 4
@ -1086,14 +1086,6 @@ class LNWallet(LNWorker):
if chan.short_channel_id == short_channel_id:
return chan
def pay_scheduled_invoices(self):
asyncio.ensure_future(self._pay_scheduled_invoices())
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)
def can_pay_invoice(self, invoice: Invoice) -> bool:
assert invoice.is_lightning()
return (invoice.get_amount_sat() or 0) <= self.num_sats_can_send()
@ -1910,13 +1902,9 @@ class LNWallet(LNWorker):
def set_payment_status(self, payment_hash: bytes, status: int) -> None:
info = self.get_payment_info(payment_hash)
if info is None and status != PR_SCHEDULED:
if info is None:
# if we are forwarding
return
if info is None and status == PR_SCHEDULED:
# we should add a htlc to our ctx, so that the funds are 'reserved'
# Note: info.amount will be added by pay_invoice
info = PaymentInfo(payment_hash, None, SENT, PR_SCHEDULED)
info = info._replace(status=status)
self.save_payment_info(info)

6
electrum/wallet.py

@ -74,7 +74,7 @@ from .plugin import run_hook
from .address_synchronizer import (AddressSynchronizer, TX_HEIGHT_LOCAL,
TX_HEIGHT_UNCONF_PARENT, TX_HEIGHT_UNCONFIRMED, TX_HEIGHT_FUTURE)
from .invoices import Invoice
from .invoices import PR_PAID, PR_UNPAID, PR_UNKNOWN, PR_EXPIRED, PR_UNCONFIRMED, PR_SCHEDULED
from .invoices import PR_PAID, PR_UNPAID, PR_UNKNOWN, PR_EXPIRED, PR_UNCONFIRMED
from .contacts import Contacts
from .interface import NetworkException
from .mnemonic import Mnemonic
@ -826,10 +826,6 @@ class Abstract_Wallet(AddressSynchronizer, ABC):
invoices = self.get_invoices()
return [x for x in invoices if self.get_invoice_status(x) != PR_PAID]
def get_scheduled_invoices(self):
invoices = self.get_invoices()
return [x for x in invoices if self.get_invoice_status(x) == PR_SCHEDULED]
def get_invoice(self, key):
return self.invoices.get(key)

Loading…
Cancel
Save