From 56e80c20d70ec93e9d497fae8c0f79cd096fd8ee Mon Sep 17 00:00:00 2001 From: ThomasV Date: Tue, 4 Feb 2020 12:45:31 +0100 Subject: [PATCH] wallet_db upgrade: do not use '/' in StoredDict keys --- electrum/gui/qt/__init__.py | 12 +++++----- electrum/plugins/trustedcoin/qt.py | 6 ++--- electrum/plugins/trustedcoin/trustedcoin.py | 26 ++++++++++----------- electrum/tests/test_wallet_vertical.py | 14 +++++------ electrum/wallet.py | 6 ++--- electrum/wallet_db.py | 14 +++++++++-- electrum/wizard.py | 18 +++++++------- 7 files changed, 53 insertions(+), 43 deletions(-) diff --git a/electrum/gui/qt/__init__.py b/electrum/gui/qt/__init__.py index 982f389d4..524c51657 100644 --- a/electrum/gui/qt/__init__.py +++ b/electrum/gui/qt/__init__.py @@ -420,7 +420,7 @@ class ElectrumGui(BaseElectrumGui, Logger): if not d['wallet_exists']: self.logger.info('about to create wallet') wizard.create_storage() - if d['wallet_type'] == '2fa' and 'x3/' not in d: + if d['wallet_type'] == '2fa' and 'x3' not in d: return wallet_file = wizard.path else: @@ -441,16 +441,16 @@ class ElectrumGui(BaseElectrumGui, Logger): if action := db.get_action(): # wallet creation is not complete, 2fa online phase assert action[1] == 'accept_terms_of_use', 'only support for resuming trustedcoin split setup' - k1 = load_keystore(db, 'x1/') + k1 = load_keystore(db, 'x1') if 'password' in d and d['password']: xprv = k1.get_master_private_key(d['password']) else: - xprv = db.get('x1/')['xprv'] + xprv = db.get('x1')['xprv'] data = { 'wallet_name': os.path.basename(wallet_file), 'xprv1': xprv, - 'xpub1': db.get('x1/')['xpub'], - 'xpub2': db.get('x2/')['xpub'], + 'xpub1': db.get('x1')['xpub'], + 'xpub2': db.get('x2')['xpub'], } wizard = QENewWalletWizard(self.config, self.app, self.plugins, self.daemon, path, start_viewstate=WizardViewState('trustedcoin_tos_email', data, {})) @@ -458,7 +458,7 @@ class ElectrumGui(BaseElectrumGui, Logger): if result == QENewWalletWizard.Rejected: self.logger.info('ok bye bye') return - db.put('x3/', wizard.get_wizard_data()['x3/']) + db.put('x3', wizard.get_wizard_data()['x3']) db.write() wallet = Wallet(db, config=self.config) diff --git a/electrum/plugins/trustedcoin/qt.py b/electrum/plugins/trustedcoin/qt.py index b59a41fd6..c17a5fb16 100644 --- a/electrum/plugins/trustedcoin/qt.py +++ b/electrum/plugins/trustedcoin/qt.py @@ -75,7 +75,7 @@ class HandlerTwoFactor(QObject, Logger): return if wallet.can_sign_without_server(): return - if not wallet.keystores['x3/'].can_sign(tx, ignore_watching_only=True): + if not wallet.keystores['x3'].can_sign(tx, ignore_watching_only=True): self.logger.info("twofactor: xpub3 not needed") return window = self.window.top_level_window() @@ -414,8 +414,8 @@ class Plugin(TrustedCoinPlugin): k1 = keystore.from_xprv(xprv1) k2 = keystore.from_xpub(xpub2) - wizard_data['x1/'] = k1.dump() - wizard_data['x2/'] = k2.dump() + wizard_data['x1'] = k1.dump() + wizard_data['x2'] = k2.dump() class WCDisclaimer(WizardComponent): diff --git a/electrum/plugins/trustedcoin/trustedcoin.py b/electrum/plugins/trustedcoin/trustedcoin.py index ea35ea081..b34b59c0b 100644 --- a/electrum/plugins/trustedcoin/trustedcoin.py +++ b/electrum/plugins/trustedcoin/trustedcoin.py @@ -405,8 +405,8 @@ class Wallet_2fa(Multisig_Wallet): def get_user_id(db): def make_long_id(xpub_hot, xpub_cold): return sha256(''.join(sorted([xpub_hot, xpub_cold]))) - xpub1 = db.get('x1/')['xpub'] - xpub2 = db.get('x2/')['xpub'] + xpub1 = db.get('x1')['xpub'] + xpub2 = db.get('x2')['xpub'] long_id = make_long_id(xpub1, xpub2) short_id = hashlib.sha256(long_id).hexdigest() return long_id, short_id @@ -468,7 +468,7 @@ class TrustedCoinPlugin(BasePlugin): return if wallet.can_sign_without_server(): return - if not wallet.keystores['x3/'].can_sign(tx, ignore_watching_only=True): + if not wallet.keystores['x3'].can_sign(tx, ignore_watching_only=True): self.logger.info("twofactor: xpub3 not needed") return def wrapper(tx): @@ -587,11 +587,11 @@ class TrustedCoinPlugin(BasePlugin): def get_action(self, db): if db.get('wallet_type') != '2fa': return - if not db.get('x1/'): + if not db.get('x1'): return self, 'show_disclaimer' - if not db.get('x2/'): + if not db.get('x2'): return self, 'show_disclaimer' - if not db.get('x3/'): + if not db.get('x3'): return self, 'accept_terms_of_use' # insert trustedcoin pages in new wallet wizard @@ -644,7 +644,7 @@ class TrustedCoinPlugin(BasePlugin): else: xprv1, xpub1, xprv2, xpub2 = self.xkeys_from_seed(wizard_data['seed'], wizard_data['seed_extra_words']) - data = {'x1/': {'xpub': xpub1}, 'x2/': {'xpub': xpub2}} + data = {'x1': {'xpub': xpub1}, 'x2': {'xpub': xpub2}} # Generate third key deterministically. long_user_id, short_id = get_user_id(data) @@ -660,9 +660,9 @@ class TrustedCoinPlugin(BasePlugin): k2 = keystore.from_xpub(xpub2) k3 = keystore.from_xpub(xpub3) - wizard_data['x1/'] = k1.dump() - wizard_data['x2/'] = k2.dump() - wizard_data['x3/'] = k3.dump() + wizard_data['x1'] = k1.dump() + wizard_data['x2'] = k2.dump() + wizard_data['x3'] = k3.dump() def recovery_disable(self, wizard_data): if wizard_data['trustedcoin_keepordisable'] != 'disable': @@ -674,7 +674,7 @@ class TrustedCoinPlugin(BasePlugin): k2 = keystore.from_xprv(xprv2) k3 = keystore.from_xpub(xpub3) - wizard_data['x1/'] = k1.dump() - wizard_data['x2/'] = k2.dump() - wizard_data['x3/'] = k3.dump() + wizard_data['x1'] = k1.dump() + wizard_data['x2'] = k2.dump() + wizard_data['x3'] = k3.dump() diff --git a/electrum/tests/test_wallet_vertical.py b/electrum/tests/test_wallet_vertical.py index 0a91d8186..3f9037f7b 100644 --- a/electrum/tests/test_wallet_vertical.py +++ b/electrum/tests/test_wallet_vertical.py @@ -74,7 +74,7 @@ class WalletIntegrityHelper: db = storage.WalletDB('', storage=None, upgrade=False) for i, ks in enumerate(keystores): cosigner_index = i + 1 - db.put('x%d/' % cosigner_index, ks.dump()) + db.put('x%d' % cosigner_index, ks.dump()) db.put('wallet_type', multisig_type) db.put('gap_limit', gap_limit or cls.gap_limit) w = Multisig_Wallet(db, config=config) @@ -190,8 +190,8 @@ class TestWalletKeystoreAddressIntegrityForMainnet(ElectrumTestCase): self.assertEqual(ks2.xpub, xpub2) long_user_id, short_id = trustedcoin.get_user_id( - {'x1/': {'xpub': xpub1}, - 'x2/': {'xpub': xpub2}}) + {'x1': {'xpub': xpub1}, + 'x2': {'xpub': xpub2}}) xtype = bip32.xpub_type(xpub1) xpub3 = trustedcoin.make_xpub(trustedcoin.get_signing_xpub(xtype), long_user_id) ks3 = keystore.from_xpub(xpub3) @@ -225,8 +225,8 @@ class TestWalletKeystoreAddressIntegrityForMainnet(ElectrumTestCase): self.assertEqual(ks2.xpub, xpub2) long_user_id, short_id = trustedcoin.get_user_id( - {'x1/': {'xpub': xpub1}, - 'x2/': {'xpub': xpub2}}) + {'x1': {'xpub': xpub1}, + 'x2': {'xpub': xpub2}}) xtype = bip32.xpub_type(xpub1) xpub3 = trustedcoin.make_xpub(trustedcoin.get_signing_xpub(xtype), long_user_id) ks3 = keystore.from_xpub(xpub3) @@ -259,8 +259,8 @@ class TestWalletKeystoreAddressIntegrityForMainnet(ElectrumTestCase): self.assertEqual(ks2.xpub, xpub2) long_user_id, short_id = trustedcoin.get_user_id( - {'x1/': {'xpub': xpub1}, - 'x2/': {'xpub': xpub2}}) + {'x1': {'xpub': xpub1}, + 'x2': {'xpub': xpub2}}) xtype = bip32.xpub_type(xpub1) xpub3 = trustedcoin.make_xpub(trustedcoin.get_signing_xpub(xtype), long_user_id) ks3 = keystore.from_xpub(xpub3) diff --git a/electrum/wallet.py b/electrum/wallet.py index 2dfc68cc3..b08ca023f 100644 --- a/electrum/wallet.py +++ b/electrum/wallet.py @@ -3615,9 +3615,9 @@ class Multisig_Wallet(Deterministic_Wallet): def load_keystore(self): self.keystores = {} for i in range(self.n): - name = 'x%d/'%(i+1) + name = 'x%d'%(i+1) self.keystores[name] = load_keystore(self.db, name) - self.keystore = self.keystores['x1/'] + self.keystore = self.keystores['x1'] xtype = bip32.xpub_type(self.keystore.xpub) self.txin_type = 'p2sh' if xtype == 'standard' else xtype @@ -3626,7 +3626,7 @@ class Multisig_Wallet(Deterministic_Wallet): self.db.put(name, k.dump()) def get_keystore(self): - return self.keystores.get('x1/') + return self.keystores.get('x1') def get_keystores(self): return [self.keystores[i] for i in sorted(self.keystores.keys())] diff --git a/electrum/wallet_db.py b/electrum/wallet_db.py index 56837fbd9..69e34dd8b 100644 --- a/electrum/wallet_db.py +++ b/electrum/wallet_db.py @@ -59,7 +59,7 @@ class WalletRequiresSplit(WalletFileException): OLD_SEED_VERSION = 4 # electrum versions < 2.0 NEW_SEED_VERSION = 11 # electrum versions >= 2.0 -FINAL_SEED_VERSION = 54 # electrum >= 2.7 will set this to prevent +FINAL_SEED_VERSION = 55 # electrum >= 2.7 will set this to prevent # old versions from overwriting new format @@ -217,6 +217,7 @@ class WalletDBUpgrader(Logger): self._convert_version_52() self._convert_version_53() self._convert_version_54() + self._convert_version_55() self.put('seed_version', FINAL_SEED_VERSION) # just to be sure def _convert_wallet_type(self): @@ -1065,6 +1066,15 @@ class WalletDBUpgrader(Logger): del d[key] self.data['seed_version'] = 54 + def _convert_version_55(self): + if not self._is_upgrade_method_needed(54, 54): + return + # do not use '/' in dict keys + for key in list(self.data.keys()): + if key.endswith('/'): + self.data[key[:-1]] = self.data.pop(key) + self.data['seed_version'] = 55 + def _convert_imported(self): if not self._is_upgrade_method_needed(0, 13): return @@ -1619,7 +1629,7 @@ class WalletDB(JsonDB): 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)] + multisig_keystore_names = [('x%d' % i) for i in range(1, 16)] if key in multisig_keystore_names: return False return True diff --git a/electrum/wizard.py b/electrum/wizard.py index 9c54776c6..0ba82a988 100644 --- a/electrum/wizard.py +++ b/electrum/wizard.py @@ -547,7 +547,7 @@ class NewWalletWizard(AbstractWizard): k = keystore.from_bip43_rootseed(root_seed, derivation, xtype=script) elif is_any_2fa_seed_type(data['seed_type']): self._logger.debug('creating keystore from 2fa seed') - k = keystore.from_xprv(data['x1/']['xprv']) + k = keystore.from_xprv(data['x1']['xprv']) else: raise Exception('unsupported/unknown seed_type %s' % data['seed_type']) elif data['keystore_type'] == 'masterkey': @@ -597,23 +597,23 @@ class NewWalletWizard(AbstractWizard): if data['wallet_type'] == 'standard': db.put('keystore', k.dump()) elif data['wallet_type'] == '2fa': - db.put('x1/', k.dump()) + db.put('x1', k.dump()) if 'trustedcoin_keepordisable' in data and data['trustedcoin_keepordisable'] == 'disable': - k2 = keystore.from_xprv(data['x2/']['xprv']) + k2 = keystore.from_xprv(data['x2']['xprv']) if data['encrypt'] and k2.may_have_password(): k2.update_password(None, data['password']) - db.put('x2/', k2.dump()) + db.put('x2', k2.dump()) else: - db.put('x2/', data['x2/']) - if 'x3/' in data: - db.put('x3/', data['x3/']) + db.put('x2', data['x2']) + if 'x3' in data: + db.put('x3', data['x3']) db.put('use_trustedcoin', True) elif data['wallet_type'] == 'multisig': if not isinstance(k, keystore.Xpub): raise Exception(f'unexpected keystore(main) type={type(k)} in multisig. not bip32.') k_xpub_type = xpub_type(k.xpub) db.put('wallet_type', '%dof%d' % (data['multisig_signatures'], data['multisig_participants'])) - db.put('x1/', k.dump()) + db.put('x1', k.dump()) for cosigner in data['multisig_cosigner_data']: cosigner_keystore = self.keystore_from_data('multisig', data['multisig_cosigner_data'][cosigner]) if not isinstance(cosigner_keystore, keystore.Xpub): @@ -622,7 +622,7 @@ class NewWalletWizard(AbstractWizard): raise Exception('multisig wallet needs to have homogeneous xpub types') if data['encrypt'] and cosigner_keystore.may_have_password(): cosigner_keystore.update_password(None, data['password']) - db.put(f'x{cosigner}/', cosigner_keystore.dump()) + db.put(f'x{cosigner}', cosigner_keystore.dump()) elif data['wallet_type'] == 'imported': if k: db.put('keystore', k.dump())