electrum

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

commit c7e47b74a9894f0320d11508e909c58813923b36
parent dbdabcfc5d65e4b3a3c7232c44bc2f63d2b9e53b
Author: ThomasV <thomasv@electrum.org>
Date:   Wed, 27 Jun 2018 12:44:43 +0200

Separate open_channel dialog. In open_channel_coroutine, use host and port from channel announcements

Diffstat:
Melectrum/gui/qt/main_window.py | 1+
Melectrum/network.py | 1+
Mgui/qt/channels_list.py | 90++++++++++++++++++++++++++++++++++++++++++++++++++++---------------------------
Mlib/lnbase.py | 3+--
Mlib/lnworker.py | 20+++++++++-----------
5 files changed, 71 insertions(+), 44 deletions(-)

diff --git a/electrum/gui/qt/main_window.py b/electrum/gui/qt/main_window.py @@ -425,6 +425,7 @@ class ElectrumWindow(QMainWindow, MessageBoxMixin, Logger): self.update_console() self.clear_receive_tab() self.request_list.update() + self.channels_list.update() self.tabs.show() self.init_geometry() if self.config.get('hide_gui') and self.gui_object.tray.isVisible(): diff --git a/electrum/network.py b/electrum/network.py @@ -300,6 +300,7 @@ class Network(Logger): self._set_status('disconnected') # lightning network + self.lightning_nodes = {} self.channel_db = lnrouter.ChannelDB() self.path_finder = lnrouter.LNPathFinder(self.channel_db) self.lnwatcher = lnwatcher.LNWatcher(self) diff --git a/gui/qt/channels_list.py b/gui/qt/channels_list.py @@ -1,9 +1,12 @@ # -*- coding: utf-8 -*- from PyQt5 import QtCore, QtWidgets -from electrum.util import inv_dict, bh2u +from PyQt5.QtWidgets import * + +from electrum.util import inv_dict, bh2u, bfh from electrum.i18n import _ from electrum.lnbase import OpenChannel -from .util import MyTreeWidget, SortableTreeWidgetItem +from .util import MyTreeWidget, SortableTreeWidgetItem, WindowModalDialog, Buttons, OkButton, CancelButton +from .amountedit import BTCAmountEdit class ChannelsList(MyTreeWidget): update_rows = QtCore.pyqtSignal() @@ -14,6 +17,7 @@ class ChannelsList(MyTreeWidget): self.main_window = parent self.update_rows.connect(self.do_update_rows) self.update_single_row.connect(self.do_update_single_row) + self.status = QLabel('') def format_fields(self, chan): status = self.parent.wallet.lnworker.channel_state[chan.channel_id] @@ -25,7 +29,7 @@ class ChannelsList(MyTreeWidget): ] def create_menu(self, position): - menu = QtWidgets.QMenu() + menu = QMenu() channel_id = self.currentItem().data(0, QtCore.Qt.UserRole) print('ID', bh2u(channel_id)) def close(): @@ -50,35 +54,59 @@ class ChannelsList(MyTreeWidget): self.insertTopLevelItem(0, item) def get_toolbar(self): - nodeid_inp = QtWidgets.QLineEdit(self) - local_amt_inp = QtWidgets.QLineEdit(self, text='200000') - push_amt_inp = QtWidgets.QLineEdit(self, text='0') - button = QtWidgets.QPushButton(_('Open channel'), self) - button.clicked.connect(lambda: self.main_window.protect(self.open_channel, (nodeid_inp, local_amt_inp, push_amt_inp))) - h = QtWidgets.QGridLayout() - nodeid_label = QtWidgets.QLabel(self) - nodeid_label.setText(_("Node ID")) - local_amt_label = QtWidgets.QLabel(self) - local_amt_label.setText("Local amount (sat)") - push_amt_label = QtWidgets.QLabel(self) - push_amt_label.setText("Push amount (sat)") - h.addWidget(nodeid_label, 0, 0) - h.addWidget(local_amt_label, 0, 1) - h.addWidget(push_amt_label, 0, 2) - h.addWidget(nodeid_inp, 1, 0) - h.addWidget(local_amt_inp, 1, 1) - h.addWidget(push_amt_inp, 1, 2) - h.addWidget(button, 1, 3) - h.setColumnStretch(0, 3) - h.setColumnStretch(1, 1) - h.setColumnStretch(2, 1) - h.setColumnStretch(3, 1) + b = QPushButton(_('Open Channel')) + b.clicked.connect(self.new_channel_dialog) + h = QHBoxLayout() + h.addWidget(self.status) + h.addStretch() + h.addWidget(b) return h - def open_channel(self, nodeIdInput, local_amt_inp, push_amt_inp, password): - node_id = str(nodeIdInput.text()) - local_amt = int(local_amt_inp.text()) - push_amt = int(push_amt_inp.text()) + def on_update(self): + n = len(self.parent.network.lightning_nodes) + np = len(self.parent.wallet.lnworker.peers) + self.status.setText(_('{} peers, {} nodes').format(np, n)) + + def new_channel_dialog(self): + d = WindowModalDialog(self.parent, _('Open Channel')) + d.setFixedWidth(700) + vbox = QVBoxLayout(d) + h = QGridLayout() + local_nodeid = QLineEdit() + local_nodeid.setText(bh2u(self.parent.wallet.lnworker.pubkey)) + local_nodeid.setReadOnly(True) + local_nodeid.setCursorPosition(0) + remote_nodeid = QLineEdit() + local_amt_inp = BTCAmountEdit(self.parent.get_decimal_point) + local_amt_inp.setAmount(200000) + push_amt_inp = BTCAmountEdit(self.parent.get_decimal_point) + push_amt_inp.setAmount(0) + h.addWidget(QLabel(_('Your Node ID')), 0, 0) + h.addWidget(local_nodeid, 0, 1) + h.addWidget(QLabel(_('Remote Node ID')), 1, 0) + h.addWidget(remote_nodeid, 1, 1) + h.addWidget(QLabel('Local amount'), 2, 0) + h.addWidget(local_amt_inp, 2, 1) + h.addWidget(QLabel('Push amount'), 3, 0) + h.addWidget(push_amt_inp, 3, 1) + vbox.addLayout(h) + vbox.addLayout(Buttons(CancelButton(d), OkButton(d))) + if not d.exec_(): + return + nodeid_hex = str(remote_nodeid.text()) + local_amt = local_amt_inp.get_amount() + push_amt = push_amt_inp.get_amount() + try: + node_id = bfh(nodeid_hex) + except: + self.parent.show_error(_('Invalid node ID')) + return + if node_id not in self.parent.wallet.lnworker.peers and node_id not in self.parent.network.lightning_nodes: + self.parent.show_error(_('Unknown node:') + ' ' + nodeid_hex) + return assert local_amt >= 200000 assert local_amt >= push_amt - obj = self.parent.wallet.lnworker.open_channel(node_id, local_amt, push_amt, password) + self.main_window.protect(self.open_channel, (node_id, local_amt, push_amt)) + + def open_channel(self, *args, **kwargs): + self.parent.wallet.lnworker.open_channel(*args, **kwargs) diff --git a/lib/lnbase.py b/lib/lnbase.py @@ -607,7 +607,6 @@ class Peer(PrintError): self.announcement_signatures = defaultdict(asyncio.Queue) self.update_fail_htlc = defaultdict(asyncio.Queue) self.localfeatures = (0x08 if request_initial_sync else 0) - self.nodes = {} self.channels = lnworker.channels self.invoices = lnworker.invoices self.attempted_route = {} @@ -757,7 +756,7 @@ class Peer(PrintError): pass continue alias = payload['alias'].rstrip(b'\x00') - self.nodes[pubkey] = { + self.network.lightning_nodes[pubkey] = { 'alias': alias, 'addresses': addresses } diff --git a/lib/lnworker.py b/lib/lnworker.py @@ -90,8 +90,6 @@ class LNWorker(PrintError): self.pubkey = ECPrivkey(self.privkey).get_public_key_bytes() self.config = network.config self.peers = {} - # view of the network - self.nodes = {} # received node announcements 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) @@ -99,7 +97,7 @@ class LNWorker(PrintError): for chan_id, chan in self.channels.items(): self.network.lnwatcher.watch_channel(chan, self.on_channel_utxos) for host, port, pubkey in peer_list: - self.add_peer(host, int(port), pubkey) + self.add_peer(host, int(port), bfh(pubkey)) # 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 @@ -108,8 +106,7 @@ class LNWorker(PrintError): assert type(node_id) is bytes return {x: y for (x, y) in self.channels.items() if y.node_id == node_id} - def add_peer(self, host, port, pubkey): - node_id = bfh(pubkey) + def add_peer(self, host, port, node_id): peer = Peer(self, host, int(port), node_id, request_initial_sync=self.config.get("request_initial_sync", True)) self.network.futures.append(asyncio.run_coroutine_threadsafe(peer.main_loop(), asyncio.get_event_loop())) self.peers[node_id] = peer @@ -171,14 +168,15 @@ class LNWorker(PrintError): conf = self.wallet.get_tx_height(chan.funding_outpoint.txid)[1] peer.on_network_update(chan, conf) - # not aiosafe because we call .result() which will propagate an exception async def _open_channel_coroutine(self, node_id, amount_sat, push_sat, password): - if node_id == "": - peer = next(iter(self.peers.values())) - else: - peer = self.peers[bfh(node_id)] + if node_id not in self.peers: + node = self.network.lightning_nodes.get(node_id) + if node is None: + return False + host, port = node['addresses'][0] + self.add_peer(host, port, node_id) + peer = self.peers[node_id] openingchannel = await peer.channel_establishment_flow(self.wallet, self.config, password, amount_sat, push_sat * 1000, temp_channel_id=os.urandom(32)) - self.print_error("SAVING OPENING CHANNEL") self.save_channel(openingchannel) self.on_channels_updated()