URI: 
       tRemove LNBackups object: no longer needed since LNWorker is instantiated by default. - electrum - Electrum Bitcoin wallet
  HTML git clone https://git.parazyd.org/electrum
   DIR Log
   DIR Files
   DIR Refs
   DIR Submodules
       ---
   DIR commit 652d10aa5f810d6db00ce4870ea7c779f9ff35a4
   DIR parent ef661050c8da36b7b2b73bec47dbaeddb38301f5
  HTML Author: ThomasV <thomasv@electrum.org>
       Date:   Tue,  9 Mar 2021 09:55:55 +0100
       
       Remove LNBackups object: no longer needed since LNWorker is instantiated by default.
       
       Diffstat:
         M electrum/gui/kivy/uix/dialogs/ligh… |      16 ++++++++--------
         M electrum/gui/qt/channels_list.py    |       9 ++++-----
         M electrum/lnpeer.py                  |      13 +++++++------
         M electrum/lnworker.py                |      86 ++++++++++---------------------
         M electrum/wallet.py                  |       7 +------
       
       5 files changed, 46 insertions(+), 85 deletions(-)
       ---
   DIR diff --git a/electrum/gui/kivy/uix/dialogs/lightning_channels.py b/electrum/gui/kivy/uix/dialogs/lightning_channels.py
       t@@ -410,11 +410,12 @@ Builder.load_string(r'''
        
        class ChannelBackupPopup(Popup, Logger):
        
       -    def __init__(self, chan: AbstractChannel, app: 'ElectrumWindow', **kwargs):
       +    def __init__(self, chan: AbstractChannel, channels_list, **kwargs):
                Popup.__init__(self, **kwargs)
                Logger.__init__(self)
                self.chan = chan
       -        self.app = app
       +        self.channels_list = channels_list
       +        self.app = channels_list.app
                self.short_id = format_short_channel_id(chan.short_channel_id)
                self.state = chan.get_state_for_GUI()
                self.title = _('Channel Backup')
       t@@ -427,7 +428,7 @@ class ChannelBackupPopup(Popup, Logger):
                if not b:
                    return
                loop = self.app.wallet.network.asyncio_loop
       -        coro = asyncio.run_coroutine_threadsafe(self.app.wallet.lnbackups.request_force_close(self.chan.channel_id), loop)
       +        coro = asyncio.run_coroutine_threadsafe(self.app.wallet.lnworker.request_force_close_from_backup(self.chan.channel_id), loop)
                try:
                    coro.result(5)
                    self.app.show_info(_('Channel closed'))
       t@@ -442,7 +443,7 @@ class ChannelBackupPopup(Popup, Logger):
            def _remove_backup(self, b):
                if not b:
                    return
       -        self.app.wallet.lnbackups.remove_channel_backup(self.chan.channel_id)
       +        self.app.wallet.lnworker.remove_channel_backup(self.chan.channel_id)
                self.dismiss()
        
        
       t@@ -550,9 +551,9 @@ class LightningChannelsDialog(Factory.Popup):
            def show_item(self, obj):
                chan = obj._chan
                if chan.is_backup():
       -            p = ChannelBackupPopup(chan, self.app)
       +            p = ChannelBackupPopup(chan, self)
                else:
       -            p = ChannelDetailsPopup(chan, self.app)
       +            p = ChannelDetailsPopup(chan, self)
                p.open()
        
            def format_fields(self, chan):
       t@@ -587,8 +588,7 @@ class LightningChannelsDialog(Factory.Popup):
                    return
                lnworker = self.app.wallet.lnworker
                channels = list(lnworker.channels.values()) if lnworker else []
       -        lnbackups = self.app.wallet.lnbackups
       -        backups = list(lnbackups.channel_backups.values())
       +        backups = list(lnworker.channel_backups.values()) if lnworker else []
                for i in channels + backups:
                    item = Factory.LightningChannelItem()
                    item.screen = self
   DIR diff --git a/electrum/gui/qt/channels_list.py b/electrum/gui/qt/channels_list.py
       t@@ -65,7 +65,6 @@ class ChannelsList(MyTreeView):
                self.update_single_row.connect(self.do_update_single_row)
                self.network = self.parent.network
                self.lnworker = self.parent.wallet.lnworker
       -        self.lnbackups = self.parent.wallet.lnbackups
                self.setSortingEnabled(True)
        
            def format_fields(self, chan: AbstractChannel) -> Dict['ChannelsList.Columns', str]:
       t@@ -136,7 +135,7 @@ class ChannelsList(MyTreeView):
        
            def remove_channel_backup(self, channel_id):
                if self.main_window.question(_('Remove channel backup?')):
       -            self.lnbackups.remove_channel_backup(channel_id)
       +            self.lnworker.remove_channel_backup(channel_id)
        
            def export_channel_backup(self, channel_id):
                msg = ' '.join([
       t@@ -150,7 +149,7 @@ class ChannelsList(MyTreeView):
        
            def request_force_close(self, channel_id):
                def task():
       -            coro = self.lnbackups.request_force_close(channel_id)
       +            coro = self.lnworker.request_force_close_from_backup(channel_id)
                    return self.network.run_from_another_thread(coro)
                def on_success(b):
                    self.main_window.show_message('success')
       t@@ -185,7 +184,7 @@ class ChannelsList(MyTreeView):
                if not item:
                    return
                channel_id = idx.sibling(idx.row(), self.Columns.NODE_ALIAS).data(ROLE_CHANNEL_ID)
       -        if channel_id in self.lnbackups.channel_backups:
       +        if channel_id in self.lnworker.channel_backups:
                    menu.addAction(_("Request force-close"), lambda: self.request_force_close(channel_id))
                    menu.addAction(_("Delete"), lambda: self.remove_channel_backup(channel_id))
                    menu.exec_(self.viewport().mapToGlobal(position))
       t@@ -253,7 +252,7 @@ class ChannelsList(MyTreeView):
                if wallet != self.parent.wallet:
                    return
                channels = list(wallet.lnworker.channels.values()) if wallet.lnworker else []
       -        backups = list(wallet.lnbackups.channel_backups.values())
       +        backups = list(wallet.lnworker.channel_backups.values()) if wallet.lnworker else []
                if wallet.lnworker:
                    self.update_can_send(wallet.lnworker)
                self.model().clear()
   DIR diff --git a/electrum/lnpeer.py b/electrum/lnpeer.py
       t@@ -52,7 +52,7 @@ from .json_db import StoredDict
        from .invoices import PR_PAID
        
        if TYPE_CHECKING:
       -    from .lnworker import LNGossip, LNWallet, LNBackups
       +    from .lnworker import LNGossip, LNWallet
            from .lnrouter import LNPaymentRoute
            from .transaction import PartialTransaction
        
       t@@ -65,10 +65,12 @@ class Peer(Logger):
        
            def __init__(
                    self,
       -            lnworker: Union['LNGossip', 'LNWallet', 'LNBackups'],
       +            lnworker: Union['LNGossip', 'LNWallet'],
                    pubkey: bytes,
       -            transport: LNTransportBase
       -    ):
       +            transport: LNTransportBase,
       +            *, is_channel_backup= False):
       +
       +        self.is_channel_backup = is_channel_backup
                self._sent_init = False  # type: bool
                self._received_init = False  # type: bool
                self.initialized = asyncio.Future()
       t@@ -171,8 +173,7 @@ class Peer(Logger):
            def process_message(self, message):
                message_type, payload = decode_msg(message)
                # only process INIT if we are a backup
       -        from .lnworker import LNBackups
       -        if isinstance(self.lnworker, LNBackups) and message_type != 'init':
       +        if self.is_channel_backup is True and message_type != 'init':
                    return
                if message_type in self.ordered_messages:
                    chan_id = payload.get('channel_id') or payload["temporary_channel_id"]
   DIR diff --git a/electrum/lnworker.py b/electrum/lnworker.py
       t@@ -599,6 +599,11 @@ class LNWallet(LNWorker):
                for channel_id, c in random_shuffled_copy(channels.items()):
                    self._channels[bfh(channel_id)] = Channel(c, sweep_address=self.sweep_address, lnworker=self)
        
       +        self._channel_backups = {}  # type: Dict[bytes, Channel]
       +        channel_backups = self.db.get_dict("channel_backups")
       +        for channel_id, cb in random_shuffled_copy(channel_backups.items()):
       +            self._channel_backups[bfh(channel_id)] = ChannelBackup(cb, sweep_address=self.sweep_address, lnworker=self)
       +
                self.sent_htlcs = defaultdict(asyncio.Queue)  # type: Dict[bytes, asyncio.Queue[HtlcLog]]
                self.sent_htlcs_routes = dict()               # (RHASH, scid, htlc_id) -> route, payment_secret, amount_msat, bucket_msat
                self.sent_buckets = dict()                    # payment_secret -> (amount_sent, amount_failed)
       t@@ -618,6 +623,12 @@ class LNWallet(LNWorker):
                with self.lock:
                    return self._channels.copy()
        
       +    @property
       +    def channel_backups(self) -> Mapping[bytes, Channel]:
       +        """Returns a read-only copy of channels."""
       +        with self.lock:
       +            return self._channel_backups.copy()
       +
            def get_channel_by_id(self, channel_id: bytes) -> Optional[Channel]:
                return self._channels.get(channel_id, None)
        
       t@@ -680,6 +691,8 @@ class LNWallet(LNWorker):
        
                for chan in self.channels.values():
                    self.lnwatcher.add_channel(chan.funding_outpoint.to_str(), chan.get_funding_address())
       +        for cb in self.channel_backups.values():
       +            self.lnwatcher.add_channel(cb.funding_outpoint.to_str(), cb.get_funding_address())
        
                for coro in [
                        self.maybe_listen(),
       t@@ -843,7 +856,8 @@ class LNWallet(LNWorker):
                        if chan.node_id == node_id}
        
            def channel_state_changed(self, chan: Channel):
       -        self.save_channel(chan)
       +        if type(chan) is Channel:
       +            self.save_channel(chan)
                util.trigger_callback('channel', self.wallet, chan)
        
            def save_channel(self, chan: Channel):
       t@@ -857,8 +871,14 @@ class LNWallet(LNWorker):
                for chan in self.channels.values():
                    if chan.funding_outpoint.to_str() == txo:
                        return chan
       +        for chan in self.channel_backups.values():
       +            if chan.funding_outpoint.to_str() == txo:
       +                return chan
        
            async def on_channel_update(self, chan: Channel):
       +        if type(chan) is ChannelBackup:
       +            util.trigger_callback('channel', self.wallet, chan)
       +            return
        
                if chan.get_state() == ChannelState.OPEN and chan.should_be_closed_due_to_expiring_htlcs(self.network.get_local_height()):
                    self.logger.info(f"force-closing due to expiring htlcs")
       t@@ -1940,61 +1960,6 @@ class LNWallet(LNWorker):
                peer = await self.add_peer(connect_str)
                await peer.trigger_force_close(channel_id)
        
       -
       -class LNBackups(Logger):
       -
       -    lnwatcher: Optional['LNWalletWatcher']
       -
       -    def __init__(self, wallet: 'Abstract_Wallet'):
       -        Logger.__init__(self)
       -        self.features = LNWALLET_FEATURES
       -        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)
       -
       -    @property
       -    def sweep_address(self) -> str:
       -        # TODO possible address-reuse
       -        return self.wallet.get_new_sweep_address_for_channel()
       -
       -    def channel_state_changed(self, chan):
       -        util.trigger_callback('channel', self.wallet, chan)
       -
       -    def peer_closed(self, chan):
       -        pass
       -
       -    async def on_channel_update(self, chan):
       -        util.trigger_callback('channel', self.wallet, chan)
       -
       -    def channel_by_txo(self, txo):
       -        with self.lock:
       -            channel_backups = list(self.channel_backups.values())
       -        for chan in channel_backups:
       -            if chan.funding_outpoint.to_str() == txo:
       -                return chan
       -
       -    def on_peer_successfully_established(self, peer: Peer) -> None:
       -        pass
       -
       -    def channels_for_peer(self, node_id):
       -        return {}
       -
       -    def start_network(self, network: 'Network'):
       -        assert network
       -        self.lnwatcher = LNWalletWatcher(self, network)
       -        self.lnwatcher.start_network(network)
       -        self.network = network
       -        for cb in self.channel_backups.values():
       -            self.lnwatcher.add_channel(cb.funding_outpoint.to_str(), cb.get_funding_address())
       -
       -    def stop(self):
       -        self.lnwatcher.stop()
       -        self.lnwatcher = None
       -
            def import_channel_backup(self, data):
                assert data.startswith('channel_backup:')
                encrypted = data[15:]
       t@@ -2015,19 +1980,20 @@ class LNBackups(Logger):
                d = self.db.get_dict("channel_backups")
                if channel_id.hex() not in d:
                    raise Exception('Channel not found')
       -        d.pop(channel_id.hex())
       -        self.channel_backups.pop(channel_id)
       +        with self.lock:
       +            d.pop(channel_id.hex())
       +            self._channel_backups.pop(channel_id)
                self.wallet.save_db()
                util.trigger_callback('channels_updated', self.wallet)
        
            @log_exceptions
       -    async def request_force_close(self, channel_id: bytes):
       +    async def request_force_close_from_backup(self, channel_id: bytes):
                cb = self.channel_backups[channel_id].cb
                # TODO also try network addresses from gossip db (as it might have changed)
                peer_addr = LNPeerAddr(cb.host, cb.port, cb.node_id)
                transport = LNTransport(cb.privkey, peer_addr,
                                        proxy=self.network.proxy)
       -        peer = Peer(self, cb.node_id, transport)
       +        peer = Peer(self, cb.node_id, transport, is_channel_backup=True)
                async with TaskGroup() as group:
                    await group.spawn(peer._message_loop())
                    await group.spawn(peer.trigger_force_close(channel_id))
   DIR diff --git a/electrum/wallet.py b/electrum/wallet.py
       t@@ -80,7 +80,7 @@ from .contacts import Contacts
        from .interface import NetworkException
        from .mnemonic import Mnemonic
        from .logging import get_logger
       -from .lnworker import LNWallet, LNBackups
       +from .lnworker import LNWallet
        from .paymentrequest import PaymentRequest
        from .util import read_json_file, write_json_file, UserFacingException
        
       t@@ -273,7 +273,6 @@ class Abstract_Wallet(AddressSynchronizer, ABC):
            txin_type: str
            wallet_type: str
            lnworker: Optional['LNWallet']
       -    lnbackups: Optional['LNBackups']
        
            def __init__(self, db: WalletDB, storage: Optional[WalletStorage], *, config: SimpleConfig):
                if not db.is_ready_to_be_used_by_wallet():
       t@@ -310,8 +309,6 @@ class Abstract_Wallet(AddressSynchronizer, ABC):
                self._coin_price_cache = {}
        
                self.lnworker = None
       -        # a wallet may have channel backups, regardless of lnworker activation
       -        self.lnbackups = LNBackups(self)
        
            def save_db(self):
                if self.storage:
       t@@ -364,7 +361,6 @@ class Abstract_Wallet(AddressSynchronizer, ABC):
                    if self.lnworker:
                        self.lnworker.stop()
                        self.lnworker = None
       -            self.lnbackups.stop()
                self.save_db()
        
            def set_up_to_date(self, b):
       t@@ -383,7 +379,6 @@ class Abstract_Wallet(AddressSynchronizer, ABC):
                        # only start gossiping when we already have channels
                        if self.db.get('channels'):
                            self.network.start_gossip()
       -            self.lnbackups.start_network(network)
        
            def load_and_cleanup(self):
                self.load_keystore()