From a7199696d332eb37b8ba4d8b12e3fa40a09c1fac Mon Sep 17 00:00:00 2001
From: SomberNight <somber.night@protonmail.com>
Date: Fri, 4 Sep 2020 16:11:01 +0200
Subject: [PATCH] json_db: exempt keystore from StoredDict conversion

The keystore logic would need to be significantly changed to nicely
interoperate with StoredDict/json_db logic.
(just see KeyStore.__init__() and KeyStore.dump())
For now we exempt the keystore from the recursive StoredDict conversion, as
it is a smaller change that is also easier to review for correctness.

fixes #6066
fixes #6401

also reverts 2d3c2eeea9c225af2ec2d1654363c4b75c5b1158 (which was an even hackier workaround for #6066)
---
 electrum/json_db.py                   | 6 +++++-
 electrum/keystore.py                  | 1 -
 electrum/plugins/bitbox02/bitbox02.py | 2 +-
 electrum/plugins/ledger/ledger.py     | 1 -
 electrum/wallet_db.py                 | 8 ++++++++
 5 files changed, 14 insertions(+), 4 deletions(-)

diff --git a/electrum/json_db.py b/electrum/json_db.py
index 5e284df6a..69b7f216b 100644
--- a/electrum/json_db.py
+++ b/electrum/json_db.py
@@ -103,7 +103,8 @@ class StoredDict(dict):
         elif isinstance(v, dict):
             if self.db:
                 v = self.db._convert_dict(self.path, key, v)
-            v = StoredDict(v, self.db, self.path + [key])
+            if not self.db or self.db._should_convert_to_stored_dict(key):
+                v = StoredDict(v, self.db, self.path + [key])
         # convert_value is called depth-first
         if isinstance(v, dict) or isinstance(v, str):
             if self.db:
@@ -194,3 +195,6 @@ class JsonDB(Logger):
     @locked
     def dump(self):
         return json.dumps(self.data, indent=4, sort_keys=True, cls=JsonDBJsonEncoder)
+
+    def _should_convert_to_stored_dict(self, key) -> bool:
+        return True
diff --git a/electrum/keystore.py b/electrum/keystore.py
index 4f1fb9090..be9874344 100644
--- a/electrum/keystore.py
+++ b/electrum/keystore.py
@@ -894,7 +894,6 @@ def hardware_keystore(d) -> Hardware_KeyStore:
 
 def load_keystore(db: 'WalletDB', name: str) -> KeyStore:
     d = db.get(name, {})
-    d = dict(d)  # convert to dict from StoredDict (see #6066)
     t = d.get('type')
     if not t:
         raise WalletFileException(
diff --git a/electrum/plugins/bitbox02/bitbox02.py b/electrum/plugins/bitbox02/bitbox02.py
index e3f43ec46..2a3fff7ce 100644
--- a/electrum/plugins/bitbox02/bitbox02.py
+++ b/electrum/plugins/bitbox02/bitbox02.py
@@ -521,7 +521,7 @@ class BitBox02_KeyStore(Hardware_KeyStore):
     device = "BitBox02"
     plugin: "BitBox02Plugin"
 
-    def __init__(self, d: StoredDict):
+    def __init__(self, d: dict):
         super().__init__(d)
         self.force_watching_only = False
         self.ux_busy = False
diff --git a/electrum/plugins/ledger/ledger.py b/electrum/plugins/ledger/ledger.py
index 0b125c712..1a2761480 100644
--- a/electrum/plugins/ledger/ledger.py
+++ b/electrum/plugins/ledger/ledger.py
@@ -255,7 +255,6 @@ class Ledger_KeyStore(Hardware_KeyStore):
         self.force_watching_only = False
         self.signing = False
         self.cfg = d.get('cfg', {'mode': 0})
-        self.cfg = dict(self.cfg)  # convert to dict from StoredDict (see #6066)
 
     def dump(self):
         obj = Hardware_KeyStore.dump(self)
diff --git a/electrum/wallet_db.py b/electrum/wallet_db.py
index e0fbfb8ef..418375287 100644
--- a/electrum/wallet_db.py
+++ b/electrum/wallet_db.py
@@ -1211,6 +1211,14 @@ class WalletDB(JsonDB):
             v = Outpoint(**v)
         return v
 
+    def _should_convert_to_stored_dict(self, key) -> bool:
+        if key == 'keystore':
+            return False
+        multisig_keystore_names = [('x%d/' % i) for i in range(1, 16)]
+        if key in multisig_keystore_names:
+            return False
+        return True
+
     def write(self, storage: 'WalletStorage'):
         with self.lock:
             self._write(storage)