URI: 
       twizard: copy/restore storage when stepping through the wizard - electrum - Electrum Bitcoin wallet
  HTML git clone https://git.parazyd.org/electrum
   DIR Log
   DIR Files
   DIR Refs
   DIR Submodules
       ---
   DIR commit 8412b53ed59cf4f2f88dfe6577f3ef3c5a01502b
   DIR parent 9013f6d59e4134b623688bd030d2e894c054e4bf
  HTML 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:
         M electrum/base_wizard.py             |      27 ++++++++++++++++++++-------
         M electrum/storage.py                 |      14 ++++++++++++++
       
       2 files changed, 34 insertions(+), 7 deletions(-)
       ---
   DIR diff --git a/electrum/base_wizard.py b/electrum/base_wizard.py
       t@@ -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
       t@@ -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):
       t@@ -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'
       t@@ -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:
       t@@ -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 = []
       t@@ -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)
   DIR diff --git a/electrum/storage.py b/electrum/storage.py
       t@@ -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: