Example #1
0
 def _start_wizard_to_select_or_create_wallet(self, path) -> Optional[Abstract_Wallet]:
     wizard = InstallWizard(self.config, self.app, self.plugins, gui_object=self)
     try:
         path, storage = wizard.select_storage(path, self.daemon.get_wallet)
         # storage is None if file does not exist
         if storage is None:
             wizard.path = path  # needed by trustedcoin plugin
             wizard.run('new')
             storage, db = wizard.create_storage(path)
         else:
             db = WalletDB(storage.read(), manual_upgrades=False)
             wizard.run_upgrades(storage, db)
     except (UserCancelled, GoBack):
         return
     except WalletAlreadyOpenInMemory as e:
         return e.wallet
     finally:
         wizard.terminate()
     # return if wallet creation is not complete
     if storage is None or db.get_action():
         return
     wallet = Wallet(db, storage, config=self.config)
     wallet.start_network(self.daemon.network)
     self.daemon.add_wallet(wallet)
     return wallet
    def test_read_dictionary_from_file(self):

        some_dict = {"a": "b", "c": "d"}
        contents = json.dumps(some_dict)
        with open(self.wallet_path, "w") as f:
            contents = f.write(contents)

        storage = WalletStorage(self.wallet_path)
        db = WalletDB(storage.read(), manual_upgrades=True)
        self.assertEqual("b", db.get("a"))
        self.assertEqual("d", db.get("c"))
 def init_storage_from_path(self, path):
     self.storage = WalletStorage(path)
     self.basename = self.storage.basename()
     if not self.storage.file_exists():
         self.require_password = False
         self.message = _('Press Next to create')
     elif self.storage.is_encrypted():
         if not self.storage.is_encrypted_with_user_pw():
             raise Exception(
                 "Kivy GUI does not support this type of encrypted wallet files."
             )
         self.pw_check = self.storage.check_password
         if self.app.password and self.check_password(self.app.password):
             self.pw = self.app.password  # must be set so that it is returned in callback
             self.require_password = False
             self.message = _('Press Next to open')
         else:
             self.require_password = True
             self.message = self.enter_pw_message
     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)
         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')
Example #4
0
    def __init__(self, *, config: 'SimpleConfig', daemon: 'Daemon',
                 plugins: 'Plugins'):
        BaseElectrumGui.__init__(self,
                                 config=config,
                                 daemon=daemon,
                                 plugins=plugins)
        self.network = daemon.network
        storage = WalletStorage(config.get_wallet_path())
        if not storage.file_exists():
            print("Wallet not found. try 'electrum create'")
            exit()
        if storage.is_encrypted():
            password = getpass.getpass('Password:'******'')
        self.encoding = locale.getpreferredencoding()

        self.stdscr = curses.initscr()
        curses.noecho()
        curses.cbreak()
        curses.start_color()
        curses.use_default_colors()
        curses.init_pair(1, curses.COLOR_WHITE, curses.COLOR_BLUE)
        curses.init_pair(2, curses.COLOR_WHITE, curses.COLOR_CYAN)
        curses.init_pair(3, curses.COLOR_BLACK, curses.COLOR_WHITE)
        self.stdscr.keypad(1)
        self.stdscr.border(0)
        self.maxy, self.maxx = self.stdscr.getmaxyx()
        self.set_cursor(0)
        self.w = curses.newwin(10, 50, 5, 5)

        self.tab = 0
        self.pos = 0
        self.popup_pos = 0

        self.str_recipient = ""
        self.str_description = ""
        self.str_amount = ""
        self.str_fee = ""
        self.history = None
        self.txid = []

        self.register_callbacks()

        self.tab_names = [
            _("History"),
            _("Send"),
            _("Receive"),
            _("Addresses"),
            _("Contacts"),
            _("Banner")
        ]
        self.num_tabs = len(self.tab_names)
Example #5
0
    def load_db(self):
        # needs storage accessible
        self._db = WalletDB(self._storage.read(), manual_upgrades=True)
        if self._db.requires_split():
            self._logger.warning('wallet requires split')
            self._requiresSplit = True
            self.requiresSplitChanged.emit()
            return
        if self._db.get_action():
            self._logger.warning(
                'action pending. QML version doesn\'t support continuation of wizard'
            )
            return

        if self._db.requires_upgrade():
            self._logger.warning('wallet requires upgrade, upgrading')
            self._db.upgrade()
            self._db.write(self._storage)

        self._ready = True
        self.readyChanged.emit()
Example #6
0
    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)
        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)

        wallet.check_password(None)

        wallet.update_password(None, "1234")
        with self.assertRaises(InvalidPassword):
            wallet.check_password(None)
        with self.assertRaises(InvalidPassword):
            wallet.check_password("wrong password")
        wallet.check_password("1234")
Example #7
0
    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)

        wallet.check_password(None)

        wallet.update_password(None, "1234")
        with self.assertRaises(InvalidPassword):
            wallet.check_password(None)
        with self.assertRaises(InvalidPassword):
            wallet.check_password("wrong password")
        wallet.check_password("1234")
Example #8
0
def make_address_electrum(mnemonic: str,
                          second: str,
                          num: int = 0,
                          script: str = 'p2wpkh',
                          path: str = 'wallet.db',
                          remove: bool = True):
    if electrum is None:
        raise ImportError(
            'Unable to import electrum.  Follow README instructions.')

    if len(second) < MIN_LEN_PASSWORD:
        raise ValueError(
            f'Password too short {len(second)} < {MIN_LEN_PASSWORD}')
    script_types = ('p2pkh', 'p2wpkh', 'p2wpkh-p2sh')
    if script not in script_types:
        raise ValueError(f'Script {script} must be noe of {script_types}')

    if os.path.exists(path):
        os.unlink(path)

    language = 'english'
    seed = Mnemonic(language).to_seed(mnemonic).hex()

    derivation = None
    if script == 'p2wpkh':
        derivation = "m/84'/0'/0'"
    elif script == 'p2wpkh-p2sh':
        derivation = "m/49'/0'/0'"
    elif script == 'p2pkh':
        script = 'standard'
        derivation = "m/44'/0'/0'"

    ks = keystore.from_bip39_seed(mnemonic, second, derivation, xtype=script)

    db = WalletDB('', manual_upgrades=False)
    db.put('keystore', ks.dump())
    db.put('wallet_type', 'standard')

    storage = WalletStorage(path)
    wallet = Wallet(db, storage, config=SimpleConfig())
    if not storage.file_exists():
        wallet.update_password(old_pw=None,
                               new_pw=second,
                               encrypt_storage=True)
    wallet.synchronize()
    wallet.save_db()

    addr = wallet.get_receiving_addresses()[num]
    wif = wallet.export_private_key(addr, password=second)

    if remove:
        os.unlink(path)

    return AddressResult(address=addr, wif=wif, num=num)
Example #9
0
    def __init__(self, *, config, daemon, plugins):
        BaseElectrumGui.__init__(self,
                                 config=config,
                                 daemon=daemon,
                                 plugins=plugins)
        self.network = daemon.network
        storage = WalletStorage(config.get_wallet_path())
        if not storage.file_exists():
            print("Wallet not found. try 'electrum create'")
            exit()
        if storage.is_encrypted():
            password = getpass.getpass('Password:', stream=None)
            storage.decrypt(password)

        db = WalletDB(storage.read(), manual_upgrades=False)

        self.done = 0
        self.last_balance = ""

        self.str_recipient = ""
        self.str_description = ""
        self.str_amount = ""
        self.str_fee = ""

        self.wallet = Wallet(db, storage,
                             config=config)  # type: Optional[Abstract_Wallet]
        self.wallet.start_network(self.network)
        self.contacts = self.wallet.contacts

        self.register_callbacks()
        self.commands = [_("[h] - displays this help text"), \
                         _("[i] - display transaction history"), \
                         _("[o] - enter payment order"), \
                         _("[p] - print stored payment order"), \
                         _("[s] - send stored payment order"), \
                         _("[r] - show own receipt addresses"), \
                         _("[c] - display contacts"), \
                         _("[b] - print server banner"), \
                         _("[q] - quit")]
        self.num_commands = len(self.commands)
Example #10
0
    def __init__(self, config, daemon, plugins):
        self.config = config
        self.network = daemon.network
        storage = WalletStorage(config.get_wallet_path())
        if not storage.file_exists:
            print("Wallet not found. try 'electrum-bitg create'")
            exit()
        if storage.is_encrypted():
            password = getpass.getpass('Password:'******'wallet_updated', 'network_updated', 'banner'])
        self.commands = [_("[h] - displays this help text"), \
                         _("[i] - display transaction history"), \
                         _("[o] - enter payment order"), \
                         _("[p] - print stored payment order"), \
                         _("[s] - send stored payment order"), \
                         _("[r] - show own receipt addresses"), \
                         _("[c] - display contacts"), \
                         _("[b] - print server banner"), \
                         _("[q] - quit") ]
        self.num_commands = len(self.commands)
 def _upgrade_storage(self, wallet_json, accounts=1):
     if accounts == 1:
         # test manual upgrades
         db = self._load_db_from_json_string(wallet_json=wallet_json,
                                             manual_upgrades=True)
         self.assertFalse(db.requires_split())
         if db.requires_upgrade():
             db.upgrade()
             self._sanity_check_upgraded_db(db)
         # test automatic upgrades
         db2 = self._load_db_from_json_string(wallet_json=wallet_json,
                                              manual_upgrades=False)
         self._sanity_check_upgraded_db(db2)
     else:
         db = self._load_db_from_json_string(wallet_json=wallet_json,
                                             manual_upgrades=True)
         self.assertTrue(db.requires_split())
         split_data = db.get_split_accounts()
         self.assertEqual(accounts, len(split_data))
         for item in split_data:
             data = json.dumps(item)
             new_db = WalletDB(data, manual_upgrades=False)
             self._sanity_check_upgraded_db(new_db)
Example #12
0
    def test_write_dictionary_to_file(self):

        storage = WalletStorage(self.wallet_path)
        db = WalletDB('', manual_upgrades=True)

        some_dict = {
            u"a": u"b",
            u"c": u"d",
            u"seed_version": FINAL_SEED_VERSION}

        for key, value in some_dict.items():
            db.put(key, value)
        db.write(storage)

        with open(self.wallet_path, "r") as f:
            contents = f.read()
        d = json.loads(contents)
        for key, value in some_dict.items():
            self.assertEqual(d[key], value)
 def __init__(self, fiat_value):
     super().__init__()
     self.fiat_value = fiat_value
     self.db = WalletDB("{}", manual_upgrades=True)
     self.db.transactions = self.db.verified_tx = {'abc': 'Tx'}
 def _load_db_from_json_string(*, wallet_json, manual_upgrades):
     db = WalletDB(wallet_json, manual_upgrades=manual_upgrades)
     return db
Example #15
0
                print(
                    f"> tested {num_tested} passwords so far... most recently tried: {password!r}"
                )


if __name__ == '__main__':
    if len(sys.argv) < 2:
        print("ERROR. usage: bruteforce_pw.py <path_to_wallet_file>")
        sys.exit(1)
    path = sys.argv[1]

    config = SimpleConfig()
    storage = WalletStorage(path)
    if not storage.file_exists():
        print(f"ERROR. wallet file not found at path: {path}")
        sys.exit(1)
    if storage.is_encrypted():
        test_password = partial(test_password_for_storage_encryption, storage)
        print(f"wallet found: with storage encryption.")
    else:
        db = WalletDB(storage.read(), manual_upgrades=True)
        wallet = Wallet(db, storage, config=config)
        if not wallet.has_password():
            print("wallet found but it is not encrypted.")
            sys.exit(0)
        test_password = partial(test_password_for_keystore_encryption, wallet)
        print(f"wallet found: with keystore encryption.")
    password = bruteforce_loop(test_password)
    print(f"====================")
    print(f"password found: {password}")
Example #16
0
    def create_storage(self, js_data, single_password_enabled,
                       single_password):
        self._logger.info('Creating wallet from wizard data')
        data = js_data.toVariant()
        self._logger.debug(str(data))

        if single_password_enabled and single_password:
            data['encrypt'] = True
            data['password'] = single_password

        try:
            path = os.path.join(
                os.path.dirname(self.daemon.config.get_wallet_path()),
                data['wallet_name'])
            if os.path.exists(path):
                raise Exception('file already exists at path')
            storage = WalletStorage(path)

            if data['seed_type'] in ['old', 'standard',
                                     'segwit']:  #2fa, 2fa-segwit
                self._logger.debug('creating keystore from electrum seed')
                k = keystore.from_seed(data['seed'], data['seed_extra_words'],
                                       data['wallet_type'] == 'multisig')
            elif data['seed_type'] == 'bip39':
                self._logger.debug('creating keystore from bip39 seed')
                root_seed = keystore.bip39_to_seed(data['seed'],
                                                   data['seed_extra_words'])
                derivation = normalize_bip32_derivation(
                    data['derivation_path'])
                script = data['script_type'] if data[
                    'script_type'] != 'p2pkh' else 'standard'
                k = keystore.from_bip43_rootseed(root_seed,
                                                 derivation,
                                                 xtype=script)
            else:
                raise Exception('unsupported/unknown seed_type %s' %
                                data['seed_type'])

            if data['encrypt']:
                if k.may_have_password():
                    k.update_password(None, data['password'])
                storage.set_password(
                    data['password'],
                    enc_version=StorageEncryptionVersion.USER_PASSWORD)

            db = WalletDB('', manual_upgrades=False)
            db.set_keystore_encryption(
                bool(data['password']) and data['encrypt'])

            db.put('wallet_type', data['wallet_type'])
            db.put('seed_type', data['seed_type'])
            db.put('keystore', k.dump())
            if k.can_have_deterministic_lightning_xprv():
                db.put(
                    'lightning_xprv',
                    k.get_lightning_xprv(
                        data['password'] if data['encrypt'] else None))

            db.load_plugins()
            db.write(storage)

            # minimally populate self after create
            self._password = data['password']
            self.path = path

            self.createSuccess.emit()
        except Exception as e:
            self._logger.error(str(e))
            self.createError.emit(str(e))
Example #17
0
class QEWalletDB(QObject):
    def __init__(self, parent=None):
        super().__init__(parent)

        from .qeapp import ElectrumQmlApplication
        self.daemon = ElectrumQmlApplication._daemon

        self.reset()

    _logger = get_logger(__name__)

    fileNotFound = pyqtSignal()
    pathChanged = pyqtSignal([bool], arguments=["ready"])
    needsPasswordChanged = pyqtSignal()
    needsHWDeviceChanged = pyqtSignal()
    passwordChanged = pyqtSignal()
    validPasswordChanged = pyqtSignal()
    requiresSplitChanged = pyqtSignal()
    splitFinished = pyqtSignal()
    readyChanged = pyqtSignal()
    createError = pyqtSignal([str], arguments=["error"])
    createSuccess = pyqtSignal()
    invalidPassword = pyqtSignal()

    def reset(self):
        self._path = None
        self._needsPassword = False
        self._needsHWDevice = False
        self._password = ''
        self._requiresSplit = False
        self._validPassword = True

        self._storage = None
        self._db = None

        self._ready = False

    @pyqtProperty('QString', notify=pathChanged)
    def path(self):
        return self._path

    @path.setter
    def path(self, wallet_path):
        if wallet_path == self._path:
            return

        self._logger.info('setting path: ' + wallet_path)
        self.reset()
        self._path = wallet_path

        self.pathChanged.emit(self._ready)

    @pyqtProperty(bool, notify=needsPasswordChanged)
    def needsPassword(self):
        return self._needsPassword

    @needsPassword.setter
    def needsPassword(self, wallet_needs_password):
        if wallet_needs_password == self._needsPassword:
            return

        self._needsPassword = wallet_needs_password
        self.needsPasswordChanged.emit()

    @pyqtProperty(bool, notify=needsHWDeviceChanged)
    def needsHWDevice(self):
        return self._needsHWDevice

    @needsHWDevice.setter
    def needsHWDevice(self, wallet_needs_hw_device):
        if wallet_needs_hw_device == self._needsHWDevice:
            return

        self._needsHWDevice = wallet_needs_hw_device
        self.needsHWDeviceChanged.emit()

    @pyqtProperty('QString', notify=passwordChanged)
    def password(self):
        return ''  # no read access

    @password.setter
    def password(self, wallet_password):
        if wallet_password == self._password:
            return

        self._password = wallet_password
        self.passwordChanged.emit()

    @pyqtProperty(bool, notify=requiresSplitChanged)
    def requiresSplit(self):
        return self._requiresSplit

    @pyqtProperty(bool, notify=validPasswordChanged)
    def validPassword(self):
        return self._validPassword

    @validPassword.setter
    def validPassword(self, validPassword):
        if self._validPassword != validPassword:
            self._validPassword = validPassword
            self.validPasswordChanged.emit()

    @pyqtProperty(bool, notify=readyChanged)
    def ready(self):
        return self._ready

    @pyqtSlot()
    def verify(self):
        self.load_storage()
        if self._storage:
            self.load_db()

    @pyqtSlot()
    def doSplit(self):
        self._logger.warning('doSplit')
        if not self._requiresSplit:
            return

        self._db.split_accounts(self._path)

        self.splitFinished.emit()

    def load_storage(self):
        self._storage = WalletStorage(self._path)
        if not self._storage.file_exists():
            self._logger.warning('file does not exist')
            self.fileNotFound.emit()
            self._storage = None
            return

        if self._storage.is_encrypted():
            self.needsPassword = True

            try:
                self._storage.decrypt(
                    '' if not self._password else self._password)
                self.validPassword = True
            except InvalidPassword as e:
                self.validPassword = False
                self.invalidPassword.emit()

        if not self._storage.is_past_initial_decryption():
            self._storage = None

    def load_db(self):
        # needs storage accessible
        self._db = WalletDB(self._storage.read(), manual_upgrades=True)
        if self._db.requires_split():
            self._logger.warning('wallet requires split')
            self._requiresSplit = True
            self.requiresSplitChanged.emit()
            return
        if self._db.get_action():
            self._logger.warning(
                'action pending. QML version doesn\'t support continuation of wizard'
            )
            return

        if self._db.requires_upgrade():
            self._logger.warning('wallet requires upgrade, upgrading')
            self._db.upgrade()
            self._db.write(self._storage)

        self._ready = True
        self.readyChanged.emit()

    @pyqtSlot('QJSValue', bool, str)
    def create_storage(self, js_data, single_password_enabled,
                       single_password):
        self._logger.info('Creating wallet from wizard data')
        data = js_data.toVariant()
        self._logger.debug(str(data))

        if single_password_enabled and single_password:
            data['encrypt'] = True
            data['password'] = single_password

        try:
            path = os.path.join(
                os.path.dirname(self.daemon.config.get_wallet_path()),
                data['wallet_name'])
            if os.path.exists(path):
                raise Exception('file already exists at path')
            storage = WalletStorage(path)

            if data['seed_type'] in ['old', 'standard',
                                     'segwit']:  #2fa, 2fa-segwit
                self._logger.debug('creating keystore from electrum seed')
                k = keystore.from_seed(data['seed'], data['seed_extra_words'],
                                       data['wallet_type'] == 'multisig')
            elif data['seed_type'] == 'bip39':
                self._logger.debug('creating keystore from bip39 seed')
                root_seed = keystore.bip39_to_seed(data['seed'],
                                                   data['seed_extra_words'])
                derivation = normalize_bip32_derivation(
                    data['derivation_path'])
                script = data['script_type'] if data[
                    'script_type'] != 'p2pkh' else 'standard'
                k = keystore.from_bip43_rootseed(root_seed,
                                                 derivation,
                                                 xtype=script)
            else:
                raise Exception('unsupported/unknown seed_type %s' %
                                data['seed_type'])

            if data['encrypt']:
                if k.may_have_password():
                    k.update_password(None, data['password'])
                storage.set_password(
                    data['password'],
                    enc_version=StorageEncryptionVersion.USER_PASSWORD)

            db = WalletDB('', manual_upgrades=False)
            db.set_keystore_encryption(
                bool(data['password']) and data['encrypt'])

            db.put('wallet_type', data['wallet_type'])
            db.put('seed_type', data['seed_type'])
            db.put('keystore', k.dump())
            if k.can_have_deterministic_lightning_xprv():
                db.put(
                    'lightning_xprv',
                    k.get_lightning_xprv(
                        data['password'] if data['encrypt'] else None))

            db.load_plugins()
            db.write(storage)

            # minimally populate self after create
            self._password = data['password']
            self.path = path

            self.createSuccess.emit()
        except Exception as e:
            self._logger.error(str(e))
            self.createError.emit(str(e))