URI: 
       tDisplay channel status in the GUI. - electrum - Electrum Bitcoin wallet
  HTML git clone https://git.parazyd.org/electrum
   DIR Log
   DIR Files
   DIR Refs
   DIR Submodules
       ---
   DIR commit 21c883bd0b1acf7a8c06543c9fb3aaf95fbe68ed
   DIR parent bf6d28e1f0146d8de0359e05e9ea64cd999fdd90
  HTML Author: ThomasV <thomasv@electrum.org>
       Date:   Mon,  4 Jun 2018 20:53:34 +0200
       
       Display channel status in the GUI.
       
       Do not convert channel_id to integer; there is no reason to do that.
       
       Diffstat:
         M gui/qt/channels_list.py             |      24 ++++++++++++++----------
         M lib/lnbase.py                       |      35 +++++++++++++++++--------------
         M lib/lnworker.py                     |      11 +++++------
       
       3 files changed, 38 insertions(+), 32 deletions(-)
       ---
   DIR diff --git a/gui/qt/channels_list.py b/gui/qt/channels_list.py
       t@@ -2,35 +2,39 @@
        from PyQt5 import QtCore, QtWidgets
        from electrum.util import inv_dict, bh2u
        from electrum.i18n import _
       +from electrum.lnbase import OpenChannel
        from .util import MyTreeWidget, SortableTreeWidgetItem
        
        class ChannelsList(MyTreeWidget):
            update_rows = QtCore.pyqtSignal(list)
       -    update_single_row = QtCore.pyqtSignal(dict)
       +    update_single_row = QtCore.pyqtSignal(OpenChannel)
        
            def __init__(self, parent):
       -        MyTreeWidget.__init__(self, parent, self.create_menu, [_('Node ID'), _('Capacity'), _('Balance')], 0)
       +        MyTreeWidget.__init__(self, parent, self.create_menu, [_('Node ID'), _('Capacity'), _('Balance'), _('Status')], 0)
                self.main_window = parent
                self.update_rows.connect(self.do_update_rows)
                self.update_single_row.connect(self.do_update_single_row)
        
            def format_fields(self, chan):
       -        return [bh2u(chan.node_id), self.parent.format_amount(chan.constraints.capacity), self.parent.format_amount(chan.local_state.amount_msat//1000)]
       +        status = self.parent.wallet.lnworker.channel_state[chan.channel_id]
       +        return [bh2u(chan.node_id), self.parent.format_amount(chan.constraints.capacity), self.parent.format_amount(chan.local_state.amount_msat//1000), status]
        
            def create_menu(self, position):
                menu = QtWidgets.QMenu()
                cur = self.currentItem()
       +        print('ID', cur.data(0, QtCore.Qt.UserRole))
                def close():
       -            print("closechannel result", self.parent.network.lnworker.close_channel_from_other_thread(cur.di))
       +            print("closechannel result", self.parent.wallet.lnworker.close_channel_from_other_thread(cur.di))
                menu.addAction(_("Close channel"), close)
                menu.exec_(self.viewport().mapToGlobal(position))
        
       -    @QtCore.pyqtSlot(dict)
       +    @QtCore.pyqtSlot(OpenChannel)
            def do_update_single_row(self, chan):
       -        items = self.findItems(chan.channel_id, QtCore.Qt.UserRole|QtCore.Qt.MatchContains|QtCore.Qt.MatchRecursive, column=1)
       -        for item in items:
       -            for i, v in enumerate(self.format_fields(chan)):
       -                item.setData(i, QtCore.Qt.DisplayRole, v)
       +        for i in range(self.topLevelItemCount()):
       +            item = self.topLevelItem(i)
       +            if item.data(0, QtCore.Qt.UserRole) == chan.channel_id:
       +                for i, v in enumerate(self.format_fields(chan)):
       +                    item.setData(i, QtCore.Qt.DisplayRole, v)
        
            @QtCore.pyqtSlot(list)
            def do_update_rows(self, channels):
       t@@ -73,4 +77,4 @@ class ChannelsList(MyTreeWidget):
                push_amt = int(push_amt_inp.text())
                assert local_amt >= 200000
                assert local_amt >= push_amt
       -        obj = self.parent.network.lnworker.open_channel(node_id, local_amt, push_amt, password)
       +        obj = self.parent.wallet.lnworker.open_channel(node_id, local_amt, push_amt, password)
   DIR diff --git a/lib/lnbase.py b/lib/lnbase.py
       t@@ -583,6 +583,7 @@ class Peer(PrintError):
                self.path_finder = path_finder
                self.read_buffer = b''
                self.ping_time = 0
       +        self.initialized = asyncio.Future()
                self.channel_accepted = defaultdict(asyncio.Queue)
                self.funding_signed = defaultdict(asyncio.Queue)
                self.remote_funding_locked = defaultdict(asyncio.Queue)
       t@@ -708,13 +709,13 @@ class Peer(PrintError):
                self.channel_accepted[temp_chan_id].put_nowait(payload)
        
            def on_funding_signed(self, payload):
       -        channel_id = int.from_bytes(payload['channel_id'], 'big')
       +        channel_id = payload['channel_id']
                if channel_id not in self.funding_signed: raise Exception("Got unknown funding_signed")
                self.funding_signed[channel_id].put_nowait(payload)
        
            def on_funding_locked(self, payload):
       -        channel_id = int.from_bytes(payload['channel_id'], 'big')
       -        if channel_id not in self.funding_signed: print("Got unknown funding_locked", payload)
       +        channel_id = payload['channel_id']
       +        if channel_id not in self.remote_funding_locked: print("Got unknown funding_locked", payload)
                self.remote_funding_locked[channel_id].put_nowait(payload)
        
            def on_node_announcement(self, payload):
       t@@ -771,8 +772,9 @@ class Peer(PrintError):
                # read init
                msg = await self.read_message()
                self.process_message(msg)
       +        self.initialized.set_result(True)
                # reestablish channels
       -        [await self.reestablish_channel(c) for c in self.channels.values()]
       +        [self.reestablish_channel(c) for c in self.channels.values()]
                # loop
                while True:
                    self.ping_if_required()
       t@@ -931,7 +933,9 @@ class Peer(PrintError):
                )
                return chan
        
       -    async def reestablish_channel(self, chan):
       +    def reestablish_channel(self, chan):
       +        self.channel_state[chan.channel_id] = 'REESTABLISHING'
       +        self.network.trigger_callback('channel', chan)
                self.send_message(gen_msg("channel_reestablish",
                    channel_id=chan.channel_id,
                    next_local_commitment_number=chan.local_state.ctn+1,
       t@@ -939,12 +943,10 @@ class Peer(PrintError):
                ))
        
            def on_channel_reestablish(self, payload):
       -        chan_id = int.from_bytes(payload["channel_id"], 'big')
       -        for chan in self.channels.values():
       -            if chan.channel_id == chan_id:
       -                break
       -        else:
       -            print("Warning: received unknown channel_reestablish", chan_id, list(self.channels.values()))
       +        chan_id = payload["channel_id"]
       +        chan = self.channels.get(chan_id)
       +        if not chan:
       +            print("Warning: received unknown channel_reestablish", bh2u(chan_id))
                    return
                channel_reestablish_msg = payload
                remote_ctn = int.from_bytes(channel_reestablish_msg["next_local_commitment_number"], 'big')
       t@@ -955,11 +957,12 @@ class Peer(PrintError):
                    raise Exception("expected local ctn {}, got {}".format(chan.local_state.ctn, local_ctn))
                if channel_reestablish_msg["my_current_per_commitment_point"] != chan.remote_state.last_per_commitment_point:
                    raise Exception("Remote PCP mismatch")
       +        self.channel_state[chan_id] = 'OPEN' if chan.local_state.funding_locked_received else 'OPENING'
       +        self.network.trigger_callback('channel', chan)
        
            async def funding_locked(self, chan):
                channel_id = chan.channel_id
                short_channel_id = chan.short_channel_id
       -
                per_commitment_secret_index = 2**48 - 2
                per_commitment_point_second = secret_to_pubkey(int.from_bytes(
                    get_per_commitment_secret_from_seed(chan.local_state.per_commitment_secret_seed, per_commitment_secret_index), 'big'))
       t@@ -1118,7 +1121,7 @@ class Peer(PrintError):
        
            @aiosafe
            async def receive_commitment_revoke_ack(self, htlc, decoded, payment_preimage):
       -        chan = self.channels[int.from_bytes(htlc['channel_id'], 'big')]
       +        chan = self.channels[htlc['channel_id']]
                channel_id = chan.channel_id
                expected_received_msat = int(decoded.amount * COIN * 1000)
                while True:
       t@@ -1238,11 +1241,11 @@ class Peer(PrintError):
        
            def on_commitment_signed(self, payload):
                self.print_error("commitment_signed", payload)
       -        channel_id = int.from_bytes(payload['channel_id'], 'big')
       +        channel_id = payload['channel_id']
                self.commitment_signed[channel_id].put_nowait(payload)
        
            def on_update_fulfill_htlc(self, payload):
       -        channel_id = int.from_bytes(payload["channel_id"], 'big')
       +        channel_id = payload["channel_id"]
                self.update_fulfill_htlc[channel_id].put_nowait(payload)
        
            def on_update_fail_malformed_htlc(self, payload):
       t@@ -1265,7 +1268,7 @@ class Peer(PrintError):
                    assert False
        
            def on_revoke_and_ack(self, payload):
       -        channel_id = int.from_bytes(payload["channel_id"], 'big')
       +        channel_id = payload["channel_id"]
                self.revoke_and_ack[channel_id].put_nowait(payload)
        
        
   DIR diff --git a/lib/lnworker.py b/lib/lnworker.py
       t@@ -27,7 +27,7 @@ from . import lnrouter
        is_key = lambda k: k.endswith("_basepoint") or k.endswith("_key")
        
        def maybeDecode(k, v):
       -    if k in ["node_id", "short_channel_id", "pubkey", "privkey", "last_per_commitment_point", "next_per_commitment_point", "per_commitment_secret_seed"] and v is not None:
       +    if k in ["node_id", "channel_id", "short_channel_id", "pubkey", "privkey", "last_per_commitment_point", "next_per_commitment_point", "per_commitment_secret_seed"] and v is not None:
                return binascii.unhexlify(v)
            return v
        
       t@@ -102,14 +102,12 @@ class LNWorker(PrintError):
                self.nodes = {}  # received node announcements
                self.channel_db = lnrouter.ChannelDB()
                self.path_finder = lnrouter.LNPathFinder(self.channel_db)
       -        self.channels = {x['channel_id']: reconstruct_namedtuples(x) for x in wallet.storage.get("channels", [])}
       +        self.channels = {x.channel_id: x for x in map(reconstruct_namedtuples, wallet.storage.get("channels", []))}
                self.invoices = wallet.storage.get('lightning_invoices', {})
                peer_list = network.config.get('lightning_peers', node_list)
       -        self.channel_state = {chan.channel_id: "OPENING" for chan in self.channels.values()}
       +        self.channel_state = {chan.channel_id: "DISCONNECTED" for chan in self.channels.values()}
                for host, port, pubkey in peer_list:
                    self.add_peer(host, int(port), pubkey)
       -
       -        self.callbacks = defaultdict(list)
                # wait until we see confirmations
                self.network.register_callback(self.on_network_update, ['updated', 'verified']) # thread safe
                self.on_network_update('updated') # shortcut (don't block) if funding tx locked and verified
       t@@ -159,7 +157,7 @@ class LNWorker(PrintError):
        
            def on_network_update(self, event, *args):
                for chan in self.channels.values():
       -            if self.channel_state[chan.channel_id] == "OPEN":
       +            if self.channel_state[chan.channel_id] != "OPENING":
                        continue
                    chan = self.save_short_chan_id(chan)
                    if not chan:
       t@@ -171,6 +169,7 @@ class LNWorker(PrintError):
            # aiosafe because we don't wait for result
            @aiosafe
            async def wait_funding_locked_and_mark_open(self, peer, chan):
       +        await peer.initialized
                if self.channel_state[chan.channel_id] == "OPEN":
                    return
                if not chan.local_state.funding_locked_received: