Browse Source

Separate WalletDB from storage upgrades.

Make sure that WalletDB.data is always a StoredDict.
Perform db upgrades in a separate class, since they
operate on a dict object.
master
ThomasV 2 years ago
parent
commit
b5bc5ff9ed
  1. 7
      electrum/daemon.py
  2. 15
      electrum/gui/qml/qewalletdb.py
  3. 7
      electrum/gui/qt/__init__.py
  4. 22
      electrum/gui/qt/wizard/wallet.py
  5. 30
      electrum/json_db.py
  6. 2
      electrum/lnwatcher.py
  7. 29
      electrum/tests/test_storage_upgrade.py
  8. 8
      electrum/tests/test_wallet.py
  9. 4
      electrum/wallet.py
  10. 143
      electrum/wallet_db.py

7
electrum/daemon.py

@ -47,7 +47,7 @@ from .util import log_exceptions, ignore_exceptions, randrange, OldTaskGroup
from .util import EventListener, event_listener from .util import EventListener, event_listener
from .wallet import Wallet, Abstract_Wallet from .wallet import Wallet, Abstract_Wallet
from .storage import WalletStorage from .storage import WalletStorage
from .wallet_db import WalletDB from .wallet_db import WalletDB, WalletRequiresSplit, WalletRequiresUpgrade
from .commands import known_commands, Commands from .commands import known_commands, Commands
from .simple_config import SimpleConfig from .simple_config import SimpleConfig
from .exchange_rate import FxThread from .exchange_rate import FxThread
@ -512,10 +512,11 @@ class Daemon(Logger):
return return
storage.decrypt(password) storage.decrypt(password)
# read data, pass it to db # read data, pass it to db
try:
db = WalletDB(storage.read(), storage=storage, manual_upgrades=manual_upgrades) db = WalletDB(storage.read(), storage=storage, manual_upgrades=manual_upgrades)
if db.requires_split(): except WalletRequiresSplit:
return return
if db.requires_upgrade(): except WalletRequiresUpgrade:
return return
if db.get_action(): if db.get_action():
return return

15
electrum/gui/qml/qewalletdb.py

@ -5,7 +5,7 @@ from PyQt5.QtCore import pyqtProperty, pyqtSignal, pyqtSlot, QObject
from electrum.i18n import _ from electrum.i18n import _
from electrum.logging import get_logger from electrum.logging import get_logger
from electrum.storage import WalletStorage from electrum.storage import WalletStorage
from electrum.wallet_db import WalletDB from electrum.wallet_db import WalletDB, WalletRequiresSplit
from electrum.wallet import Wallet from electrum.wallet import Wallet
from electrum.util import InvalidPassword, WalletFileException, send_exception_to_crash_reporter from electrum.util import InvalidPassword, WalletFileException, send_exception_to_crash_reporter
@ -143,7 +143,10 @@ class QEWalletDB(QObject):
else: # storage not encrypted; but it might still have a keystore pw 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. # 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 # this also completely ignores db.requires_split(), db.get_action(), etc
try:
db = WalletDB(self._storage.read(), storage=self._storage, manual_upgrades=False) db = WalletDB(self._storage.read(), storage=self._storage, manual_upgrades=False)
except WalletRequiresSplit as e:
raise WalletFileException(_('This wallet requires to be split. This is currently not supported on mobile'))
wallet = Wallet(db, config=self._config) wallet = Wallet(db, config=self._config)
self.needsPassword = wallet.has_password() self.needsPassword = wallet.has_password()
if self.needsPassword: if self.needsPassword:
@ -162,18 +165,14 @@ class QEWalletDB(QObject):
def _load_db(self): def _load_db(self):
"""can raise WalletFileException""" """can raise WalletFileException"""
# needs storage accessible # needs storage accessible
self._db = WalletDB(self._storage.read(), storage=self._storage, manual_upgrades=True) try:
if self._db.requires_split(): self._db = WalletDB(self._storage.read(), storage=self._storage, manual_upgrades=False)
except WalletRequiresSplit as e:
self._logger.warning('wallet requires split') self._logger.warning('wallet requires split')
raise WalletFileException(_('This wallet needs splitting. This is not supported on mobile')) raise WalletFileException(_('This wallet needs splitting. This is not supported on mobile'))
if self._db.get_action(): if self._db.get_action():
self._logger.warning('action pending. QML version doesn\'t support continuation of wizard') self._logger.warning('action pending. QML version doesn\'t support continuation of wizard')
raise WalletFileException(_('This wallet has an action pending. This is currently not supported on mobile')) raise WalletFileException(_('This wallet has an action pending. This is currently not supported on mobile'))
if self._db.requires_upgrade():
self._logger.warning('wallet requires upgrade, upgrading')
self._db.upgrade()
self._db.write()
self._ready = True self._ready = True
self.readyChanged.emit() self.readyChanged.emit()

7
electrum/gui/qt/__init__.py

@ -61,7 +61,7 @@ from electrum.plugin import run_hook
from electrum.util import (UserCancelled, profiler, send_exception_to_crash_reporter, from electrum.util import (UserCancelled, profiler, send_exception_to_crash_reporter,
WalletFileException, BitcoinException, get_new_wallet_name) WalletFileException, BitcoinException, get_new_wallet_name)
from electrum.wallet import Wallet, Abstract_Wallet from electrum.wallet import Wallet, Abstract_Wallet
from electrum.wallet_db import WalletDB from electrum.wallet_db import WalletDB, WalletRequiresSplit, WalletRequiresUpgrade
from electrum.logging import Logger from electrum.logging import Logger
from electrum.gui import BaseElectrumGui from electrum.gui import BaseElectrumGui
from electrum.simple_config import SimpleConfig from electrum.simple_config import SimpleConfig
@ -430,10 +430,11 @@ class ElectrumGui(BaseElectrumGui, Logger):
if storage.is_encrypted_with_user_pw() or storage.is_encrypted_with_hw_device(): if storage.is_encrypted_with_user_pw() or storage.is_encrypted_with_hw_device():
storage.decrypt(d['password']) storage.decrypt(d['password'])
try:
db = WalletDB(storage.read(), storage=storage, manual_upgrades=True) db = WalletDB(storage.read(), storage=storage, manual_upgrades=True)
if db.requires_split() or db.requires_upgrade(): except WalletRequiresSplit as e:
try: try:
wizard.run_upgrades(db) wizard.run_split(storage, e._split_data)
except UserCancelled: except UserCancelled:
return return

22
electrum/gui/qt/wizard/wallet.py

@ -2,6 +2,7 @@ import os
import sys import sys
import threading import threading
import time import time
import json
from typing import TYPE_CHECKING from typing import TYPE_CHECKING
@ -21,6 +22,7 @@ from electrum.wallet import wallet_types
from .wizard import QEAbstractWizard, WizardComponent from .wizard import QEAbstractWizard, WizardComponent
from electrum.logging import get_logger, Logger from electrum.logging import get_logger, Logger
from electrum import WalletStorage, mnemonic, keystore from electrum import WalletStorage, mnemonic, keystore
from electrum.wallet_db import WalletDB
from electrum.wizard import NewWalletWizard from electrum.wizard import NewWalletWizard
from electrum.gui.qt.bip39_recovery_dialog import Bip39RecoveryDialog from electrum.gui.qt.bip39_recovery_dialog import Bip39RecoveryDialog
@ -34,7 +36,6 @@ if TYPE_CHECKING:
from electrum.simple_config import SimpleConfig from electrum.simple_config import SimpleConfig
from electrum.plugin import Plugins from electrum.plugin import Plugins
from electrum.daemon import Daemon from electrum.daemon import Daemon
from electrum.wallet_db import WalletDB
from electrum.gui.qt import QElectrumApplication from electrum.gui.qt import QElectrumApplication
WIF_HELP_TEXT = (_('WIF keys are typed in Electrum, based on script type.') + '\n\n' + WIF_HELP_TEXT = (_('WIF keys are typed in Electrum, based on script type.') + '\n\n' +
@ -161,25 +162,20 @@ class QENewWalletWizard(NewWalletWizard, QEAbstractWizard, MessageBoxMixin):
self._password = data['password'] self._password = data['password']
self.path = path self.path = path
def run_upgrades(self, db: 'WalletDB') -> None: def run_split(self, storage, split_data) -> None:
storage = db.storage root_path = storage.path
path = storage.path
if db.requires_split():
msg = _( msg = _(
"The wallet '{}' contains multiple accounts, which are no longer supported since Electrum 2.7.\n\n" "The wallet '{}' contains multiple accounts, which are no longer supported since Electrum 2.7.\n\n"
"Do you want to split your wallet into multiple files?").format(path) "Do you want to split your wallet into multiple files?").format(root_path)
if not self.question(msg): if self.question(msg):
return file_list = WalletDB.split_accounts(root_path, split_data)
file_list = db.split_accounts(path)
msg = _('Your accounts have been moved to') + ':\n' + '\n'.join(file_list) + '\n\n' + _( msg = _('Your accounts have been moved to') + ':\n' + '\n'.join(file_list) + '\n\n' + _(
'Do you want to delete the old file') + ':\n' + path 'Do you want to delete the old file') + ':\n' + root_path
if self.question(msg): if self.question(msg):
os.remove(path) os.remove(root_path)
self.show_warning(_('The file was removed')) self.show_warning(_('The file was removed'))
# raise now, to avoid having the old storage opened # raise now, to avoid having the old storage opened
raise UserCancelled() raise UserCancelled()
if db.requires_upgrade():
self.waiting_dialog(db.upgrade, _('Upgrading wallet format...'))
def is_finalized(self, wizard_data: dict) -> bool: def is_finalized(self, wizard_data: dict) -> bool:
# check decryption of existing wallet and keep wizard open if incorrect. # check decryption of existing wallet and keep wizard open if incorrect.

30
electrum/json_db.py

@ -34,8 +34,6 @@ from .logging import Logger
if TYPE_CHECKING: if TYPE_CHECKING:
from .storage import WalletStorage from .storage import WalletStorage
JsonDBJsonEncoder = util.MyEncoder
def modifier(func): def modifier(func):
def wrapper(self, *args, **kwargs): def wrapper(self, *args, **kwargs):
with self.lock: with self.lock:
@ -168,24 +166,28 @@ class StoredDict(dict):
class JsonDB(Logger): class JsonDB(Logger):
def __init__(self, data, storage=None): def __init__(self, s: str, storage=None, encoder=None):
Logger.__init__(self) Logger.__init__(self)
self.lock = threading.RLock() self.lock = threading.RLock()
self.storage = storage self.storage = storage
self.encoder = encoder
self._modified = False self._modified = False
# load data # load data
if data: data = self.load_data(s)
self.load_data(data) # convert to StoredDict
else: self.data = StoredDict(data, self, [])
self.data = {}
def load_data(self, s:str) -> dict:
def load_data(self, s): """ overloaded in wallet_db """
if s == '':
return {}
try: try:
self.data = json.loads(s) data = json.loads(s)
except Exception: except Exception:
raise WalletFileException("Cannot read wallet file. (parsing failed)") raise WalletFileException("Cannot read wallet file. (parsing failed)")
if not isinstance(self.data, dict): if not isinstance(data, dict):
raise WalletFileException("Malformed wallet file (not dict)") raise WalletFileException("Malformed wallet file (not dict)")
return data
def set_modified(self, b): def set_modified(self, b):
with self.lock: with self.lock:
@ -204,8 +206,8 @@ class JsonDB(Logger):
@modifier @modifier
def put(self, key, value): def put(self, key, value):
try: try:
json.dumps(key, cls=JsonDBJsonEncoder) json.dumps(key, cls=self.encoder)
json.dumps(value, cls=JsonDBJsonEncoder) json.dumps(value, cls=self.encoder)
except Exception: except Exception:
self.logger.info(f"json error: cannot save {repr(key)} ({repr(value)})") self.logger.info(f"json error: cannot save {repr(key)} ({repr(value)})")
return False return False
@ -235,7 +237,7 @@ class JsonDB(Logger):
self.data, self.data,
indent=4 if human_readable else None, indent=4 if human_readable else None,
sort_keys=bool(human_readable), sort_keys=bool(human_readable),
cls=JsonDBJsonEncoder, cls=self.encoder,
) )
def _should_convert_to_stored_dict(self, key) -> bool: def _should_convert_to_stored_dict(self, key) -> bool:

2
electrum/lnwatcher.py

@ -325,7 +325,7 @@ class WatchTower(LNWatcher):
LOGGING_SHORTCUT = 'W' LOGGING_SHORTCUT = 'W'
def __init__(self, network: 'Network'): def __init__(self, network: 'Network'):
adb = AddressSynchronizer(WalletDB({}, storage=None, 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) adb.start_network(network)
LNWatcher.__init__(self, adb, network) LNWatcher.__init__(self, adb, network)
self.network = network self.network = network

29
electrum/tests/test_storage_upgrade.py

@ -7,7 +7,7 @@ import asyncio
import inspect import inspect
import electrum import electrum
from electrum.wallet_db import WalletDB from electrum.wallet_db import WalletDBUpgrader, WalletDB, WalletRequiresUpgrade, WalletRequiresSplit
from electrum.wallet import Wallet from electrum.wallet import Wallet
from electrum import constants from electrum import constants
from electrum import util from electrum import util
@ -331,22 +331,23 @@ class TestStorageUpgrade(WalletTestCase):
async def _upgrade_storage(self, wallet_json, accounts=1) -> Optional[WalletDB]: async def _upgrade_storage(self, wallet_json, accounts=1) -> Optional[WalletDB]:
if accounts == 1: if accounts == 1:
# test manual upgrades # test manual upgrades
db = self._load_db_from_json_string(wallet_json=wallet_json, try:
db = self._load_db_from_json_string(
wallet_json=wallet_json,
manual_upgrades=True) manual_upgrades=True)
self.assertFalse(db.requires_split()) except WalletRequiresUpgrade:
if db.requires_upgrade(): db = self._load_db_from_json_string(
db.upgrade() wallet_json=wallet_json,
await self._sanity_check_upgraded_db(db)
# test automatic upgrades
db2 = self._load_db_from_json_string(wallet_json=wallet_json,
manual_upgrades=False) manual_upgrades=False)
await self._sanity_check_upgraded_db(db2) await self._sanity_check_upgraded_db(db)
return db2 return db
else: else:
db = self._load_db_from_json_string(wallet_json=wallet_json, try:
db = self._load_db_from_json_string(
wallet_json=wallet_json,
manual_upgrades=True) manual_upgrades=True)
self.assertTrue(db.requires_split()) except WalletRequiresSplit as e:
split_data = db.get_split_accounts() split_data = e._split_data
self.assertEqual(accounts, len(split_data)) self.assertEqual(accounts, len(split_data))
for item in split_data: for item in split_data:
data = json.dumps(item) data = json.dumps(item)
@ -354,8 +355,6 @@ class TestStorageUpgrade(WalletTestCase):
await self._sanity_check_upgraded_db(new_db) await self._sanity_check_upgraded_db(new_db)
async def _sanity_check_upgraded_db(self, db): async def _sanity_check_upgraded_db(self, db):
self.assertFalse(db.requires_split())
self.assertFalse(db.requires_upgrade())
wallet = Wallet(db, config=self.config) wallet = Wallet(db, config=self.config)
await wallet.stop() await wallet.stop()

8
electrum/tests/test_wallet.py

@ -15,7 +15,7 @@ from electrum.wallet import (Abstract_Wallet, Standard_Wallet, create_new_wallet
from electrum.exchange_rate import ExchangeBase, FxThread from electrum.exchange_rate import ExchangeBase, FxThread
from electrum.util import TxMinedInfo, InvalidPassword from electrum.util import TxMinedInfo, InvalidPassword
from electrum.bitcoin import COIN from electrum.bitcoin import COIN
from electrum.wallet_db import WalletDB from electrum.wallet_db import WalletDB, JsonDB
from electrum.simple_config import SimpleConfig from electrum.simple_config import SimpleConfig
from electrum import util from electrum import util
@ -60,14 +60,14 @@ class TestWalletStorage(WalletTestCase):
contents = f.write(contents) contents = f.write(contents)
storage = WalletStorage(self.wallet_path) storage = WalletStorage(self.wallet_path)
db = WalletDB(storage.read(), storage=storage, manual_upgrades=True) db = JsonDB(storage.read(), storage=storage)
self.assertEqual("b", db.get("a")) self.assertEqual("b", db.get("a"))
self.assertEqual("d", db.get("c")) self.assertEqual("d", db.get("c"))
def test_write_dictionary_to_file(self): def test_write_dictionary_to_file(self):
storage = WalletStorage(self.wallet_path) storage = WalletStorage(self.wallet_path)
db = WalletDB('', storage=storage, manual_upgrades=True) db = JsonDB('', storage=storage)
some_dict = { some_dict = {
u"a": u"b", u"a": u"b",
@ -110,7 +110,7 @@ class FakeWallet:
def __init__(self, fiat_value): def __init__(self, fiat_value):
super().__init__() super().__init__()
self.fiat_value = fiat_value self.fiat_value = fiat_value
self.db = WalletDB("{}", storage=None, manual_upgrades=True) self.db = WalletDB('', storage=None, manual_upgrades=True)
self.adb = FakeADB() self.adb = FakeADB()
self.db.transactions = self.db.verified_tx = {'abc':'Tx'} self.db.transactions = self.db.verified_tx = {'abc':'Tx'}

4
electrum/wallet.py

@ -309,8 +309,8 @@ class Abstract_Wallet(ABC, Logger, EventListener):
def __init__(self, db: WalletDB, *, config: SimpleConfig): def __init__(self, db: WalletDB, *, config: SimpleConfig):
if not db.is_ready_to_be_used_by_wallet(): #if not db.is_ready_to_be_used_by_wallet():
raise Exception("storage not ready to be used by Abstract_Wallet") # raise Exception("storage not ready to be used by Abstract_Wallet")
self.config = config self.config = config
assert self.config is not None, "config must not be None" assert self.config is not None, "config must not be None"

143
electrum/wallet_db.py

@ -36,7 +36,7 @@ import time
import attr import attr
from . import util, bitcoin from . import util, bitcoin
from .util import profiler, WalletFileException, multisig_type, TxMinedInfo, bfh from .util import profiler, WalletFileException, multisig_type, TxMinedInfo, bfh, MyEncoder
from .invoices import Invoice, Request from .invoices import Invoice, Request
from .keystore import bip44_derivation from .keystore import bip44_derivation
from .transaction import Transaction, TxOutpoint, tx_from_any, PartialTransaction, PartialTxOutput from .transaction import Transaction, TxOutpoint, tx_from_any, PartialTransaction, PartialTxOutput
@ -49,6 +49,11 @@ from .plugin import run_hook, plugin_loaders
from .version import ELECTRUM_VERSION from .version import ELECTRUM_VERSION
class WalletRequiresUpgrade(WalletFileException):
pass
class WalletRequiresSplit(WalletFileException):
def __init__(self, split_data):
self._split_data = split_data
# seed_version is now used for the version of the wallet file # seed_version is now used for the version of the wallet file
@ -100,46 +105,21 @@ for key in ['locked_in', 'fails', 'settles']:
json_db.register_parent_key(key, lambda x: HTLCOwner(int(x))) json_db.register_parent_key(key, lambda x: HTLCOwner(int(x)))
class WalletDB(JsonDB):
def __init__(self, data, *, storage=None, manual_upgrades: bool): class WalletDBUpgrader(Logger):
JsonDB.__init__(self, data, storage)
if not data:
# create new DB
self.put('seed_version', FINAL_SEED_VERSION)
self._add_db_creation_metadata()
self._after_upgrade_tasks()
self._manual_upgrades = manual_upgrades
self._called_after_upgrade_tasks = False
if not self._manual_upgrades and self.requires_split():
raise WalletFileException("This wallet has multiple accounts and must be split")
if not self.requires_upgrade():
self._after_upgrade_tasks()
elif not self._manual_upgrades:
self.upgrade()
# load plugins that are conditional on wallet type
self.load_plugins()
def load_data(self, s): def __init__(self, data):
try: Logger.__init__(self)
JsonDB.load_data(self, s) self.data = data
except Exception:
try: def get(self, key, default=None):
d = ast.literal_eval(s) return self.data.get(key, default)
labels = d.get('labels', {})
except Exception as e: def put(self, key, value):
raise WalletFileException("Cannot read wallet file. (parsing failed)") if value is not None:
self.data = {}
for key, value in d.items():
try:
json.dumps(key)
json.dumps(value)
except Exception:
self.logger.info(f'Failed to convert label to json format: {key}')
continue
self.data[key] = value self.data[key] = value
if not isinstance(self.data, dict): else:
raise WalletFileException("Malformed wallet file (not dict)") self.data.pop(key, None)
def requires_split(self): def requires_split(self):
d = self.get('accounts', {}) d = self.get('accounts', {})
@ -192,9 +172,6 @@ class WalletDB(JsonDB):
@profiler @profiler
def upgrade(self): def upgrade(self):
self.logger.info('upgrading wallet format') self.logger.info('upgrading wallet format')
if self._called_after_upgrade_tasks:
# we need strict ordering between upgrade() and after_upgrade_tasks()
raise Exception("'after_upgrade_tasks' must NOT be called before 'upgrade'")
self._convert_imported() self._convert_imported()
self._convert_wallet_type() self._convert_wallet_type()
self._convert_account() self._convert_account()
@ -242,12 +219,6 @@ class WalletDB(JsonDB):
self._convert_version_54() self._convert_version_54()
self.put('seed_version', FINAL_SEED_VERSION) # just to be sure self.put('seed_version', FINAL_SEED_VERSION) # just to be sure
self._after_upgrade_tasks()
def _after_upgrade_tasks(self):
self._called_after_upgrade_tasks = True
self._load_transactions()
def _convert_wallet_type(self): def _convert_wallet_type(self):
if not self._is_upgrade_method_needed(0, 13): if not self._is_upgrade_method_needed(0, 13):
return return
@ -1140,7 +1111,6 @@ class WalletDB(JsonDB):
else: else:
return True return True
@locked
def get_seed_version(self): def get_seed_version(self):
seed_version = self.get('seed_version') seed_version = self.get('seed_version')
if not seed_version: if not seed_version:
@ -1191,14 +1161,62 @@ class WalletDB(JsonDB):
# generic exception # generic exception
raise WalletFileException(msg) raise WalletFileException(msg)
def _add_db_creation_metadata(self):
class WalletDB(JsonDB):
def __init__(self, s, *, storage=None, manual_upgrades=True):
self._upgrade = not manual_upgrades
JsonDB.__init__(self, s, storage, encoder=MyEncoder)
# create pointers
self.load_transactions()
# load plugins that are conditional on wallet type
self.load_plugins()
def load_data(self, s):
try:
data = JsonDB.load_data(self, s)
except Exception:
try:
d = ast.literal_eval(s)
labels = d.get('labels', {})
except Exception as e:
raise WalletFileException("Cannot read wallet file. (parsing failed)")
data = {}
for key, value in d.items():
try:
json.dumps(key)
json.dumps(value)
except Exception:
self.logger.info(f'Failed to convert label to json format: {key}')
continue
data[key] = value
if not isinstance(data, dict):
raise WalletFileException("Malformed wallet file (not dict)")
if len(data) == 0:
# create new DB
data['seed_version'] = FINAL_SEED_VERSION
# store this for debugging purposes # store this for debugging purposes
v = DBMetadata( v = DBMetadata(
creation_timestamp=int(time.time()), creation_timestamp=int(time.time()),
first_electrum_version_used=ELECTRUM_VERSION, first_electrum_version_used=ELECTRUM_VERSION,
) )
assert self.get("db_metadata", None) is None assert data.get("db_metadata", None) is None
self.put("db_metadata", v) data["db_metadata"] = v
dbu = WalletDBUpgrader(data)
if dbu.requires_split():
raise WalletRequiresSplit(dbu.get_split_accounts())
if self._upgrade:
dbu.upgrade()
if dbu.requires_upgrade():
raise WalletRequiresUpgrade()
return dbu.data
@locked
def get_seed_version(self):
return self.get('seed_version')
def get_db_metadata(self) -> Optional[DBMetadata]: def get_db_metadata(self) -> Optional[DBMetadata]:
# field only present for wallet files created with ver 4.4.0 or later # field only present for wallet files created with ver 4.4.0 or later
@ -1560,8 +1578,7 @@ class WalletDB(JsonDB):
self._addr_to_addr_index[addr] = (1, i) self._addr_to_addr_index[addr] = (1, i)
@profiler @profiler
def _load_transactions(self): def load_transactions(self):
self.data = StoredDict(self.data, self, [])
# references in self.data # references in self.data
# TODO make all these private # TODO make all these private
# txid -> address -> prev_outpoint -> value # txid -> address -> prev_outpoint -> value
@ -1608,21 +1625,19 @@ class WalletDB(JsonDB):
return True return True
def is_ready_to_be_used_by_wallet(self): def is_ready_to_be_used_by_wallet(self):
return not self.requires_upgrade() and self._called_after_upgrade_tasks return not self._requires_upgrade
def split_accounts(self, root_path): @classmethod
def split_accounts(klass, root_path, split_data):
from .storage import WalletStorage from .storage import WalletStorage
out = [] file_list = []
result = self.get_split_accounts() for data in split_data:
for data in result:
path = root_path + '.' + data['suffix'] path = root_path + '.' + data['suffix']
storage = WalletStorage(path) item_storage = WalletStorage(path)
db = WalletDB(json.dumps(data), storage=storage, manual_upgrades=False) db = WalletDB(json.dumps(data), storage=item_storage, manual_upgrades=False)
db._called_after_upgrade_tasks = False
db.upgrade()
db.write() db.write()
out.append(path) file_list.append(path)
return out return file_list
def get_action(self): def get_action(self):
action = run_hook('get_action', self) action = run_hook('get_action', self)

Loading…
Cancel
Save