diff --git a/electrum/gui/kivy/main_window.py b/electrum/gui/kivy/main_window.py index 27af16634..cde6fdd21 100644 --- a/electrum/gui/kivy/main_window.py +++ b/electrum/gui/kivy/main_window.py @@ -193,10 +193,6 @@ class ElectrumWindow(App, Logger): self.network.run_from_another_thread( self.network.stop_gossip()) - android_backups = BooleanProperty(False) - def on_android_backups(self, instance, x): - self.electrum_config.set_key('android_backups', self.android_backups, True) - use_change = BooleanProperty(False) def on_use_change(self, instance, x): if self.wallet: @@ -407,7 +403,6 @@ class ElectrumWindow(App, Logger): self.daemon = self.gui_object.daemon self.fx = self.daemon.fx self.use_rbf = config.get('use_rbf', True) - self.android_backups = config.get('android_backups', False) self.use_gossip = config.get('use_gossip', False) self.use_unconfirmed = not config.get('confirmed_only', False) @@ -1300,9 +1295,14 @@ class ElectrumWindow(App, Logger): def save_backup(self): if platform != 'android': - self._save_backup() + backup_dir = util.get_backup_dir(self.electrum_config) + if backup_dir: + self._save_backup(backup_dir) + else: + self.show_error(_("Backup NOT saved. Backup directory not configured.")) return + backup_dir = util.android_backup_dir() from android.permissions import request_permissions, Permission def cb(permissions, grant_results: Sequence[bool]): if not grant_results or not grant_results[0]: @@ -1313,17 +1313,14 @@ class ElectrumWindow(App, Logger): Clock.schedule_once(lambda dt: self._save_backup()) request_permissions([Permission.WRITE_EXTERNAL_STORAGE], cb) - def _save_backup(self): + def _save_backup(self, backup_dir): try: - new_path = self.wallet.save_backup() + new_path = self.wallet.save_backup(backup_dir) except Exception as e: self.logger.exception("Failed to save wallet backup") self.show_error("Failed to save wallet backup" + '\n' + str(e)) return - if new_path: - self.show_info(_("Backup saved:") + f"\n{new_path}") - else: - self.show_error(_("Backup NOT saved. Backup directory not configured.")) + self.show_info(_("Backup saved:") + f"\n{new_path}") def export_private_keys(self, pk_label, addr): if self.wallet.is_watching_only(): diff --git a/electrum/gui/kivy/uix/dialogs/lightning_open_channel.py b/electrum/gui/kivy/uix/dialogs/lightning_open_channel.py index 54b52f21b..c927ee242 100644 --- a/electrum/gui/kivy/uix/dialogs/lightning_open_channel.py +++ b/electrum/gui/kivy/uix/dialogs/lightning_open_channel.py @@ -13,6 +13,7 @@ from electrum.lnutil import ln_dummy_address, extract_nodeid from .label_dialog import LabelDialog from .confirm_tx_dialog import ConfirmTxDialog +from .qr_dialog import QRDialog if TYPE_CHECKING: from ...main_window import ElectrumWindow @@ -208,6 +209,27 @@ class LightningOpenChannelDialog(Factory.Popup, Logger): self.app.logger.exception("Problem opening channel") self.app.show_error(_('Problem opening channel: ') + '\n' + repr(e)) return + # TODO: it would be nice to show this before broadcasting + if lnworker.has_recoverable_channels(): + self.maybe_show_funding_tx(chan, funding_tx) + else: + title = _('Save backup') + help_text = ' '.join([ + _('Your wallet does not have recoverable channels.'), + _('Please save this channel backup on another device.'), + _('It may be imported in another Electrum wallet with the same seed.') + ]) + data = lnworker.export_channel_backup(chan.channel_id) + popup = QRDialog( + title, data, + show_text=False, + text_for_clipboard=data, + help_text=help_text, + close_button_text=_('OK'), + on_close=lambda: self.maybe_show_funding_tx(chan, funding_tx)) + popup.open() + + def maybe_show_funding_tx(self, chan, funding_tx): n = chan.constraints.funding_txn_minimum_depth message = '\n'.join([ _('Channel established.'), @@ -217,5 +239,6 @@ class LightningOpenChannelDialog(Factory.Popup, Logger): if not funding_tx.is_complete(): message += '\n\n' + _('Please sign and broadcast the funding transaction') self.app.show_info(message) + if not funding_tx.is_complete(): self.app.tx_dialog(funding_tx) diff --git a/electrum/gui/kivy/uix/dialogs/settings.py b/electrum/gui/kivy/uix/dialogs/settings.py index 0cb2430ad..b2db28d2f 100644 --- a/electrum/gui/kivy/uix/dialogs/settings.py +++ b/electrum/gui/kivy/uix/dialogs/settings.py @@ -93,13 +93,6 @@ Builder.load_string(''' title: _('Lightning Routing') + ': ' + self.status description: _("Use trampoline routing or gossip.") action: partial(root.routing_dialog, self) - CardSeparator - SettingsItem: - status: _('Yes') if app.android_backups else _('No') - title: _('Backups') + ': ' + self.status - description: _("Backup wallet to external storage.") - message: _("If this option is checked, a backup of your wallet will be written to external storage everytime you create a new channel. Make sure your wallet is protected with a strong password before you enable this option.") - action: partial(root.boolean_dialog, 'android_backups', _('Backups'), self.message) # disabled: there is currently only one coin selection policy #CardSeparator diff --git a/electrum/gui/kivy/uix/ui_screens/status.kv b/electrum/gui/kivy/uix/ui_screens/status.kv index 1a7c5652f..e72fba8d8 100644 --- a/electrum/gui/kivy/uix/ui_screens/status.kv +++ b/electrum/gui/kivy/uix/ui_screens/status.kv @@ -81,7 +81,6 @@ Popup: size_hint: 0.5, None height: '48dp' text: _('Export Backup') - disabled: not app.android_backups on_release: root.dismiss() app.save_backup() diff --git a/electrum/gui/qt/main_window.py b/electrum/gui/qt/main_window.py index 90cef6877..79d6cc829 100644 --- a/electrum/gui/qt/main_window.py +++ b/electrum/gui/qt/main_window.py @@ -627,18 +627,18 @@ class ElectrumWindow(QMainWindow, MessageBoxMixin, Logger): vbox.addLayout(Buttons(CancelButton(d), OkButton(d))) if not d.exec_(): return False + backup_dir = get_backup_dir(self.config) + if backup_dir is not None: + self.show_message(_("You need to configure a backup directory in your preferences"), title=_("Backup not configured")) + return try: - new_path = self.wallet.save_backup() + new_path = self.wallet.save_backup(backup_dir) except BaseException as reason: self.show_critical(_("Electrum was unable to copy your wallet file to the specified location.") + "\n" + str(reason), title=_("Unable to create backup")) return - if new_path: - msg = _("A copy of your wallet file was created in")+" '%s'" % str(new_path) - self.show_message(msg, title=_("Wallet backup created")) - return True - else: - self.show_message(_("You need to configure a backup directory in your preferences"), title=_("Backup not created")) - return False + msg = _("A copy of your wallet file was created in")+" '%s'" % str(new_path) + self.show_message(msg, title=_("Wallet backup created")) + return True def update_recently_visited(self, filename): recent = self.config.get('recently_open', []) diff --git a/electrum/lnworker.py b/electrum/lnworker.py index d91c7c943..2a5fe449f 100644 --- a/electrum/lnworker.py +++ b/electrum/lnworker.py @@ -26,7 +26,7 @@ from aiorpcx import run_in_thread, TaskGroup, NetAddress, ignore_after from . import constants, util from . import keystore -from .util import profiler, chunks +from .util import profiler, chunks, get_backup_dir from .invoices import PR_TYPE_LN, PR_UNPAID, PR_EXPIRED, PR_PAID, PR_INFLIGHT, PR_FAILED, PR_ROUTING, LNInvoice, LN_EXPIRY_NEVER from .util import NetworkRetryManager, JsonRPCClient from .lnutil import LN_MAX_FUNDING_SAT @@ -1003,7 +1003,9 @@ class LNWallet(LNWorker): self.wallet.set_reserved_state_of_address(addr, reserved=True) try: self.save_channel(chan) - self.wallet.save_backup() + backup_dir = get_backup_dir(self.config) + if backup_dir is not None: + self.wallet.save_backup(backup_dir) except: chan.set_state(ChannelState.REDEEMED) self.remove_channel(chan.channel_id) diff --git a/electrum/util.py b/electrum/util.py index a6c20c768..88aa9a089 100644 --- a/electrum/util.py +++ b/electrum/util.py @@ -428,8 +428,10 @@ def android_data_dir(): return PythonActivity.mActivity.getFilesDir().getPath() + '/data' def get_backup_dir(config): + # this is used to save a backup everytime a channel is created + # on Android, the export backup button uses android_backup_dir() if 'ANDROID_DATA' in os.environ: - return android_backup_dir() if config.get('android_backups') else None + return None else: return config.get('backup_dir') diff --git a/electrum/wallet.py b/electrum/wallet.py index 575cf0e80..069ab1ab5 100644 --- a/electrum/wallet.py +++ b/electrum/wallet.py @@ -57,7 +57,6 @@ from .util import (NotEnoughFunds, UserCancelled, profiler, WalletFileException, BitcoinException, MultipleSpendMaxTxOutputs, InvalidPassword, format_time, timestamp_to_datetime, Satoshis, Fiat, bfh, bh2u, TxMinedInfo, quantize_feerate, create_bip21_uri, OrderedDictWithIndex) -from .util import get_backup_dir from .simple_config import SimpleConfig, FEE_RATIO_HIGH_WARNING, FEERATE_WARNING_HIGH_FEE from .bitcoin import COIN, TYPE_ADDRESS from .bitcoin import is_address, address_to_script, is_minikey, relayfee, dust_threshold @@ -315,10 +314,7 @@ class Abstract_Wallet(AddressSynchronizer, ABC): if self.storage: self.db.write(self.storage) - def save_backup(self): - backup_dir = get_backup_dir(self.config) - if backup_dir is None: - return + def save_backup(self, backup_dir): new_db = WalletDB(self.db.dump(), manual_upgrades=False) if self.lnworker: