Browse Source

On Android, if channels are not recoverable, display channel backup when a new channel is created.

Remove the 'android_backups' setting, which was unpractical.
patch-4
ThomasV 4 years ago
parent
commit
2fee920f43
  1. 21
      electrum/gui/kivy/main_window.py
  2. 23
      electrum/gui/kivy/uix/dialogs/lightning_open_channel.py
  3. 7
      electrum/gui/kivy/uix/dialogs/settings.py
  4. 1
      electrum/gui/kivy/uix/ui_screens/status.kv
  5. 16
      electrum/gui/qt/main_window.py
  6. 6
      electrum/lnworker.py
  7. 4
      electrum/util.py
  8. 6
      electrum/wallet.py

21
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():

23
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)

7
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

1
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()

16
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', [])

6
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)

4
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')

6
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:

Loading…
Cancel
Save