commit b0d60007719ede7d4bc213a9393667e9b9328161
parent 26ced1b34375ae2ae73ed7e55c2c80b47b6f4930
Author: ThomasV <thomasv@electrum.org>
Date: Mon, 28 Jan 2019 11:14:30 +0100
turn lightning_payments_completed into dict. Show status of lightning payments in GUI. Make 'listchannels' available offline
Diffstat:
7 files changed, 73 insertions(+), 53 deletions(-)
diff --git a/electrum/commands.py b/electrum/commands.py
@@ -786,7 +786,7 @@ class Commands:
def nodeid(self):
return bh2u(self.wallet.lnworker.node_keypair.pubkey)
- @command('wn')
+ @command('w')
def listchannels(self):
return list(self.wallet.lnworker.list_channels())
@@ -806,7 +806,38 @@ class Commands:
@command('w')
def listinvoices(self):
- return "\n".join(self.wallet.lnworker.list_invoices())
+ report = self.wallet.lnworker._list_invoices()
+ return '\n'.join(self._format_ln_invoices(report))
+
+ def _format_ln_invoices(self, report):
+ from .lnutil import SENT
+ if report['settled']:
+ yield 'Settled invoices:'
+ yield '-----------------'
+ for date, direction, htlc, preimage in sorted(report['settled']):
+ # astimezone converts to local time
+ # replace removes the tz info since we don't need to display it
+ yield 'Paid at: ' + date.astimezone().replace(tzinfo=None).isoformat(sep=' ', timespec='minutes')
+ yield 'We paid' if direction == SENT else 'They paid'
+ yield str(htlc)
+ yield 'Preimage: ' + (bh2u(preimage) if preimage else 'Not available') # if delete_invoice was called
+ yield ''
+ if report['unsettled']:
+ yield 'Your unsettled invoices:'
+ yield '------------------------'
+ for addr, preimage, pay_req in report['unsettled']:
+ yield pay_req
+ yield str(addr)
+ yield 'Preimage: ' + bh2u(preimage)
+ yield ''
+ if report['inflight']:
+ yield 'Outgoing payments in progress:'
+ yield '------------------------------'
+ for addr, htlc, direction in report['inflight']:
+ yield str(addr)
+ yield str(htlc)
+ yield ''
+
@command('wn')
def closechannel(self, channel_point, force=False):
diff --git a/electrum/gui/kivy/uix/screens.py b/electrum/gui/kivy/uix/screens.py
@@ -26,7 +26,7 @@ from electrum.util import profiler, parse_URI, format_time, InvalidPassword, Not
from electrum import bitcoin, constants
from electrum.transaction import TxOutput, Transaction, tx_from_str
from electrum.util import send_exception_to_crash_reporter, parse_URI, InvalidBitcoinURI
-from electrum.paymentrequest import PR_UNPAID, PR_PAID, PR_UNKNOWN, PR_EXPIRED
+from electrum.util import PR_UNPAID, PR_PAID, PR_UNKNOWN, PR_EXPIRED
from electrum.plugin import run_hook
from electrum.wallet import InternalAddressCorruption
from electrum import simple_config
diff --git a/electrum/gui/qt/request_list.py b/electrum/gui/qt/request_list.py
@@ -31,8 +31,8 @@ from PyQt5.QtCore import Qt, QItemSelectionModel
from electrum.i18n import _
from electrum.util import format_time, age
+from electrum.util import PR_UNPAID, PR_EXPIRED, PR_PAID, PR_UNKNOWN, PR_INFLIGHT
from electrum.plugin import run_hook
-from electrum.paymentrequest import PR_UNKNOWN
from electrum.wallet import InternalAddressCorruption
from electrum.bitcoin import COIN
from electrum.lnaddr import lndecode
@@ -144,7 +144,9 @@ class RequestList(MyTreeView):
items[0].setData(address, ROLE_RHASH_OR_ADDR)
self.filter()
# lightning
- for payreq_key, (preimage_hex, invoice) in self.wallet.lnworker.invoices.items():
+ lnworker = self.wallet.lnworker
+ for key, (preimage_hex, invoice) in lnworker.invoices.items():
+ status = lnworker.get_invoice_status(key)
lnaddr = lndecode(invoice, expected_hrp=constants.net.SEGWIT_HRP)
amount_sat = lnaddr.amount*COIN if lnaddr.amount else None
amount_str = self.parent.format_amount(amount_sat) if amount_sat else ''
@@ -154,11 +156,13 @@ class RequestList(MyTreeView):
description = v
break
date = format_time(lnaddr.date)
- labels = [date, 'lightning', description, amount_str, '']
+ labels = [date, 'lightning', description, amount_str, pr_tooltips.get(status,'')]
items = [QStandardItem(e) for e in labels]
items[1].setIcon(self.icon_cache.get(":icons/lightning.png"))
items[0].setData(REQUEST_TYPE_LN, ROLE_REQUEST_TYPE)
- items[0].setData(payreq_key, ROLE_RHASH_OR_ADDR)
+ items[0].setData(key, ROLE_RHASH_OR_ADDR)
+ if status is not PR_UNKNOWN:
+ items[4].setIcon(self.icon_cache.get(pr_icons.get(status)))
self.model().insertRow(self.model().rowCount(), items)
# sort requests by date
self.model().sort(0)
diff --git a/electrum/gui/qt/util.py b/electrum/gui/qt/util.py
@@ -23,9 +23,8 @@ from PyQt5.QtWidgets import (QPushButton, QLabel, QMessageBox, QHBoxLayout,
QHeaderView, QApplication, QToolTip, QTreeWidget, QStyledItemDelegate)
from electrum.i18n import _, languages
-from electrum.util import (FileImportFailed, FileExportFailed,
- resource_path)
-from electrum.paymentrequest import PR_UNPAID, PR_PAID, PR_EXPIRED
+from electrum.util import FileImportFailed, FileExportFailed, make_aiohttp_session, PrintError, resource_path
+from electrum.util import PR_UNPAID, PR_PAID, PR_EXPIRED, PR_INFLIGHT
if TYPE_CHECKING:
from .main_window import ElectrumWindow
@@ -44,13 +43,15 @@ dialogs = []
pr_icons = {
PR_UNPAID:"unpaid.png",
PR_PAID:"confirmed.png",
- PR_EXPIRED:"expired.png"
+ PR_EXPIRED:"expired.png",
+ PR_INFLIGHT:"lightning.png",
}
pr_tooltips = {
PR_UNPAID:_('Pending'),
PR_PAID:_('Paid'),
- PR_EXPIRED:_('Expired')
+ PR_EXPIRED:_('Expired'),
+ PR_INFLIGHT:_('Inflight')
}
expiration_values = [
diff --git a/electrum/lnworker.py b/electrum/lnworker.py
@@ -67,13 +67,14 @@ class LNWorker(PrintError):
def __init__(self, wallet: 'Abstract_Wallet'):
self.wallet = wallet
# invoices we are currently trying to pay (might be pending HTLCs on a commitment transaction)
+ self.invoices = self.wallet.storage.get('lightning_invoices', {}) # type: Dict[str, Tuple[str,str]] # RHASH -> (preimage, invoice)
self.paying = self.wallet.storage.get('lightning_payments_inflight', {}) # type: Dict[bytes, Tuple[str, Optional[int], str]]
+ self.completed = self.wallet.storage.get('lightning_payments_completed', {})
self.sweep_address = wallet.get_receiving_address()
self.lock = threading.RLock()
self.ln_keystore = self._read_ln_keystore()
self.node_keypair = generate_keypair(self.ln_keystore, LnKeyFamily.NODE_KEY, 0)
self.peers = {} # type: Dict[bytes, Peer] # pubkey -> Peer
- self.invoices = wallet.storage.get('lightning_invoices', {}) # type: Dict[str, Tuple[str,str]] # RHASH -> (preimage, invoice)
self.channels = {} # type: Dict[bytes, Channel]
for x in wallet.storage.get("channels", []):
c = Channel(x, sweep_address=self.sweep_address, payment_completed=self.payment_completed)
@@ -123,56 +124,37 @@ class LNWorker(PrintError):
def payment_completed(self, chan, direction, htlc, preimage):
assert type(direction) is Direction
+ key = bh2u(htlc.payment_hash)
chan_id = chan.channel_id
if direction == SENT:
assert htlc.payment_hash not in self.invoices
- self.paying.pop(bh2u(htlc.payment_hash))
+ self.paying.pop(key)
self.wallet.storage.put('lightning_payments_inflight', self.paying)
- l = self.wallet.storage.get('lightning_payments_completed', [])
if not preimage:
preimage, _addr = self.get_invoice(htlc.payment_hash)
tupl = (time.time(), direction, json.loads(encoder.encode(htlc)), bh2u(preimage), bh2u(chan_id))
- l.append(tupl)
- self.wallet.storage.put('lightning_payments_completed', l)
+ self.completed[key] = tupl
+ self.wallet.storage.put('lightning_payments_completed', self.completed)
self.wallet.storage.write()
self.network.trigger_callback('ln_payment_completed', tupl[0], direction, htlc, preimage, chan_id)
- def list_invoices(self):
- report = self._list_invoices()
- if report['settled']:
- yield 'Settled invoices:'
- yield '-----------------'
- for date, direction, htlc, preimage in sorted(report['settled']):
- # astimezone converts to local time
- # replace removes the tz info since we don't need to display it
- yield 'Paid at: ' + date.astimezone().replace(tzinfo=None).isoformat(sep=' ', timespec='minutes')
- yield 'We paid' if direction == SENT else 'They paid'
- yield str(htlc)
- yield 'Preimage: ' + (bh2u(preimage) if preimage else 'Not available') # if delete_invoice was called
- yield ''
- if report['unsettled']:
- yield 'Your unsettled invoices:'
- yield '------------------------'
- for addr, preimage, pay_req in report['unsettled']:
- yield pay_req
- yield str(addr)
- yield 'Preimage: ' + bh2u(preimage)
- yield ''
- if report['inflight']:
- yield 'Outgoing payments in progress:'
- yield '------------------------------'
- for addr, htlc, direction in report['inflight']:
- yield str(addr)
- yield str(htlc)
- yield ''
+ def get_invoice_status(self, key):
+ from electrum.util import PR_UNPAID, PR_EXPIRED, PR_PAID, PR_UNKNOWN, PR_INFLIGHT
+ if key in self.completed:
+ return PR_PAID
+ elif key in self.paying:
+ return PR_INFLIGHT
+ elif key in self.invoices:
+ return PR_UNPAID
+ else:
+ return PR_UNKNOWN
def _list_invoices(self, chan_id=None):
invoices = dict(self.invoices)
- completed = self.wallet.storage.get('lightning_payments_completed', [])
settled = []
unsettled = []
inflight = []
- for date, direction, htlc, hex_preimage, hex_chan_id in completed:
+ for date, direction, htlc, hex_preimage, hex_chan_id in self.completed.values():
direction = Direction(direction)
if chan_id is not None:
if bfh(hex_chan_id) != chan_id:
diff --git a/electrum/paymentrequest.py b/electrum/paymentrequest.py
@@ -41,6 +41,7 @@ except ImportError:
from . import bitcoin, ecc, util, transaction, x509, rsakey
from .util import bh2u, bfh, export_meta, import_meta, make_aiohttp_session
+from .util import PR_UNPAID, PR_EXPIRED, PR_PAID, PR_UNKNOWN, PR_INFLIGHT
from .crypto import sha256
from .bitcoin import TYPE_ADDRESS
from .transaction import TxOutput
@@ -65,12 +66,6 @@ def load_ca_list():
-# status of payment requests
-PR_UNPAID = 0
-PR_EXPIRED = 1
-PR_UNKNOWN = 2 # sent but not propagated
-PR_PAID = 3 # send and propagated
-
async def get_payment_request(url: str) -> 'PaymentRequest':
u = urllib.parse.urlparse(url)
diff --git a/electrum/util.py b/electrum/util.py
@@ -73,6 +73,13 @@ base_units_list = ['BTC', 'mBTC', 'bits', 'sat'] # list(dict) does not guarante
DECIMAL_POINT_DEFAULT = 5 # mBTC
+# status of payment requests
+PR_UNPAID = 0
+PR_EXPIRED = 1
+PR_UNKNOWN = 2 # sent but not propagated
+PR_PAID = 3 # send and propagated
+PR_INFLIGHT = 4 # lightning
+
class UnknownBaseUnit(Exception): pass