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)
This commit is contained in:
SomberNight 2020-06-19 04:11:35 +02:00
parent 625f985f22
commit 4c70956687
No known key found for this signature in database
GPG key ID: B33B5F232C6271E9
6 changed files with 49 additions and 31 deletions

View file

@ -249,12 +249,12 @@ class ElectrumWindow(App):
if self.invoice_popup and self.invoice_popup.key == key: if self.invoice_popup and self.invoice_popup.key == key:
self.invoice_popup.update_status() 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) description = self.wallet.get_label(key)
self.show_info(_('Payment succeeded') + '\n\n' + description) self.show_info(_('Payment succeeded') + '\n\n' + description)
self._trigger_update_history() 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) self.show_info(_('Payment failed') + '\n\n' + reason)
def _get_bu(self): def _get_bu(self):
@ -723,7 +723,7 @@ class ElectrumWindow(App):
self._channels_dialog = LightningChannelsDialog(self) self._channels_dialog = LightningChannelsDialog(self)
self._channels_dialog.open() self._channels_dialog.open()
def on_channel(self, evt, chan): def on_channel(self, evt, wallet, chan):
if self._channels_dialog: if self._channels_dialog:
Clock.schedule_once(lambda dt: self._channels_dialog.update()) Clock.schedule_once(lambda dt: self._channels_dialog.update())

View file

@ -9,9 +9,10 @@ from electrum import util
from electrum.i18n import _ from electrum.i18n import _
from electrum.util import bh2u, format_time from electrum.util import bh2u, format_time
from electrum.lnutil import format_short_channel_id, LOCAL, REMOTE, UpdateAddHtlc, Direction 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.lnaddr import LnAddr, lndecode
from electrum.bitcoin import COIN from electrum.bitcoin import COIN
from electrum.wallet import Abstract_Wallet
from .util import Buttons, CloseButton, ButtonsLineEdit from .util import Buttons, CloseButton, ButtonsLineEdit
@ -80,10 +81,12 @@ class ChannelDetailsDialog(QtWidgets.QDialog):
ln_payment_completed = QtCore.pyqtSignal(str, bytes, bytes) ln_payment_completed = QtCore.pyqtSignal(str, bytes, bytes)
ln_payment_failed = QtCore.pyqtSignal(str, bytes, bytes) ln_payment_failed = QtCore.pyqtSignal(str, bytes, bytes)
htlc_added = QtCore.pyqtSignal(str, UpdateAddHtlc, LnAddr, Direction) 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) @QtCore.pyqtSlot(str, Abstract_Wallet, AbstractChannel)
def do_state_changed(self, chan): def do_state_changed(self, wallet, chan):
if wallet != self.wallet:
return
if chan == self.chan: if chan == self.chan:
self.update() self.update()
@ -115,7 +118,7 @@ class ChannelDetailsDialog(QtWidgets.QDialog):
@QtCore.pyqtSlot(str) @QtCore.pyqtSlot(str)
def show_tx(self, link_text: 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')) self.window.show_transaction(funding_tx, tx_desc=_('Funding Transaction'))
def __init__(self, window: 'ElectrumWindow', chan_id: bytes): def __init__(self, window: 'ElectrumWindow', chan_id: bytes):
@ -123,6 +126,7 @@ class ChannelDetailsDialog(QtWidgets.QDialog):
# initialize instance fields # initialize instance fields
self.window = window self.window = window
self.wallet = window.wallet
chan = self.chan = window.wallet.lnworker.channels[chan_id] chan = self.chan = window.wallet.lnworker.channels[chan_id]
self.format_msat = lambda msat: window.format_amount_and_units(msat / 1000) self.format_msat = lambda msat: window.format_amount_and_units(msat / 1000)

View file

@ -26,7 +26,7 @@ ROLE_CHANNEL_ID = Qt.UserRole
class ChannelsList(MyTreeView): class ChannelsList(MyTreeView):
update_rows = QtCore.pyqtSignal(Abstract_Wallet) 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() gossip_db_loaded = QtCore.pyqtSignal()
class Columns(IntEnum): class Columns(IntEnum):
@ -202,9 +202,11 @@ class ChannelsList(MyTreeView):
menu.addAction(_("Delete"), lambda: self.remove_channel(channel_id)) menu.addAction(_("Delete"), lambda: self.remove_channel(channel_id))
menu.exec_(self.viewport().mapToGlobal(position)) menu.exec_(self.viewport().mapToGlobal(position))
@QtCore.pyqtSlot(AbstractChannel) @QtCore.pyqtSlot(Abstract_Wallet, AbstractChannel)
def do_update_single_row(self, chan: AbstractChannel): def do_update_single_row(self, wallet: Abstract_Wallet, chan: AbstractChannel):
lnworker = self.parent.wallet.lnworker if wallet != self.parent.wallet:
return
lnworker = wallet.lnworker
if not lnworker: if not lnworker:
return return
for row in range(self.model().rowCount()): for row in range(self.model().rowCount()):

View file

@ -427,18 +427,26 @@ class ElectrumWindow(QMainWindow, MessageBoxMixin, Logger):
elif event == 'gossip_db_loaded': elif event == 'gossip_db_loaded':
self.channels_list.gossip_db_loaded.emit(*args) self.channels_list.gossip_db_loaded.emit(*args)
elif event == 'channels_updated': 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': elif event == 'channel':
self.channels_list.update_single_row.emit(*args) wallet = args[0]
self.update_status() if wallet == self.wallet:
self.channels_list.update_single_row.emit(*args)
self.update_status()
elif event == 'request_status': elif event == 'request_status':
self.on_request_status(*args) self.on_request_status(*args)
elif event == 'invoice_status': elif event == 'invoice_status':
self.on_invoice_status(*args) self.on_invoice_status(*args)
elif event == 'payment_succeeded': 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': elif event == 'payment_failed':
self.on_payment_failed(*args) wallet = args[0]
if wallet == self.wallet:
self.on_payment_failed(*args)
elif event == 'status': elif event == 'status':
self.update_status() self.update_status()
elif event == 'banner': elif event == 'banner':
@ -1498,12 +1506,12 @@ class ElectrumWindow(QMainWindow, MessageBoxMixin, Logger):
return return
self.invoice_list.update_item(key, req) 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) description = self.wallet.get_label(key)
self.notify(_('Payment succeeded') + '\n\n' + description) self.notify(_('Payment succeeded') + '\n\n' + description)
self.need_update.set() 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) self.show_error(_('Payment failed') + '\n\n' + reason)
def read_invoice(self): def read_invoice(self):

View file

@ -787,7 +787,7 @@ class Peer(Logger):
f'already in peer_state {chan.peer_state!r}') f'already in peer_state {chan.peer_state!r}')
return return
chan.peer_state = PeerState.REESTABLISHING 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" # BOLT-02: "A node [...] upon disconnection [...] MUST reverse any uncommitted updates sent by the other side"
chan.hm.discard_unsigned_remote_updates() chan.hm.discard_unsigned_remote_updates()
# ctns # ctns
@ -940,7 +940,7 @@ class Peer(Logger):
# checks done # checks done
if chan.is_funded() and chan.config[LOCAL].funding_locked_received: if chan.is_funded() and chan.config[LOCAL].funding_locked_received:
self.mark_open(chan) 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 we have sent a previous shutdown, it must be retransmitted (Bolt2)
if chan.get_state() == ChannelState.SHUTDOWN: if chan.get_state() == ChannelState.SHUTDOWN:
await self.send_shutdown(chan) await self.send_shutdown(chan)
@ -1029,7 +1029,7 @@ class Peer(Logger):
return return
assert chan.config[LOCAL].funding_locked_received assert chan.config[LOCAL].funding_locked_received
chan.set_state(ChannelState.OPEN) 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 # 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) pending_channel_update = self.orphan_channel_updates.get(chan.short_channel_id)
if pending_channel_update: if pending_channel_update:

View file

@ -480,7 +480,7 @@ class LNGossip(LNWorker):
class LNWallet(LNWorker): class LNWallet(LNWorker):
lnwatcher: 'LNWalletWatcher' lnwatcher: Optional['LNWalletWatcher']
def __init__(self, wallet: 'Abstract_Wallet', xprv): def __init__(self, wallet: 'Abstract_Wallet', xprv):
Logger.__init__(self) Logger.__init__(self)
@ -488,6 +488,7 @@ class LNWallet(LNWorker):
self.db = wallet.db self.db = wallet.db
self.config = wallet.config self.config = wallet.config
LNWorker.__init__(self, xprv) LNWorker.__init__(self, xprv)
self.lnwatcher = None
self.features |= LnFeatures.OPTION_DATA_LOSS_PROTECT_REQ self.features |= LnFeatures.OPTION_DATA_LOSS_PROTECT_REQ
self.features |= LnFeatures.OPTION_STATIC_REMOTEKEY_REQ self.features |= LnFeatures.OPTION_STATIC_REMOTEKEY_REQ
self.payments = self.db.get_dict('lightning_payments') # RHASH -> amount, direction, is_paid 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): def peer_closed(self, peer):
for chan in self.channels_for_peer(peer.pubkey).values(): for chan in self.channels_for_peer(peer.pubkey).values():
chan.peer_state = PeerState.DISCONNECTED chan.peer_state = PeerState.DISCONNECTED
util.trigger_callback('channel', chan) util.trigger_callback('channel', self.wallet, chan)
super().peer_closed(peer) super().peer_closed(peer)
def get_settled_payments(self): def get_settled_payments(self):
@ -716,14 +717,14 @@ class LNWallet(LNWorker):
def channel_state_changed(self, chan): def channel_state_changed(self, chan):
self.save_channel(chan) self.save_channel(chan)
util.trigger_callback('channel', chan) util.trigger_callback('channel', self.wallet, chan)
def save_channel(self, chan): def save_channel(self, chan):
assert type(chan) is Channel assert type(chan) is Channel
if chan.config[REMOTE].next_per_commitment_point == chan.config[REMOTE].current_per_commitment_point: 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") raise Exception("Tried to save channel with next_point == current_point, this should not happen")
self.wallet.save_db() self.wallet.save_db()
util.trigger_callback('channel', chan) util.trigger_callback('channel', self.wallet, chan)
def channel_by_txo(self, txo): def channel_by_txo(self, txo):
for chan in self.channels.values(): for chan in self.channels.values():
@ -869,9 +870,9 @@ class LNWallet(LNWorker):
reason = _('Failed after {} attempts').format(attempts) reason = _('Failed after {} attempts').format(attempts)
util.trigger_callback('invoice_status', key) util.trigger_callback('invoice_status', key)
if success: if success:
util.trigger_callback('payment_succeeded', key) util.trigger_callback('payment_succeeded', self.wallet, key)
else: else:
util.trigger_callback('payment_failed', key, reason) util.trigger_callback('payment_failed', self.wallet, key, reason)
return success, log return success, log
async def _pay_to_route(self, route: LNPaymentRoute, lnaddr: LnAddr) -> PaymentAttemptLog: 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') chan.logger.info('received unexpected payment_failed, probably from previous session')
key = payment_hash.hex() key = payment_hash.hex()
util.trigger_callback('invoice_status', key) 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) util.trigger_callback('ln_payment_failed', payment_hash, chan.channel_id)
def payment_sent(self, chan, payment_hash: bytes): 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') chan.logger.info('received unexpected payment_sent, probably from previous session')
key = payment_hash.hex() key = payment_hash.hex()
util.trigger_callback('invoice_status', key) 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) util.trigger_callback('ln_payment_completed', payment_hash, chan.channel_id)
def payment_received(self, chan, payment_hash: bytes): def payment_received(self, chan, payment_hash: bytes):
@ -1405,6 +1406,8 @@ class LNWallet(LNWorker):
class LNBackups(Logger): class LNBackups(Logger):
lnwatcher: Optional['LNWalletWatcher']
def __init__(self, wallet: 'Abstract_Wallet'): def __init__(self, wallet: 'Abstract_Wallet'):
Logger.__init__(self) Logger.__init__(self)
self.features = LnFeatures(0) self.features = LnFeatures(0)
@ -1414,6 +1417,7 @@ class LNBackups(Logger):
self.lock = threading.RLock() self.lock = threading.RLock()
self.wallet = wallet self.wallet = wallet
self.db = wallet.db self.db = wallet.db
self.lnwatcher = None
self.channel_backups = {} self.channel_backups = {}
for channel_id, cb in random_shuffled_copy(self.db.get_dict("channel_backups").items()): 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) 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() return self.wallet.get_new_sweep_address_for_channel()
def channel_state_changed(self, chan): def channel_state_changed(self, chan):
util.trigger_callback('channel', chan) util.trigger_callback('channel', self.wallet, chan)
def peer_closed(self, chan): def peer_closed(self, chan):
pass pass