commit 8412b53ed59cf4f2f88dfe6577f3ef3c5a01502b
parent 9013f6d59e4134b623688bd030d2e894c054e4bf
Author: SomberNight <somber.night@protonmail.com>
Date: Mon, 4 Feb 2019 17:07:49 +0100
wizard: copy/restore storage when stepping through the wizard
When interacting with wizard, there is a single shared storage instance.
If you go down the tree of dialogs, press "back" a couple times, go
down another branch of dialogs, etc, there are side-effects on storage,
which are never undone.
fixes #5057
fixes #4496
Diffstat:
2 files changed, 34 insertions(+), 7 deletions(-)
diff --git a/electrum/base_wizard.py b/electrum/base_wizard.py
@@ -27,7 +27,7 @@ import os
import sys
import traceback
from functools import partial
-from typing import List, TYPE_CHECKING, Tuple
+from typing import List, TYPE_CHECKING, Tuple, NamedTuple, Any
from . import bitcoin
from . import keystore
@@ -56,6 +56,12 @@ class ScriptTypeNotSupported(Exception): pass
class GoBack(Exception): pass
+class WizardStackItem(NamedTuple):
+ action: Any
+ args: Any
+ storage_data: dict
+
+
class BaseWizard(object):
def __init__(self, config: SimpleConfig, plugins: Plugins, storage: WalletStorage):
@@ -64,7 +70,7 @@ class BaseWizard(object):
self.plugins = plugins
self.storage = storage
self.wallet = None # type: Abstract_Wallet
- self._stack = []
+ self._stack = [] # type: List[WizardStackItem]
self.plugin = None
self.keystores = []
self.is_kivy = config.get('gui') == 'kivy'
@@ -76,7 +82,8 @@ class BaseWizard(object):
def run(self, *args):
action = args[0]
args = args[1:]
- self._stack.append((action, args))
+ storage_data = self.storage.get_all_data()
+ self._stack.append(WizardStackItem(action, args, storage_data))
if not action:
return
if type(action) is tuple:
@@ -96,9 +103,15 @@ class BaseWizard(object):
def go_back(self):
if not self.can_go_back():
return
+ # pop 'current' frame
self._stack.pop()
- action, args = self._stack.pop()
- self.run(action, *args)
+ # pop 'previous' frame
+ stack_item = self._stack.pop()
+ # try to undo side effects since we last entered 'previous' frame
+ # FIXME only self.storage is properly restored
+ self.storage.overwrite_all_data(stack_item.storage_data)
+ # rerun 'previous' frame
+ self.run(stack_item.action, *stack_item.args)
def reset_stack(self):
self._stack = []
@@ -154,8 +167,8 @@ class BaseWizard(object):
def choose_multisig(self):
def on_multisig(m, n):
- self.multisig_type = "%dof%d"%(m, n)
- self.storage.put('wallet_type', self.multisig_type)
+ multisig_type = "%dof%d" % (m, n)
+ self.storage.put('wallet_type', multisig_type)
self.n = n
self.run('choose_keystore')
self.multisig_dialog(run_next=on_multisig)
diff --git a/electrum/storage.py b/electrum/storage.py
@@ -101,6 +101,20 @@ class JsonDB(PrintError):
self.modified = True
self.data.pop(key)
+ def get_all_data(self) -> dict:
+ with self.db_lock:
+ return copy.deepcopy(self.data)
+
+ def overwrite_all_data(self, data: dict) -> None:
+ try:
+ json.dumps(data, cls=util.MyEncoder)
+ except:
+ self.print_error(f"json error: cannot save {repr(data)}")
+ return
+ with self.db_lock:
+ self.modified = True
+ self.data = copy.deepcopy(data)
+
@profiler
def write(self):
with self.db_lock: