Browse Source

Make storage a field of db

This comes from the jsonpatch_new branch.
I rather have in master now, because it touches a lot of filese.
master
ThomasV 3 years ago
parent
commit
b96cc82333
  1. 4
      electrum/base_wizard.py
  2. 4
      electrum/daemon.py
  3. 6
      electrum/gui/kivy/main_window.py
  4. 4
      electrum/gui/kivy/uix/dialogs/password_dialog.py
  5. 8
      electrum/gui/qml/qewalletdb.py
  6. 4
      electrum/gui/qt/__init__.py
  7. 4
      electrum/gui/stdio.py
  8. 4
      electrum/gui/text.py
  9. 14
      electrum/json_db.py
  10. 2
      electrum/lnwatcher.py
  11. 4
      electrum/plugins/trustedcoin/trustedcoin.py
  12. 10
      electrum/tests/test_storage_upgrade.py
  13. 24
      electrum/tests/test_wallet.py
  14. 12
      electrum/tests/test_wallet_vertical.py
  15. 57
      electrum/wallet.py
  16. 8
      electrum/wallet_db.py
  17. 2
      electrum/wizard.py
  18. 4
      run_electrum

4
electrum/base_wizard.py

@ -680,12 +680,12 @@ class BaseWizard(Logger):
storage = WalletStorage(path)
if pw_args.encrypt_storage:
storage.set_password(pw_args.password, enc_version=pw_args.storage_enc_version)
db = WalletDB('', manual_upgrades=False)
db = WalletDB('', storage=storage, manual_upgrades=False)
db.set_keystore_encryption(bool(pw_args.password) and pw_args.encrypt_keystore)
for key, value in self.data.items():
db.put(key, value)
db.load_plugins()
db.write(storage)
db.write()
return storage, db
def terminate(self, *, storage: WalletStorage = None,

4
electrum/daemon.py

@ -511,14 +511,14 @@ class Daemon(Logger):
return
storage.decrypt(password)
# read data, pass it to db
db = WalletDB(storage.read(), manual_upgrades=manual_upgrades)
db = WalletDB(storage.read(), storage=storage, manual_upgrades=manual_upgrades)
if db.requires_split():
return
if db.requires_upgrade():
return
if db.get_action():
return
wallet = Wallet(db, storage, config=config)
wallet = Wallet(db, config=config)
return wallet
@with_wallet_lock

6
electrum/gui/kivy/main_window.py

@ -673,13 +673,13 @@ class ElectrumWindow(App, Logger, EventListener):
else:
return ''
def on_wizard_success(self, storage, db, password):
def on_wizard_success(self, db, password):
self.password = password
if self.electrum_config.WALLET_USE_SINGLE_PASSWORD:
self._use_single_password = self.daemon.update_password_for_directory(
old_password=password, new_password=password)
self.logger.info(f'use single password: {self._use_single_password}')
wallet = Wallet(db, storage, config=self.electrum_config)
wallet = Wallet(db, config=self.electrum_config)
wallet.start_network(self.daemon.network)
self.daemon.add_wallet(wallet)
self.load_wallet(wallet)
@ -714,7 +714,7 @@ class ElectrumWindow(App, Logger, EventListener):
wizard.run('new')
else:
assert storage.is_past_initial_decryption()
db = WalletDB(storage.read(), manual_upgrades=False)
db = WalletDB(storage.read(), storage=storage, manual_upgrades=False)
assert not db.requires_upgrade()
self.on_wizard_success(storage, db, password)

4
electrum/gui/kivy/uix/dialogs/password_dialog.py

@ -359,8 +359,8 @@ class OpenWalletDialog(PasswordDialog):
else:
# it is a bit wasteful load the wallet here and load it again in main_window,
# but that is fine, because we are progressively enforcing storage encryption.
db = WalletDB(self.storage.read(), manual_upgrades=False)
wallet = Wallet(db, self.storage, config=self.app.electrum_config)
db = WalletDB(self.storage.read(), storage=self.storage, manual_upgrades=False)
wallet = Wallet(db, config=self.app.electrum_config)
self.require_password = wallet.has_password()
self.pw_check = wallet.check_password
self.message = self.enter_pw_message if self.require_password else _('Wallet not encrypted')

8
electrum/gui/qml/qewalletdb.py

@ -162,8 +162,8 @@ class QEWalletDB(QObject):
else: # storage not encrypted; but it might still have a keystore pw
# FIXME hack... load both db and full wallet, just to tell if it has keystore pw.
# this also completely ignores db.requires_split(), db.get_action(), etc
db = WalletDB(self._storage.read(), manual_upgrades=False)
wallet = Wallet(db, self._storage, config=self._config)
db = WalletDB(self._storage.read(), storage=self._storage, manual_upgrades=False)
wallet = Wallet(db, config=self._config)
self.needsPassword = wallet.has_password()
if self.needsPassword:
try:
@ -181,7 +181,7 @@ class QEWalletDB(QObject):
def _load_db(self):
"""can raise WalletFileException"""
# needs storage accessible
self._db = WalletDB(self._storage.read(), manual_upgrades=True)
self._db = WalletDB(self._storage.read(), storage=self._storage, manual_upgrades=True)
if self._db.requires_split():
self._logger.warning('wallet requires split')
self._requiresSplit = True
@ -194,7 +194,7 @@ class QEWalletDB(QObject):
if self._db.requires_upgrade():
self._logger.warning('wallet requires upgrade, upgrading')
self._db.upgrade()
self._db.write(self._storage)
self._db.write()
self._ready = True
self.readyChanged.emit()

4
electrum/gui/qt/__init__.py

@ -407,7 +407,7 @@ class ElectrumGui(BaseElectrumGui, Logger):
wizard.run('new')
storage, db = wizard.create_storage(path)
else:
db = WalletDB(storage.read(), manual_upgrades=False)
db = WalletDB(storage.read(), storage=storage, manual_upgrades=False)
wizard.run_upgrades(storage, db)
except (UserCancelled, GoBack):
return
@ -418,7 +418,7 @@ class ElectrumGui(BaseElectrumGui, Logger):
# return if wallet creation is not complete
if storage is None or db.get_action():
return
wallet = Wallet(db, storage, config=self.config)
wallet = Wallet(db, config=self.config)
wallet.start_network(self.daemon.network)
self.daemon.add_wallet(wallet)
return wallet

4
electrum/gui/stdio.py

@ -33,7 +33,7 @@ class ElectrumGui(BaseElectrumGui, EventListener):
password = getpass.getpass('Password:', stream=None)
storage.decrypt(password)
db = WalletDB(storage.read(), manual_upgrades=False)
db = WalletDB(storage.read(), storage=storage, manual_upgrades=False)
self.done = 0
self.last_balance = ""
@ -43,7 +43,7 @@ class ElectrumGui(BaseElectrumGui, EventListener):
self.str_amount = ""
self.str_fee = ""
self.wallet = Wallet(db, storage, config=config) # type: Optional[Abstract_Wallet]
self.wallet = Wallet(db, config=config) # type: Optional[Abstract_Wallet]
self.wallet.start_network(self.network)
self.contacts = self.wallet.contacts

4
electrum/gui/text.py

@ -60,8 +60,8 @@ class ElectrumGui(BaseElectrumGui, EventListener):
if storage.is_encrypted():
password = getpass.getpass('Password:', stream=None)
storage.decrypt(password)
db = WalletDB(storage.read(), manual_upgrades=False)
self.wallet = Wallet(db, storage, config=config) # type: Optional[Abstract_Wallet]
db = WalletDB(storage.read(), storage=storage, manual_upgrades=False)
self.wallet = Wallet(db, config=config) # type: Optional[Abstract_Wallet]
self.wallet.start_network(self.network)
self.contacts = self.wallet.contacts

14
electrum/json_db.py

@ -168,9 +168,10 @@ class StoredDict(dict):
class JsonDB(Logger):
def __init__(self, data):
def __init__(self, data, storage=None):
Logger.__init__(self)
self.lock = threading.RLock()
self.storage = storage
self._modified = False
# load data
if data:
@ -268,18 +269,17 @@ class JsonDB(Logger):
v = constructor(v)
return v
def write(self, storage: 'WalletStorage'):
def write(self):
with self.lock:
self._write(storage)
self._write()
@profiler
def _write(self, storage: 'WalletStorage'):
def _write(self):
if threading.current_thread().daemon:
self.logger.warning('daemon thread cannot write db')
return
if not self.modified():
return
json_str = self.dump(human_readable=not storage.is_encrypted())
storage.write(json_str)
json_str = self.dump(human_readable=not self.storage.is_encrypted())
self.storage.write(json_str)
self.set_modified(False)

2
electrum/lnwatcher.py

@ -325,7 +325,7 @@ class WatchTower(LNWatcher):
LOGGING_SHORTCUT = 'W'
def __init__(self, network: 'Network'):
adb = AddressSynchronizer(WalletDB({}, manual_upgrades=False), network.config, name=self.diagnostic_name())
adb = AddressSynchronizer(WalletDB({}, storage=None, manual_upgrades=False), network.config, name=self.diagnostic_name())
adb.start_network(network)
LNWatcher.__init__(self, adb, network)
self.network = network

4
electrum/plugins/trustedcoin/trustedcoin.py

@ -265,9 +265,9 @@ class Wallet_2fa(Multisig_Wallet):
wallet_type = '2fa'
def __init__(self, db, storage, *, config):
def __init__(self, db, *, config):
self.m, self.n = 2, 3
Deterministic_Wallet.__init__(self, db, storage, config=config)
Deterministic_Wallet.__init__(self, db, config=config)
self.is_billing = False
self.billing_info = None
self._load_billing_addresses()

10
electrum/tests/test_storage_upgrade.py

@ -270,7 +270,7 @@ class TestStorageUpgrade(WalletTestCase):
# see #6066
wallet_str = '''{"addr_history":{"bc1q0k4hemnmw5czyq7yyka5mpc3hvz37lk0urhd34":[],"bc1q2tgeuhkr85pjkrys44zn2a7lfap0g8u7ny68p3":[],"bc1q2xm8slpsqlt47u0j7segcsfmaq6s4s2pvx2526":[],"bc1q4dhwcvnnm8a0umt4gvn2tatq66qf9d37rx5t8u":[],"bc1q4pqe6tcfyl8m35myj9trz7fn4w0kdpljnt3sxd":[],"bc1q5l345sqf8fhlurn4hgu8dxu0w76j5tf3kc2f7h":[],"bc1q5nd447vdf9gx0l8xmj500wr859pny29xurgcpn":[],"bc1qaa2xnanrpmttw35gc4xqvz9ldz5sggqvc2ed72":[],"bc1qav4zrnx5g4s5h2z5hzr9hncg8qwt96ezltepmp":[],"bc1qcxryu22d3k66k4l55dzupvx45e88lmvp3rcww3":[],"bc1qd4us67486cn5qy44z6v6ervv5cuzrykq0vlcw2":[],"bc1qdd773rd9p8t3eylv2gvs2tmn2n79pwcfz65uyp":[],"bc1qdwafv8hy0cx9utkkj4hs6ntafm3x95m9zgpgvn":[],"bc1qehqt2um35x0c49snyugf94hvh7jz3vcjt0ya6m":[],"bc1qex23ueucc9hxyxgk3jg8ahw7cgw954legfnrxg":[],"bc1qf4tx5eesmrcy478gk384s2jv4lfh9dwt9jws0e":[],"bc1qh9l2au0f6m2fl3l3qa6perw5xnpvjul8lyylkt":[],"bc1qkmprcg50zcsdd0p3w70w2rxs5hwmwwn2xd0ls9":[],"bc1qkztpz05djsatmxxafgjqqldp0yfs8knr6um3e4":[],"bc1qrgj0zygryl6edylgm6gzx5j9rghdufrn5fp6hw":[],"bc1qscxh3na5uqapjm006xmg4s0geurq7nw427ywca":[],"bc1qunqye3f6cw88wqsjkks7amskder0rvufu49l6e":[],"bc1qv077qy5udlr3q8ammxq9ecq57vh9lxjnwh0vy9":[],"bc1qw9nqstryl3e0e49jg6670u6mu8507takz66qgv":[],"bc1qx4neqay68lmvgrav3yslzuempv9xn7aqdks5r6":[],"bc1qzhwpu84e5ajet4mxxr9ylc0fwass3q5k32uj5u":[]},"addresses":{"change":["bc1qdd773rd9p8t3eylv2gvs2tmn2n79pwcfz65uyp","bc1qv077qy5udlr3q8ammxq9ecq57vh9lxjnwh0vy9","bc1qx4neqay68lmvgrav3yslzuempv9xn7aqdks5r6","bc1qh9l2au0f6m2fl3l3qa6perw5xnpvjul8lyylkt","bc1qw9nqstryl3e0e49jg6670u6mu8507takz66qgv","bc1qaa2xnanrpmttw35gc4xqvz9ldz5sggqvc2ed72"],"receiving":["bc1qav4zrnx5g4s5h2z5hzr9hncg8qwt96ezltepmp","bc1qzhwpu84e5ajet4mxxr9ylc0fwass3q5k32uj5u","bc1qehqt2um35x0c49snyugf94hvh7jz3vcjt0ya6m","bc1q0k4hemnmw5czyq7yyka5mpc3hvz37lk0urhd34","bc1qf4tx5eesmrcy478gk384s2jv4lfh9dwt9jws0e","bc1q2xm8slpsqlt47u0j7segcsfmaq6s4s2pvx2526","bc1q5nd447vdf9gx0l8xmj500wr859pny29xurgcpn","bc1qex23ueucc9hxyxgk3jg8ahw7cgw954legfnrxg","bc1qscxh3na5uqapjm006xmg4s0geurq7nw427ywca","bc1qdwafv8hy0cx9utkkj4hs6ntafm3x95m9zgpgvn","bc1qkmprcg50zcsdd0p3w70w2rxs5hwmwwn2xd0ls9","bc1qunqye3f6cw88wqsjkks7amskder0rvufu49l6e","bc1q5l345sqf8fhlurn4hgu8dxu0w76j5tf3kc2f7h","bc1q4pqe6tcfyl8m35myj9trz7fn4w0kdpljnt3sxd","bc1qkztpz05djsatmxxafgjqqldp0yfs8knr6um3e4","bc1q4dhwcvnnm8a0umt4gvn2tatq66qf9d37rx5t8u","bc1q2tgeuhkr85pjkrys44zn2a7lfap0g8u7ny68p3","bc1qrgj0zygryl6edylgm6gzx5j9rghdufrn5fp6hw","bc1qd4us67486cn5qy44z6v6ervv5cuzrykq0vlcw2","bc1qcxryu22d3k66k4l55dzupvx45e88lmvp3rcww3"]},"keystore":{"cfg":{"mode":0,"pair":""},"derivation":"m/84'/0'/0'","hw_type":"ledger","label":"","type":"hardware","xpub":"zpub6qmVsnBYWipPzoeuZwtVeVnC42achPEZpGopT7jsop5WgDuFqKT3aS3EuAAQ6G76wbwtvDMdzffwxyEtwa6iafXSgjW2RjraiXfsgxQHnz8"},"seed_version":18,"spent_outpoints":{},"stored_height":646576,"transactions":{},"tx_fees":{},"txi":{},"txo":{},"use_encryption":false,"verified_tx3":{},"wallet_type":"standard","winpos-qt":[168,276,840,400]}'''
db = await self._upgrade_storage(wallet_str)
wallet = Wallet(db, None, config=self.config)
wallet = Wallet(db, config=self.config)
ks = wallet.keystore
# to simulate ks.opportunistically_fill_in_missing_info_from_device():
ks._root_fingerprint = "deadbeef"
@ -281,7 +281,7 @@ class TestStorageUpgrade(WalletTestCase):
# see #6401
wallet_str = '{"addr_history":{"1364Js2VG66BwRdkaoxAaFtdPb1eQgn8Dr":[],"15CyDgLffJsJgQrhcyooFH4gnVDG82pUrA":[],"1Exet2BhHsFxKTwhnfdsBMkPYLGvobxuW6":[]},"addresses":{"change":[],"receiving":["1364Js2VG66BwRdkaoxAaFtdPb1eQgn8Dr","1Exet2BhHsFxKTwhnfdsBMkPYLGvobxuW6","15CyDgLffJsJgQrhcyooFH4gnVDG82pUrA"]},"keystore":{"keypairs":{"0344b1588589958b0bcab03435061539e9bcf54677c104904044e4f8901f4ebdf5":"L2sED74axVXC4H8szBJ4rQJrkfem7UMc6usLCPUoEWxDCFGUaGUM","0389508c13999d08ffae0f434a085f4185922d64765c0bff2f66e36ad7f745cc5f":"L3Gi6EQLvYw8gEEUckmqawkevfj9s8hxoQDFveQJGZHTfyWnbk1U","04575f52b82f159fa649d2a4c353eb7435f30206f0a6cb9674fbd659f45082c37d559ffd19bea9c0d3b7dcc07a7b79f4cffb76026d5d4dff35341efe99056e22d2":"5JyVyXU1LiRXATvRTQvR9Kp8Rx1X84j2x49iGkjSsXipydtByUq"},"type":"imported"},"pruned_txo":{},"seed_version":13,"stored_height":-1,"transactions":{},"tx_fees":{},"txi":{},"txo":{},"use_encryption":false,"verified_tx3":{},"wallet_type":"standard","winpos-qt":[100,100,840,405]}'
db = await self._upgrade_storage(wallet_str)
wallet = Wallet(db, None, config=self.config)
wallet = Wallet(db, config=self.config)
wallet.import_private_keys(
["p2wpkh:L1cgMEnShp73r9iCukoPE3MogLeueNYRD9JVsfT1zVHyPBR3KqBY"],
password=None
@ -339,16 +339,16 @@ class TestStorageUpgrade(WalletTestCase):
self.assertEqual(accounts, len(split_data))
for item in split_data:
data = json.dumps(item)
new_db = WalletDB(data, manual_upgrades=False)
new_db = WalletDB(data, storage=None, manual_upgrades=False)
await self._sanity_check_upgraded_db(new_db)
async def _sanity_check_upgraded_db(self, db):
self.assertFalse(db.requires_split())
self.assertFalse(db.requires_upgrade())
wallet = Wallet(db, None, config=self.config)
wallet = Wallet(db, config=self.config)
await wallet.stop()
@staticmethod
def _load_db_from_json_string(*, wallet_json, manual_upgrades):
db = WalletDB(wallet_json, manual_upgrades=manual_upgrades)
db = WalletDB(wallet_json, storage=None, manual_upgrades=manual_upgrades)
return db

24
electrum/tests/test_wallet.py

@ -62,14 +62,14 @@ class TestWalletStorage(WalletTestCase):
contents = f.write(contents)
storage = WalletStorage(self.wallet_path)
db = WalletDB(storage.read(), manual_upgrades=True)
db = WalletDB(storage.read(), storage=storage, manual_upgrades=True)
self.assertEqual("b", db.get("a"))
self.assertEqual("d", db.get("c"))
def test_write_dictionary_to_file(self):
storage = WalletStorage(self.wallet_path)
db = WalletDB('', manual_upgrades=True)
db = WalletDB('', storage=storage, manual_upgrades=True)
some_dict = {
u"a": u"b",
@ -78,7 +78,7 @@ class TestWalletStorage(WalletTestCase):
for key, value in some_dict.items():
db.put(key, value)
db.write(storage)
db.write()
with open(self.wallet_path, "r") as f:
contents = f.read()
@ -112,7 +112,7 @@ class FakeWallet:
def __init__(self, fiat_value):
super().__init__()
self.fiat_value = fiat_value
self.db = WalletDB("{}", manual_upgrades=True)
self.db = WalletDB("{}", storage=None, manual_upgrades=True)
self.adb = FakeADB()
self.db.transactions = self.db.verified_tx = {'abc':'Tx'}
@ -258,9 +258,9 @@ class TestWalletPassword(WalletTestCase):
async def test_update_password_of_imported_wallet(self):
wallet_str = '{"addr_history":{"1364Js2VG66BwRdkaoxAaFtdPb1eQgn8Dr":[],"15CyDgLffJsJgQrhcyooFH4gnVDG82pUrA":[],"1Exet2BhHsFxKTwhnfdsBMkPYLGvobxuW6":[]},"addresses":{"change":[],"receiving":["1364Js2VG66BwRdkaoxAaFtdPb1eQgn8Dr","1Exet2BhHsFxKTwhnfdsBMkPYLGvobxuW6","15CyDgLffJsJgQrhcyooFH4gnVDG82pUrA"]},"keystore":{"keypairs":{"0344b1588589958b0bcab03435061539e9bcf54677c104904044e4f8901f4ebdf5":"L2sED74axVXC4H8szBJ4rQJrkfem7UMc6usLCPUoEWxDCFGUaGUM","0389508c13999d08ffae0f434a085f4185922d64765c0bff2f66e36ad7f745cc5f":"L3Gi6EQLvYw8gEEUckmqawkevfj9s8hxoQDFveQJGZHTfyWnbk1U","04575f52b82f159fa649d2a4c353eb7435f30206f0a6cb9674fbd659f45082c37d559ffd19bea9c0d3b7dcc07a7b79f4cffb76026d5d4dff35341efe99056e22d2":"5JyVyXU1LiRXATvRTQvR9Kp8Rx1X84j2x49iGkjSsXipydtByUq"},"type":"imported"},"pruned_txo":{},"seed_version":13,"stored_height":-1,"transactions":{},"tx_fees":{},"txi":{},"txo":{},"use_encryption":false,"verified_tx3":{},"wallet_type":"standard","winpos-qt":[100,100,840,405]}'
db = WalletDB(wallet_str, manual_upgrades=False)
storage = WalletStorage(self.wallet_path)
wallet = Wallet(db, storage, config=self.config)
db = WalletDB(wallet_str, storage=storage, manual_upgrades=False)
wallet = Wallet(db, config=self.config)
wallet.check_password(None)
@ -274,9 +274,9 @@ class TestWalletPassword(WalletTestCase):
async def test_update_password_of_standard_wallet(self):
wallet_str = '''{"addr_history":{"12ECgkzK6gHouKAZ7QiooYBuk1CgJLJxes":[],"12iR43FPb5M7sw4Mcrr5y1nHKepg9EtZP1":[],"13HT1pfWctsSXVFzF76uYuVdQvcAQ2MAgB":[],"13kG9WH9JqS7hyCcVL1ssLdNv4aXocQY9c":[],"14Tf3qiiHJXStSU4KmienAhHfHq7FHpBpz":[],"14gmBxYV97mzYwWdJSJ3MTLbTHVegaKrcA":[],"15FGuHvRssu1r8fCw98vrbpfc3M4xs5FAV":[],"17oJzweA2gn6SDjsKgA9vUD5ocT1sSnr2Z":[],"18hNcSjZzRcRP6J2bfFRxp9UfpMoC4hGTv":[],"18n9PFxBjmKCGhd4PCDEEqYsi2CsnEfn2B":[],"19a98ZfEezDNbCwidVigV5PAJwrR2kw4Jz":[],"19z3j2ELqbg2pR87byCCt3BCyKR7rc3q8G":[],"1A3XSmvLQvePmvm7yctsGkBMX9ZKKXLrVq":[],"1CmhFe2BN1h9jheFpJf4v39XNPj8F9U6d":[],"1DuphhHUayKzbkdvjVjf5dtjn2ACkz4zEs":[],"1E4ygSNJpWL2uPXZHBptmU2LqwZTqb1Ado":[],"1GTDSjkVc9vaaBBBGNVqTANHJBcoT5VW9z":[],"1GWqgpThAuSq3tDg6uCoLQxPXQNnU8jZ52":[],"1GhmpwqSF5cqNgdr9oJMZx8dKxPRo4pYPP":[],"1J5TTUQKhwehEACw6Jjte1E22FVrbeDmpv":[],"1JWySzjzJhsETUUcqVZHuvQLA7pfFfmesb":[],"1KQHxcy3QUHAWMHKUtJjqD9cMKXcY2RTwZ":[],"1KoxZfc2KsgovjGDxwqanbFEA76uxgYH4G":[],"1KqVEPXdpbYvEbwsZcEKkrA4A2jsgj9hYN":[],"1N16yDSYe76c5A3CoVoWAKxHeAUc8Jhf9J":[],"1Pm8JBhzUJDqeQQKrmnop1Frr4phe1jbTt":[]},"addresses":{"change":["1GhmpwqSF5cqNgdr9oJMZx8dKxPRo4pYPP","1GTDSjkVc9vaaBBBGNVqTANHJBcoT5VW9z","15FGuHvRssu1r8fCw98vrbpfc3M4xs5FAV","1A3XSmvLQvePmvm7yctsGkBMX9ZKKXLrVq","19z3j2ELqbg2pR87byCCt3BCyKR7rc3q8G","1JWySzjzJhsETUUcqVZHuvQLA7pfFfmesb"],"receiving":["14gmBxYV97mzYwWdJSJ3MTLbTHVegaKrcA","13HT1pfWctsSXVFzF76uYuVdQvcAQ2MAgB","19a98ZfEezDNbCwidVigV5PAJwrR2kw4Jz","1J5TTUQKhwehEACw6Jjte1E22FVrbeDmpv","1Pm8JBhzUJDqeQQKrmnop1Frr4phe1jbTt","13kG9WH9JqS7hyCcVL1ssLdNv4aXocQY9c","1KQHxcy3QUHAWMHKUtJjqD9cMKXcY2RTwZ","12ECgkzK6gHouKAZ7QiooYBuk1CgJLJxes","12iR43FPb5M7sw4Mcrr5y1nHKepg9EtZP1","14Tf3qiiHJXStSU4KmienAhHfHq7FHpBpz","1KqVEPXdpbYvEbwsZcEKkrA4A2jsgj9hYN","17oJzweA2gn6SDjsKgA9vUD5ocT1sSnr2Z","1E4ygSNJpWL2uPXZHBptmU2LqwZTqb1Ado","18hNcSjZzRcRP6J2bfFRxp9UfpMoC4hGTv","1KoxZfc2KsgovjGDxwqanbFEA76uxgYH4G","18n9PFxBjmKCGhd4PCDEEqYsi2CsnEfn2B","1CmhFe2BN1h9jheFpJf4v39XNPj8F9U6d","1DuphhHUayKzbkdvjVjf5dtjn2ACkz4zEs","1GWqgpThAuSq3tDg6uCoLQxPXQNnU8jZ52","1N16yDSYe76c5A3CoVoWAKxHeAUc8Jhf9J"]},"keystore":{"seed":"cereal wise two govern top pet frog nut rule sketch bundle logic","type":"bip32","xprv":"xprv9s21ZrQH143K29XjRjUs6MnDB9wXjXbJP2kG1fnRk8zjdDYWqVkQYUqaDtgZp5zPSrH5PZQJs8sU25HrUgT1WdgsPU8GbifKurtMYg37d4v","xpub":"xpub661MyMwAqRbcEdcCXm1sTViwjBn28zK9kFfrp4C3JUXiW1sfP34f6HA45B9yr7EH5XGzWuTfMTdqpt9XPrVQVUdgiYb5NW9m8ij1FSZgGBF"},"pruned_txo":{},"seed_type":"standard","seed_version":13,"stored_height":-1,"transactions":{},"tx_fees":{},"txi":{},"txo":{},"use_encryption":false,"verified_tx3":{},"wallet_type":"standard","winpos-qt":[619,310,840,405]}'''
db = WalletDB(wallet_str, manual_upgrades=False)
storage = WalletStorage(self.wallet_path)
wallet = Wallet(db, storage, config=self.config)
db = WalletDB(wallet_str, storage=storage, manual_upgrades=False)
wallet = Wallet(db, config=self.config)
wallet.check_password(None)
@ -289,16 +289,16 @@ class TestWalletPassword(WalletTestCase):
async def test_update_password_with_app_restarts(self):
wallet_str = '{"addr_history":{"1364Js2VG66BwRdkaoxAaFtdPb1eQgn8Dr":[],"15CyDgLffJsJgQrhcyooFH4gnVDG82pUrA":[],"1Exet2BhHsFxKTwhnfdsBMkPYLGvobxuW6":[]},"addresses":{"change":[],"receiving":["1364Js2VG66BwRdkaoxAaFtdPb1eQgn8Dr","1Exet2BhHsFxKTwhnfdsBMkPYLGvobxuW6","15CyDgLffJsJgQrhcyooFH4gnVDG82pUrA"]},"keystore":{"keypairs":{"0344b1588589958b0bcab03435061539e9bcf54677c104904044e4f8901f4ebdf5":"L2sED74axVXC4H8szBJ4rQJrkfem7UMc6usLCPUoEWxDCFGUaGUM","0389508c13999d08ffae0f434a085f4185922d64765c0bff2f66e36ad7f745cc5f":"L3Gi6EQLvYw8gEEUckmqawkevfj9s8hxoQDFveQJGZHTfyWnbk1U","04575f52b82f159fa649d2a4c353eb7435f30206f0a6cb9674fbd659f45082c37d559ffd19bea9c0d3b7dcc07a7b79f4cffb76026d5d4dff35341efe99056e22d2":"5JyVyXU1LiRXATvRTQvR9Kp8Rx1X84j2x49iGkjSsXipydtByUq"},"type":"imported"},"pruned_txo":{},"seed_version":13,"stored_height":-1,"transactions":{},"tx_fees":{},"txi":{},"txo":{},"use_encryption":false,"verified_tx3":{},"wallet_type":"standard","winpos-qt":[100,100,840,405]}'
db = WalletDB(wallet_str, manual_upgrades=False)
storage = WalletStorage(self.wallet_path)
wallet = Wallet(db, storage, config=self.config)
db = WalletDB(wallet_str, storage=storage, manual_upgrades=False)
wallet = Wallet(db, config=self.config)
await wallet.stop()
storage = WalletStorage(self.wallet_path)
# if storage.is_encrypted():
# storage.decrypt(password)
db = WalletDB(storage.read(), manual_upgrades=False)
wallet = Wallet(db, storage, config=self.config)
db = WalletDB(storage.read(), storage=storage, manual_upgrades=False)
wallet = Wallet(db, config=self.config)
wallet.check_password(None)

12
electrum/tests/test_wallet_vertical.py

@ -51,33 +51,33 @@ class WalletIntegrityHelper:
@classmethod
def create_standard_wallet(cls, ks, *, config: SimpleConfig, gap_limit=None):
db = storage.WalletDB('', manual_upgrades=False)
db = storage.WalletDB('', storage=None, manual_upgrades=False)
db.put('keystore', ks.dump())
db.put('gap_limit', gap_limit or cls.gap_limit)
w = Standard_Wallet(db, None, config=config)
w = Standard_Wallet(db, config=config)
w.synchronize()
return w
@classmethod
def create_imported_wallet(cls, *, config: SimpleConfig, privkeys: bool):
db = storage.WalletDB('', manual_upgrades=False)
db = storage.WalletDB('', storage=None, manual_upgrades=False)
if privkeys:
k = keystore.Imported_KeyStore({})
db.put('keystore', k.dump())
w = Imported_Wallet(db, None, config=config)
w = Imported_Wallet(db, config=config)
return w
@classmethod
def create_multisig_wallet(cls, keystores: Sequence, multisig_type: str, *,
config: SimpleConfig, gap_limit=None):
"""Creates a multisig wallet."""
db = storage.WalletDB('', manual_upgrades=True)
db = storage.WalletDB('', storage=None, manual_upgrades=True)
for i, ks in enumerate(keystores):
cosigner_index = i + 1
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, None, config=config)
w = Multisig_Wallet(db, config=config)
w.synchronize()
return w

57
electrum/wallet.py

@ -306,7 +306,7 @@ class Abstract_Wallet(ABC, Logger, EventListener):
lnworker: Optional['LNWallet']
network: Optional['Network']
def __init__(self, db: WalletDB, storage: Optional[WalletStorage], *, config: SimpleConfig):
def __init__(self, db: WalletDB, *, config: SimpleConfig):
if not db.is_ready_to_be_used_by_wallet():
raise Exception("storage not ready to be used by Abstract_Wallet")
@ -314,7 +314,7 @@ class Abstract_Wallet(ABC, Logger, EventListener):
self.config = config
assert self.config is not None, "config must not be None"
self.db = db
self.storage = storage
self.storage = db.storage
# load addresses needs to be called before constructor for sanity checks
db.load_addresses(self.wallet_type)
self.keystore = None # type: Optional[KeyStore] # will be set by load_keystore
@ -393,25 +393,24 @@ class Abstract_Wallet(ABC, Logger, EventListener):
await run_in_thread(self.synchronize)
def save_db(self):
if self.storage:
self.db.write(self.storage)
if self.db.storage:
self.db.write()
def save_backup(self, backup_dir):
new_db = WalletDB(self.db.dump(), manual_upgrades=False)
new_path = os.path.join(backup_dir, self.basename() + '.backup')
new_storage = WalletStorage(new_path)
new_storage._encryption_version = self.storage._encryption_version
new_storage.pubkey = self.storage.pubkey
new_db = WalletDB(self.db.dump(), storage=new_storage, manual_upgrades=False)
if self.lnworker:
channel_backups = new_db.get_dict('imported_channel_backups')
for chan_id, chan in self.lnworker.channels.items():
channel_backups[chan_id.hex()] = self.lnworker.create_channel_backup(chan_id)
new_db.put('channels', None)
new_db.put('lightning_privkey2', None)
new_path = os.path.join(backup_dir, self.basename() + '.backup')
new_storage = WalletStorage(new_path)
new_storage._encryption_version = self.storage._encryption_version
new_storage.pubkey = self.storage.pubkey
new_db.set_modified(True)
new_db.write(new_storage)
new_db.write()
return new_path
def has_lightning(self) -> bool:
@ -3059,8 +3058,8 @@ class Imported_Wallet(Simple_Wallet):
wallet_type = 'imported'
txin_type = 'address'
def __init__(self, db, storage, *, config):
Abstract_Wallet.__init__(self, db, storage, config=config)
def __init__(self, db, *, config):
Abstract_Wallet.__init__(self, db, config=config)
self.use_change = db.get('use_change', False)
def is_watching_only(self):
@ -3277,9 +3276,9 @@ class Imported_Wallet(Simple_Wallet):
class Deterministic_Wallet(Abstract_Wallet):
def __init__(self, db, storage, *, config):
def __init__(self, db, *, config):
self._ephemeral_addr_to_addr_index = {} # type: Dict[str, Sequence[int]]
Abstract_Wallet.__init__(self, db, storage, config=config)
Abstract_Wallet.__init__(self, db, config=config)
self.gap_limit = db.get('gap_limit', 20)
# generate addresses now. note that without libsecp this might block
# for a few seconds!
@ -3492,8 +3491,8 @@ class Simple_Deterministic_Wallet(Simple_Wallet, Deterministic_Wallet):
""" Deterministic Wallet with a single pubkey per address """
def __init__(self, db, storage, *, config):
Deterministic_Wallet.__init__(self, db, storage, config=config)
def __init__(self, db, *, config):
Deterministic_Wallet.__init__(self, db, config=config)
def get_public_key(self, address):
sequence = self.get_address_index(address)
@ -3530,10 +3529,10 @@ class Standard_Wallet(Simple_Deterministic_Wallet):
class Multisig_Wallet(Deterministic_Wallet):
# generic m of n
def __init__(self, db, storage, *, config):
def __init__(self, db, *, config):
self.wallet_type = db.get('wallet_type')
self.m, self.n = multisig_type(self.wallet_type)
Deterministic_Wallet.__init__(self, db, storage, config=config)
Deterministic_Wallet.__init__(self, db, config=config)
# sanity checks
for ks in self.get_keystores():
if not isinstance(ks, keystore.Xpub):
@ -3630,10 +3629,10 @@ class Wallet(object):
This class is actually a factory that will return a wallet of the correct
type when passed a WalletStorage instance."""
def __new__(self, db: 'WalletDB', storage: Optional[WalletStorage], *, config: SimpleConfig):
def __new__(self, db: 'WalletDB', *, config: SimpleConfig):
wallet_type = db.get('wallet_type')
WalletClass = Wallet.wallet_class(wallet_type)
wallet = WalletClass(db, storage, config=config)
wallet = WalletClass(db, config=config)
return wallet
@staticmethod
@ -3651,7 +3650,7 @@ def create_new_wallet(*, path, config: SimpleConfig, passphrase=None, password=N
storage = WalletStorage(path)
if storage.file_exists():
raise Exception("Remove the existing wallet first!")
db = WalletDB('', manual_upgrades=False)
db = WalletDB('', storage=storage, manual_upgrades=False)
seed = Mnemonic('en').make_seed(seed_type=seed_type)
k = keystore.from_seed(seed, passphrase)
@ -3661,7 +3660,7 @@ def create_new_wallet(*, path, config: SimpleConfig, passphrase=None, password=N
db.put('lightning_xprv', k.get_lightning_xprv(None))
if gap_limit is not None:
db.put('gap_limit', gap_limit)
wallet = Wallet(db, storage, config=config)
wallet = Wallet(db, config=config)
wallet.update_password(old_pw=None, new_pw=password, encrypt_storage=encrypt_file)
wallet.synchronize()
msg = "Please keep your seed in a safe place; if you lose it, you will not be able to restore your wallet."
@ -3690,10 +3689,10 @@ def restore_wallet_from_text(
raise Exception("Remove the existing wallet first!")
if encrypt_file is None:
encrypt_file = True
db = WalletDB('', manual_upgrades=False)
db = WalletDB('', storage=storage, manual_upgrades=False)
text = text.strip()
if keystore.is_address_list(text):
wallet = Imported_Wallet(db, storage, config=config)
wallet = Imported_Wallet(db, config=config)
addresses = text.split()
good_inputs, bad_inputs = wallet.import_addresses(addresses, write_to_disk=False)
# FIXME tell user about bad_inputs
@ -3702,7 +3701,7 @@ def restore_wallet_from_text(
elif keystore.is_private_key_list(text, allow_spaces_inside_key=False):
k = keystore.Imported_KeyStore({})
db.put('keystore', k.dump())
wallet = Imported_Wallet(db, storage, config=config)
wallet = Imported_Wallet(db, config=config)
keys = keystore.get_private_keys(text, allow_spaces_inside_key=False)
good_inputs, bad_inputs = wallet.import_private_keys(keys, None, write_to_disk=False)
# FIXME tell user about bad_inputs
@ -3721,9 +3720,9 @@ def restore_wallet_from_text(
db.put('wallet_type', 'standard')
if gap_limit is not None:
db.put('gap_limit', gap_limit)
wallet = Wallet(db, storage, config=config)
if storage:
assert not storage.file_exists(), "file was created too soon! plaintext keys might have been written to disk"
wallet = Wallet(db, config=config)
if db.storage:
assert not db.storage.file_exists(), "file was created too soon! plaintext keys might have been written to disk"
wallet.update_password(old_pw=None, new_pw=password, encrypt_storage=encrypt_file)
wallet.synchronize()
msg = ("This wallet was restored offline. It may contain more addresses than displayed. "

8
electrum/wallet_db.py

@ -102,8 +102,8 @@ for key in ['locked_in', 'fails', 'settles']:
class WalletDB(JsonDB):
def __init__(self, data, *, manual_upgrades: bool):
JsonDB.__init__(self, data)
def __init__(self, data, *, storage=None, manual_upgrades: bool):
JsonDB.__init__(self, data, storage)
if not data:
# create new DB
self.put('seed_version', FINAL_SEED_VERSION)
@ -1599,10 +1599,10 @@ class WalletDB(JsonDB):
for data in result:
path = root_path + '.' + data['suffix']
storage = WalletStorage(path)
db = WalletDB(json.dumps(data), manual_upgrades=False)
db = WalletDB(json.dumps(data), storage=storage, manual_upgrades=False)
db._called_after_upgrade_tasks = False
db.upgrade()
db.write(storage)
db.write()
out.append(path)
return out

2
electrum/wizard.py

@ -425,7 +425,7 @@ class NewWalletWizard(AbstractWizard):
k.update_password(None, data['password'])
storage.set_password(data['password'], enc_version=StorageEncryptionVersion.USER_PASSWORD)
db = WalletDB('', manual_upgrades=False)
db = WalletDB('', storage=storage, manual_upgrades=False)
db.set_keystore_encryption(bool(data['password']) and data['encrypt'])
db.put('wallet_type', data['wallet_type'])

4
run_electrum

@ -226,8 +226,8 @@ async def run_offline_command(config, config_options, plugins: 'Plugins'):
password = get_password_for_hw_device_encrypted_storage(plugins)
config_options['password'] = password
storage.decrypt(password)
db = WalletDB(storage.read(), manual_upgrades=False)
wallet = Wallet(db, storage, config=config)
db = WalletDB(storage.read(), storage=storage, manual_upgrades=False)
wallet = Wallet(db, config=config)
config_options['wallet'] = wallet
else:
wallet = None

Loading…
Cancel
Save