electrum

Electrum Bitcoin wallet
git clone https://git.parazyd.org/electrum
Log | Files | Refs | Submodules

commit f803bb571d196dcc02a7a97406aa221b800f8b41
parent 1520338f37ad601c328df087bdf7bc7f0025ce95
Author: Janus <ysangkok@gmail.com>
Date:   Wed,  7 Nov 2018 19:41:30 +0100

kivy: restore channel list to working state, add [force-]closing functionality

Diffstat:
Melectrum/gui/kivy/uix/dialogs/lightning_channels.py | 57+++++++++++++++++++++++++++++++++++++++++++++------------
1 file changed, 45 insertions(+), 12 deletions(-)

diff --git a/electrum/gui/kivy/uix/dialogs/lightning_channels.py b/electrum/gui/kivy/uix/dialogs/lightning_channels.py @@ -1,9 +1,12 @@ +import asyncio import binascii from kivy.lang import Builder from kivy.factory import Factory from kivy.uix.popup import Popup from kivy.clock import Clock from electrum.gui.kivy.uix.context_menu import ContextMenu +from electrum.util import bh2u +from electrum.lnutil import LOCAL, REMOTE Builder.load_string(''' <LightningChannelItem@CardItem> @@ -15,6 +18,7 @@ Builder.load_string(''' <LightningChannelsDialog@Popup>: name: 'lightning_channels' + title: 'Lightning channels. Tap to select.' BoxLayout: id: box orientation: 'vertical' @@ -86,19 +90,38 @@ class LightningChannelsDialog(Factory.Popup): self.clocks = [] self.app = app self.context_menu = None - self.app.wallet.lnworker.subscribe_channel_list_updates_from_other_thread(self.rpc_result_handler) + self.app.wallet.network.register_callback(self.channels_update, ['channels']) + self.channels_update('bogus evt') def show_channel_details(self, obj): p = Factory.ChannelDetailsPopup() + p.title = 'Lightning channels details for ' + self.presentable_chan_id(obj._chan) p.data = [{'keyName': key, 'value': str(obj.details[key])} for key in obj.details.keys()] p.open() def close_channel(self, obj): - print("UNIMPLEMENTED asked to close channel", obj.channelId) # TODO + loop = self.app.wallet.network.asyncio_loop + coro = asyncio.run_coroutine_threadsafe(self.app.wallet.lnworker.close_channel(obj._chan.channel_id), loop) + try: + coro.result(5) + self.app.show_info('Channel closed') + except Exception as e: + self.app.show_info('Could not close channel: ' + repr(e)) # repr because str(Exception()) == '' + + def force_close_channel(self, obj): + loop = self.app.wallet.network.asyncio_loop + coro = asyncio.run_coroutine_threadsafe(self.app.wallet.lnworker.force_close_channel(obj._chan.channel_id), loop) + try: + coro.result(1) + self.app.show_info('Channel closed, you may need to wait at least ' + str(obj._chan.config[REMOTE].to_self_delay) + ' blocks, because of CSV delays') + except Exception as e: + self.app.show_info('Could not force close channel: ' + repr(e)) # repr because str(Exception()) == '' def show_menu(self, obj): self.hide_menu() - self.context_menu = ContextMenu(obj, [("Close", self.close_channel), + self.context_menu = ContextMenu(obj, [ + ("Force close", self.force_close_channel), + ("Co-op close", self.close_channel), ("Details", self.show_channel_details)]) self.ids.box.add_widget(self.context_menu) @@ -107,17 +130,27 @@ class LightningChannelsDialog(Factory.Popup): self.ids.box.remove_widget(self.context_menu) self.context_menu = None - def rpc_result_handler(self, res): + def presentable_chan_id(self, i): + return bh2u(i.short_channel_id) if i.short_channel_id else bh2u(i.channel_id)[:16] + + def channels_update(self, evt): channel_cards = self.ids.lightning_channels_container channel_cards.clear_widgets() - if "channels" in res: - for i in res["channels"]: + lnworker = self.app.wallet.lnworker + for i in lnworker.channels.values(): item = Factory.LightningChannelItem() item.screen = self - print(i) - item.channelId = i["chan_id"] - item.active = i["active"] - item.details = i + item.channelId = self.presentable_chan_id(i) + item.active = i.node_id in lnworker.peers + item.details = self.channel_details(i) + item._chan = i channel_cards.add_widget(item) - else: - self.app.show_info(res) + + def channel_details(self, chan): + return {'Node ID': bh2u(chan.node_id), + 'Channel ID': bh2u(chan.channel_id), + 'Capacity': self.app.format_amount_and_units(chan.constraints.capacity), + 'Funding TXID': chan.funding_outpoint.txid, + 'Short Chan ID': bh2u(chan.short_channel_id) if chan.short_channel_id else 'Not available', + 'Available to spend': self.app.format_amount_and_units(chan.available_to_spend(LOCAL) // 1000), + 'State': chan.get_state()}