mirror of
https://github.com/LBRYFoundation/LBRY-Vault.git
synced 2025-09-18 08:29:49 +00:00
qt: channel_details: add more info: sent/received, channel id, funding tx, short channel id, node id
This commit is contained in:
parent
762d8be84f
commit
864d910888
4 changed files with 91 additions and 21 deletions
|
@ -5,10 +5,12 @@ import PyQt5.QtWidgets as QtWidgets
|
|||
import PyQt5.QtCore as QtCore
|
||||
|
||||
from electrum.i18n import _
|
||||
from electrum.lnchan import UpdateAddHtlc
|
||||
from electrum.lnchan import UpdateAddHtlc, HTLCOwner
|
||||
from electrum.util import bh2u, format_time
|
||||
from electrum.lnchan import HTLCOwner
|
||||
from electrum.lnutil import format_short_channel_id, SENT, RECEIVED
|
||||
from electrum.lnaddr import LnAddr, lndecode
|
||||
from electrum.bitcoin import COIN
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from .main_window import ElectrumWindow
|
||||
|
||||
|
@ -17,22 +19,38 @@ class HTLCItem(QtGui.QStandardItem):
|
|||
super().__init__(*args, **kwargs)
|
||||
self.setEditable(False)
|
||||
|
||||
class ChannelDetailsDialog(QtWidgets.QDialog):
|
||||
class SelectableLabel(QtWidgets.QLabel):
|
||||
def __init__(self, text=''):
|
||||
super().__init__(text)
|
||||
self.setTextInteractionFlags(QtCore.Qt.TextSelectableByMouse)
|
||||
|
||||
def make_inflight(self, lnaddr, i: UpdateAddHtlc):
|
||||
it = HTLCItem(_('HTLC with ID ') + str(i.htlc_id))
|
||||
class LinkedLabel(QtWidgets.QLabel):
|
||||
def __init__(self, text, on_clicked):
|
||||
super().__init__(text)
|
||||
self.linkActivated.connect(on_clicked)
|
||||
|
||||
class ChannelDetailsDialog(QtWidgets.QDialog):
|
||||
def make_htlc_item(self, i: UpdateAddHtlc, direction: HTLCOwner) -> HTLCItem:
|
||||
it = HTLCItem(_('Sent HTLC with ID {}' if SENT == direction else 'Received HTLC with ID {}').format(i.htlc_id))
|
||||
it.appendRow([HTLCItem(_('Amount')),HTLCItem(self.format(i.amount_msat))])
|
||||
it.appendRow([HTLCItem(_('CLTV expiry')),HTLCItem(str(i.cltv_expiry))])
|
||||
it.appendRow([HTLCItem(_('Payment hash')),HTLCItem(bh2u(i.payment_hash))])
|
||||
return it
|
||||
|
||||
def append_lnaddr(self, it: HTLCItem, lnaddr: LnAddr):
|
||||
invoice = HTLCItem(_('Invoice'))
|
||||
invoice.appendRow([HTLCItem(_('Remote node public key')), HTLCItem(bh2u(lnaddr.pubkey.serialize()))])
|
||||
invoice.appendRow([HTLCItem(_('Amount in BTC')), HTLCItem(str(lnaddr.amount))])
|
||||
invoice.appendRow([HTLCItem(_('Amount in sat')), HTLCItem(str(lnaddr.amount * COIN))]) # might have a comma because mSAT!
|
||||
invoice.appendRow([HTLCItem(_('Description')), HTLCItem(dict(lnaddr.tags).get('d', _('N/A')))])
|
||||
invoice.appendRow([HTLCItem(_('Date')), HTLCItem(format_time(lnaddr.date))])
|
||||
it.appendRow([invoice])
|
||||
|
||||
def make_inflight(self, lnaddr, i: UpdateAddHtlc, direction: HTLCOwner) -> HTLCItem:
|
||||
it = self.make_htlc_item(i, direction)
|
||||
self.append_lnaddr(it, lnaddr)
|
||||
return it
|
||||
|
||||
def make_model(self, htlcs):
|
||||
def make_model(self, htlcs) -> QtGui.QStandardItemModel:
|
||||
model = QtGui.QStandardItemModel(0, 2)
|
||||
model.setHorizontalHeaderLabels(['HTLC', 'Property value'])
|
||||
parentItem = model.invisibleRootItem()
|
||||
|
@ -41,6 +59,8 @@ class ChannelDetailsDialog(QtWidgets.QDialog):
|
|||
|
||||
self.keyname_rows = {}
|
||||
|
||||
invoices = dict(self.window.wallet.lnworker.invoices)
|
||||
|
||||
for keyname, i in folder_types.items():
|
||||
myFont=QtGui.QFont()
|
||||
myFont.setBold(True)
|
||||
|
@ -51,18 +71,19 @@ class ChannelDetailsDialog(QtWidgets.QDialog):
|
|||
mapping = {}
|
||||
num = 0
|
||||
if keyname == 'inflight':
|
||||
for lnaddr, i in htlcs[keyname]:
|
||||
it = self.make_inflight(lnaddr, i)
|
||||
for lnaddr, i, direction in htlcs[keyname]:
|
||||
it = self.make_inflight(lnaddr, i, direction)
|
||||
self.folders[keyname].appendRow(it)
|
||||
mapping[i.payment_hash] = num
|
||||
num += 1
|
||||
elif keyname == 'settled':
|
||||
for date, direction, i, preimage in htlcs[keyname]:
|
||||
it = HTLCItem(_('HTLC with ID ') + str(i.htlc_id))
|
||||
it.appendRow([HTLCItem(_('Amount')),HTLCItem(self.format(i.amount_msat))])
|
||||
it.appendRow([HTLCItem(_('CLTV expiry')),HTLCItem(str(i.cltv_expiry))])
|
||||
it.appendRow([HTLCItem(_('Payment hash')),HTLCItem(bh2u(i.payment_hash))])
|
||||
# NOTE no invoices because user can delete invoices after settlement
|
||||
it = self.make_htlc_item(i, direction)
|
||||
hex_pay_hash = bh2u(i.payment_hash)
|
||||
if hex_pay_hash in invoices:
|
||||
# if we made the invoice and still have it, we can show more info
|
||||
invoice = invoices[hex_pay_hash][1]
|
||||
self.append_lnaddr(it, lndecode(invoice))
|
||||
self.folders[keyname].appendRow(it)
|
||||
mapping[i.payment_hash] = num
|
||||
num += 1
|
||||
|
@ -85,25 +106,65 @@ class ChannelDetailsDialog(QtWidgets.QDialog):
|
|||
def do_htlc_added(self, evtname, htlc, lnaddr, direction):
|
||||
mapping = self.keyname_rows['inflight']
|
||||
mapping[htlc.payment_hash] = len(mapping)
|
||||
self.folders['inflight'].appendRow(self.make_inflight(lnaddr, htlc))
|
||||
self.folders['inflight'].appendRow(self.make_inflight(lnaddr, htlc, direction))
|
||||
|
||||
@QtCore.pyqtSlot(str, float, HTLCOwner, UpdateAddHtlc, bytes, bytes)
|
||||
def do_ln_payment_completed(self, evtname, date, direction, htlc, preimage, chan_id):
|
||||
self.move('inflight', 'settled', htlc.payment_hash)
|
||||
self.update_sent_received()
|
||||
|
||||
def update_sent_received(self):
|
||||
self.sent_label.setText(str(sum(self.chan.settled[SENT])))
|
||||
self.received_label.setText(str(sum(self.chan.settled[RECEIVED])))
|
||||
|
||||
@QtCore.pyqtSlot(str)
|
||||
def show_tx(self, link_text: str):
|
||||
funding_tx = self.window.wallet.transactions[self.chan.funding_outpoint.txid]
|
||||
self.window.show_transaction(funding_tx, tx_desc=_('Funding Transaction'))
|
||||
|
||||
def __init__(self, window: 'ElectrumWindow', chan_id: bytes):
|
||||
super().__init__(window)
|
||||
|
||||
# initialize instance fields
|
||||
self.window = window
|
||||
chan = self.chan = window.wallet.lnworker.channels[chan_id]
|
||||
self.format = lambda msat: window.format_amount_and_units(msat / 1000)
|
||||
|
||||
# connect signals with slots
|
||||
self.ln_payment_completed.connect(self.do_ln_payment_completed)
|
||||
self.htlc_added.connect(self.do_htlc_added)
|
||||
htlcs = window.wallet.lnworker._list_invoices(chan_id)
|
||||
self.format = lambda msat: window.format_amount_and_units(msat / 1000)
|
||||
|
||||
# register callbacks for updating
|
||||
window.network.register_callback(self.ln_payment_completed.emit, ['ln_payment_completed'])
|
||||
window.network.register_callback(self.htlc_added.emit, ['htlc_added'])
|
||||
|
||||
# set attributes of QDialog
|
||||
self.setWindowTitle(_('Channel Details'))
|
||||
self.setMinimumSize(800, 400)
|
||||
|
||||
# add layouts
|
||||
vbox = QtWidgets.QVBoxLayout(self)
|
||||
form_layout = QtWidgets.QFormLayout(None)
|
||||
vbox.addLayout(form_layout)
|
||||
|
||||
# add form content
|
||||
form_layout.addRow(_('Node ID:'), SelectableLabel(bh2u(chan.node_id)))
|
||||
form_layout.addRow(_('Channel ID:'), SelectableLabel(bh2u(chan.channel_id)))
|
||||
funding_label_text = f'<a href=click_destination>{chan.funding_outpoint.txid}</a>:{chan.funding_outpoint.output_index}'
|
||||
form_layout.addRow(_('Funding Outpoint:'), LinkedLabel(funding_label_text, self.show_tx))
|
||||
form_layout.addRow(_('Short Channel ID:'), SelectableLabel(format_short_channel_id(chan.short_channel_id)))
|
||||
self.received_label = SelectableLabel()
|
||||
form_layout.addRow(_('Received (mSAT):'), self.received_label)
|
||||
self.sent_label = SelectableLabel()
|
||||
form_layout.addRow(_('Sent (mSAT):'), self.sent_label)
|
||||
|
||||
# add htlc tree view to vbox (wouldn't scale correctly in QFormLayout)
|
||||
form_layout.addRow(_('Payments (HTLCs):'), None)
|
||||
w = QtWidgets.QTreeView(self)
|
||||
htlcs = window.wallet.lnworker._list_invoices(chan_id)
|
||||
w.setModel(self.make_model(htlcs))
|
||||
#w.header().setStretchLastSection(False)
|
||||
w.header().setSectionResizeMode(0, QtWidgets.QHeaderView.ResizeToContents)
|
||||
vbox.addWidget(w)
|
||||
|
||||
# initialize sent/received fields
|
||||
self.update_sent_received()
|
||||
|
|
|
@ -46,7 +46,10 @@ class ChannelsList(MyTreeWidget):
|
|||
network = self.parent.network
|
||||
lnworker = self.parent.wallet.lnworker
|
||||
menu = QMenu()
|
||||
channel_id = self.currentItem().data(0, QtCore.Qt.UserRole)
|
||||
item = self.currentItem()
|
||||
if not item:
|
||||
return
|
||||
channel_id = item.data(0, QtCore.Qt.UserRole)
|
||||
def on_success(txid):
|
||||
self.main_window.show_error('Channel closed' + '\n' + txid)
|
||||
def on_failure(exc_info):
|
||||
|
|
|
@ -664,3 +664,9 @@ class EncumberedTransaction(NamedTuple("EncumberedTransaction", [('name', str),
|
|||
NUM_MAX_HOPS_IN_PAYMENT_PATH = 20
|
||||
NUM_MAX_EDGES_IN_PAYMENT_PATH = NUM_MAX_HOPS_IN_PAYMENT_PATH + 1
|
||||
|
||||
def format_short_channel_id(short_channel_id: Optional[bytes]):
|
||||
if not short_channel_id:
|
||||
return _('Not yet available')
|
||||
return str(int.from_bytes(short_channel_id[:3], 'big')) \
|
||||
+ 'x' + str(int.from_bytes(short_channel_id[3:6], 'big')) \
|
||||
+ 'x' + str(int.from_bytes(short_channel_id[6:], 'big'))
|
||||
|
|
|
@ -128,7 +128,7 @@ class LNWorker(PrintError):
|
|||
if report['inflight']:
|
||||
yield 'Outgoing payments in progress:'
|
||||
yield '------------------------------'
|
||||
for addr, htlc in report['inflight']:
|
||||
for addr, htlc, direction in report['inflight']:
|
||||
yield str(addr)
|
||||
yield str(htlc)
|
||||
yield ''
|
||||
|
@ -162,7 +162,7 @@ class LNWorker(PrintError):
|
|||
htlc = self.find_htlc_for_addr(addr, None if chan_id is None else [chan_id])
|
||||
if not htlc:
|
||||
self.print_error('Warning, in flight HTLC not found in any channel')
|
||||
inflight.append((addr, htlc))
|
||||
inflight.append((addr, htlc, direction))
|
||||
return {'settled': settled, 'unsettled': unsettled, 'inflight': inflight}
|
||||
|
||||
def find_htlc_for_addr(self, addr, whitelist=None):
|
||||
|
|
Loading…
Add table
Reference in a new issue