electrum

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

commit 4c7095668778c1d3f98a2bf9669a5aa4eeeede87
parent 625f985f22a6b09bb106159b400843df491a3833
Author: SomberNight <somber.night@protonmail.com>
Date:   Fri, 19 Jun 2020 04:11:35 +0200

filter callbacks to wallet: channel, payment_succeeded, payment_failed

It is ugly that the 'channel' callback takes a wallet I guess,
but with channel backups in one wallet, and active channels in another,
it was causing problems... (when open simultaneously)

Diffstat:
Melectrum/gui/kivy/main_window.py | 6+++---
Melectrum/gui/qt/channel_details.py | 14+++++++++-----
Melectrum/gui/qt/channels_list.py | 10++++++----
Melectrum/gui/qt/main_window.py | 22+++++++++++++++-------
Melectrum/lnpeer.py | 6+++---
Melectrum/lnworker.py | 22+++++++++++++---------
6 files changed, 49 insertions(+), 31 deletions(-)

diff --git a/electrum/gui/kivy/main_window.py b/electrum/gui/kivy/main_window.py @@ -249,12 +249,12 @@ class ElectrumWindow(App): if self.invoice_popup and self.invoice_popup.key == key: self.invoice_popup.update_status() - def on_payment_succeeded(self, event, key): + def on_payment_succeeded(self, event, wallet, key): description = self.wallet.get_label(key) self.show_info(_('Payment succeeded') + '\n\n' + description) self._trigger_update_history() - def on_payment_failed(self, event, key, reason): + def on_payment_failed(self, event, wallet, key, reason): self.show_info(_('Payment failed') + '\n\n' + reason) def _get_bu(self): @@ -723,7 +723,7 @@ class ElectrumWindow(App): self._channels_dialog = LightningChannelsDialog(self) self._channels_dialog.open() - def on_channel(self, evt, chan): + def on_channel(self, evt, wallet, chan): if self._channels_dialog: Clock.schedule_once(lambda dt: self._channels_dialog.update()) diff --git a/electrum/gui/qt/channel_details.py b/electrum/gui/qt/channel_details.py @@ -9,9 +9,10 @@ from electrum import util from electrum.i18n import _ from electrum.util import bh2u, format_time from electrum.lnutil import format_short_channel_id, LOCAL, REMOTE, UpdateAddHtlc, Direction -from electrum.lnchannel import htlcsum, Channel +from electrum.lnchannel import htlcsum, Channel, AbstractChannel from electrum.lnaddr import LnAddr, lndecode from electrum.bitcoin import COIN +from electrum.wallet import Abstract_Wallet from .util import Buttons, CloseButton, ButtonsLineEdit @@ -80,10 +81,12 @@ class ChannelDetailsDialog(QtWidgets.QDialog): ln_payment_completed = QtCore.pyqtSignal(str, bytes, bytes) ln_payment_failed = QtCore.pyqtSignal(str, bytes, bytes) htlc_added = QtCore.pyqtSignal(str, UpdateAddHtlc, LnAddr, Direction) - state_changed = QtCore.pyqtSignal(str, Channel) + state_changed = QtCore.pyqtSignal(str, Abstract_Wallet, AbstractChannel) - @QtCore.pyqtSlot(str, Channel) - def do_state_changed(self, chan): + @QtCore.pyqtSlot(str, Abstract_Wallet, AbstractChannel) + def do_state_changed(self, wallet, chan): + if wallet != self.wallet: + return if chan == self.chan: self.update() @@ -115,7 +118,7 @@ class ChannelDetailsDialog(QtWidgets.QDialog): @QtCore.pyqtSlot(str) def show_tx(self, link_text: str): - funding_tx = self.window.wallet.db.get_transaction(self.chan.funding_outpoint.txid) + funding_tx = self.wallet.db.get_transaction(self.chan.funding_outpoint.txid) self.window.show_transaction(funding_tx, tx_desc=_('Funding Transaction')) def __init__(self, window: 'ElectrumWindow', chan_id: bytes): @@ -123,6 +126,7 @@ class ChannelDetailsDialog(QtWidgets.QDialog): # initialize instance fields self.window = window + self.wallet = window.wallet chan = self.chan = window.wallet.lnworker.channels[chan_id] self.format_msat = lambda msat: window.format_amount_and_units(msat / 1000) diff --git a/electrum/gui/qt/channels_list.py b/electrum/gui/qt/channels_list.py @@ -26,7 +26,7 @@ ROLE_CHANNEL_ID = Qt.UserRole class ChannelsList(MyTreeView): update_rows = QtCore.pyqtSignal(Abstract_Wallet) - update_single_row = QtCore.pyqtSignal(AbstractChannel) + update_single_row = QtCore.pyqtSignal(Abstract_Wallet, AbstractChannel) gossip_db_loaded = QtCore.pyqtSignal() class Columns(IntEnum): @@ -202,9 +202,11 @@ class ChannelsList(MyTreeView): menu.addAction(_("Delete"), lambda: self.remove_channel(channel_id)) menu.exec_(self.viewport().mapToGlobal(position)) - @QtCore.pyqtSlot(AbstractChannel) - def do_update_single_row(self, chan: AbstractChannel): - lnworker = self.parent.wallet.lnworker + @QtCore.pyqtSlot(Abstract_Wallet, AbstractChannel) + def do_update_single_row(self, wallet: Abstract_Wallet, chan: AbstractChannel): + if wallet != self.parent.wallet: + return + lnworker = wallet.lnworker if not lnworker: return for row in range(self.model().rowCount()): diff --git a/electrum/gui/qt/main_window.py b/electrum/gui/qt/main_window.py @@ -427,18 +427,26 @@ class ElectrumWindow(QMainWindow, MessageBoxMixin, Logger): elif event == 'gossip_db_loaded': self.channels_list.gossip_db_loaded.emit(*args) elif event == 'channels_updated': - self.channels_list.update_rows.emit(*args) + wallet = args[0] + if wallet == self.wallet: + self.channels_list.update_rows.emit(*args) elif event == 'channel': - self.channels_list.update_single_row.emit(*args) - self.update_status() + wallet = args[0] + if wallet == self.wallet: + self.channels_list.update_single_row.emit(*args) + self.update_status() elif event == 'request_status': self.on_request_status(*args) elif event == 'invoice_status': self.on_invoice_status(*args) elif event == 'payment_succeeded': - self.on_payment_succeeded(*args) + wallet = args[0] + if wallet == self.wallet: + self.on_payment_succeeded(*args) elif event == 'payment_failed': - self.on_payment_failed(*args) + wallet = args[0] + if wallet == self.wallet: + self.on_payment_failed(*args) elif event == 'status': self.update_status() elif event == 'banner': @@ -1498,12 +1506,12 @@ class ElectrumWindow(QMainWindow, MessageBoxMixin, Logger): return self.invoice_list.update_item(key, req) - def on_payment_succeeded(self, key): + def on_payment_succeeded(self, wallet, key): description = self.wallet.get_label(key) self.notify(_('Payment succeeded') + '\n\n' + description) self.need_update.set() - def on_payment_failed(self, key, reason): + def on_payment_failed(self, wallet, key, reason): self.show_error(_('Payment failed') + '\n\n' + reason) def read_invoice(self): diff --git a/electrum/lnpeer.py b/electrum/lnpeer.py @@ -787,7 +787,7 @@ class Peer(Logger): f'already in peer_state {chan.peer_state!r}') return chan.peer_state = PeerState.REESTABLISHING - util.trigger_callback('channel', chan) + util.trigger_callback('channel', self.lnworker.wallet, chan) # BOLT-02: "A node [...] upon disconnection [...] MUST reverse any uncommitted updates sent by the other side" chan.hm.discard_unsigned_remote_updates() # ctns @@ -940,7 +940,7 @@ class Peer(Logger): # checks done if chan.is_funded() and chan.config[LOCAL].funding_locked_received: self.mark_open(chan) - util.trigger_callback('channel', chan) + util.trigger_callback('channel', self.lnworker.wallet, chan) # if we have sent a previous shutdown, it must be retransmitted (Bolt2) if chan.get_state() == ChannelState.SHUTDOWN: await self.send_shutdown(chan) @@ -1029,7 +1029,7 @@ class Peer(Logger): return assert chan.config[LOCAL].funding_locked_received chan.set_state(ChannelState.OPEN) - util.trigger_callback('channel', chan) + util.trigger_callback('channel', self.lnworker.wallet, chan) # peer may have sent us a channel update for the incoming direction previously pending_channel_update = self.orphan_channel_updates.get(chan.short_channel_id) if pending_channel_update: diff --git a/electrum/lnworker.py b/electrum/lnworker.py @@ -480,7 +480,7 @@ class LNGossip(LNWorker): class LNWallet(LNWorker): - lnwatcher: 'LNWalletWatcher' + lnwatcher: Optional['LNWalletWatcher'] def __init__(self, wallet: 'Abstract_Wallet', xprv): Logger.__init__(self) @@ -488,6 +488,7 @@ class LNWallet(LNWorker): self.db = wallet.db self.config = wallet.config LNWorker.__init__(self, xprv) + self.lnwatcher = None self.features |= LnFeatures.OPTION_DATA_LOSS_PROTECT_REQ self.features |= LnFeatures.OPTION_STATIC_REMOTEKEY_REQ self.payments = self.db.get_dict('lightning_payments') # RHASH -> amount, direction, is_paid @@ -583,7 +584,7 @@ class LNWallet(LNWorker): def peer_closed(self, peer): for chan in self.channels_for_peer(peer.pubkey).values(): chan.peer_state = PeerState.DISCONNECTED - util.trigger_callback('channel', chan) + util.trigger_callback('channel', self.wallet, chan) super().peer_closed(peer) def get_settled_payments(self): @@ -716,14 +717,14 @@ class LNWallet(LNWorker): def channel_state_changed(self, chan): self.save_channel(chan) - util.trigger_callback('channel', chan) + util.trigger_callback('channel', self.wallet, chan) def save_channel(self, chan): assert type(chan) is Channel if chan.config[REMOTE].next_per_commitment_point == chan.config[REMOTE].current_per_commitment_point: raise Exception("Tried to save channel with next_point == current_point, this should not happen") self.wallet.save_db() - util.trigger_callback('channel', chan) + util.trigger_callback('channel', self.wallet, chan) def channel_by_txo(self, txo): for chan in self.channels.values(): @@ -869,9 +870,9 @@ class LNWallet(LNWorker): reason = _('Failed after {} attempts').format(attempts) util.trigger_callback('invoice_status', key) if success: - util.trigger_callback('payment_succeeded', key) + util.trigger_callback('payment_succeeded', self.wallet, key) else: - util.trigger_callback('payment_failed', key, reason) + util.trigger_callback('payment_failed', self.wallet, key, reason) return success, log async def _pay_to_route(self, route: LNPaymentRoute, lnaddr: LnAddr) -> PaymentAttemptLog: @@ -1193,7 +1194,7 @@ class LNWallet(LNWorker): chan.logger.info('received unexpected payment_failed, probably from previous session') key = payment_hash.hex() util.trigger_callback('invoice_status', key) - util.trigger_callback('payment_failed', key, '') + util.trigger_callback('payment_failed', self.wallet, key, '') util.trigger_callback('ln_payment_failed', payment_hash, chan.channel_id) def payment_sent(self, chan, payment_hash: bytes): @@ -1209,7 +1210,7 @@ class LNWallet(LNWorker): chan.logger.info('received unexpected payment_sent, probably from previous session') key = payment_hash.hex() util.trigger_callback('invoice_status', key) - util.trigger_callback('payment_succeeded', key) + util.trigger_callback('payment_succeeded', self.wallet, key) util.trigger_callback('ln_payment_completed', payment_hash, chan.channel_id) def payment_received(self, chan, payment_hash: bytes): @@ -1405,6 +1406,8 @@ class LNWallet(LNWorker): class LNBackups(Logger): + lnwatcher: Optional['LNWalletWatcher'] + def __init__(self, wallet: 'Abstract_Wallet'): Logger.__init__(self) self.features = LnFeatures(0) @@ -1414,6 +1417,7 @@ class LNBackups(Logger): self.lock = threading.RLock() self.wallet = wallet self.db = wallet.db + self.lnwatcher = None self.channel_backups = {} for channel_id, cb in random_shuffled_copy(self.db.get_dict("channel_backups").items()): self.channel_backups[bfh(channel_id)] = ChannelBackup(cb, sweep_address=self.sweep_address, lnworker=self) @@ -1424,7 +1428,7 @@ class LNBackups(Logger): return self.wallet.get_new_sweep_address_for_channel() def channel_state_changed(self, chan): - util.trigger_callback('channel', chan) + util.trigger_callback('channel', self.wallet, chan) def peer_closed(self, chan): pass