Browse Source

update wallet format again, for keystore

283
ThomasV 9 years ago
parent
commit
afe39330dc
  1. 16
      lib/base_wizard.py
  2. 165
      lib/keystore.py
  3. 8
      lib/plugins.py
  4. 67
      lib/storage.py
  5. 42
      lib/wallet.py
  6. 5
      plugins/trezor/plugin.py
  7. 17
      plugins/trezor/qt_generic.py

16
lib/base_wizard.py

@ -148,7 +148,6 @@ class BaseWizard(object):
self.restore_keys_dialog(title=title, message=message, run_next=self.on_restore, is_valid=v) self.restore_keys_dialog(title=title, message=message, run_next=self.on_restore, is_valid=v)
def choose_hw(self): def choose_hw(self):
self.storage.put('key_type', 'hardware')
hw_wallet_types, choices = self.plugins.hardware_wallets('create') hw_wallet_types, choices = self.plugins.hardware_wallets('create')
choices = zip(hw_wallet_types, choices) choices = zip(hw_wallet_types, choices)
title = _('Hardware Keystore') title = _('Hardware Keystore')
@ -162,7 +161,7 @@ class BaseWizard(object):
self.choice_dialog(title=title, message=msg, choices=choices, run_next=self.on_hardware) self.choice_dialog(title=title, message=msg, choices=choices, run_next=self.on_hardware)
def on_hardware(self, hw_type): def on_hardware(self, hw_type):
self.storage.put('hardware_type', hw_type) self.hw_type = hw_type
title = _('Hardware wallet') + ' [%s]' % hw_type title = _('Hardware wallet') + ' [%s]' % hw_type
message = _('Do you have a device, or do you want to restore a wallet using an existing seed?') message = _('Do you have a device, or do you want to restore a wallet using an existing seed?')
choices = [ choices = [
@ -178,10 +177,9 @@ class BaseWizard(object):
def on_hardware_account_id(self, account_id): def on_hardware_account_id(self, account_id):
from keystore import load_keystore, bip44_derivation from keystore import load_keystore, bip44_derivation
derivation = bip44_derivation(int(account_id)) derivation = bip44_derivation(int(account_id))
self.storage.put('derivation', derivation) plugin = self.plugins.get_plugin(self.hw_type)
name = self.storage.get('hardware_type') k = plugin.create_keystore(self.hw_type, derivation, self)
plugin = self.plugins.get_plugin(name) self.create_wallet(k, None)
plugin.on_create_wallet(self.storage, self)
def on_hardware_seed(self): def on_hardware_seed(self):
self.storage.put('key_type', 'hw_seed') self.storage.put('key_type', 'hw_seed')
@ -209,13 +207,13 @@ class BaseWizard(object):
derivation = "m/44'/0'/%d'"%account_id derivation = "m/44'/0'/%d'"%account_id
self.storage.put('account_id', account_id) self.storage.put('account_id', account_id)
k.add_xprv_from_seed(bip32_seed, derivation, password) k.add_xprv_from_seed(bip32_seed, derivation, password)
k.save(self.storage, 'x/') self.storage.put('keystore', k.dump())
self.wallet = Standard_Wallet(self.storage) self.wallet = Standard_Wallet(self.storage)
self.run('create_addresses') self.run('create_addresses')
def create_wallet(self, k, password): def create_wallet(self, k, password):
if self.wallet_type == 'standard': if self.wallet_type == 'standard':
k.save(self.storage, 'x/') self.storage.put('keystore', k.dump())
self.wallet = Standard_Wallet(self.storage) self.wallet = Standard_Wallet(self.storage)
self.run('create_addresses') self.run('create_addresses')
elif self.wallet_type == 'multisig': elif self.wallet_type == 'multisig':
@ -232,7 +230,7 @@ class BaseWizard(object):
d = self.storage.get('master_public_keys', {}) d = self.storage.get('master_public_keys', {})
if keystore.xpub in d.values(): if keystore.xpub in d.values():
raise BaseException('duplicate key') raise BaseException('duplicate key')
keystore.save(self.storage, 'x%d/'%(i+1)) self.storage.put('x%d/'%(i+1), keystore.dump())
def add_cosigners(self, password, i): def add_cosigners(self, password, i):
self.add_cosigner_dialog(run_next=lambda x: self.on_cosigner(x, password, i), index=i, is_valid=keystore.is_xpub) self.add_cosigner_dialog(run_next=lambda x: self.on_cosigner(x, password, i), index=i, is_valid=keystore.is_xpub)

165
lib/keystore.py

@ -43,9 +43,6 @@ class KeyStore(PrintError):
def has_seed(self): def has_seed(self):
return False return False
def has_password(self):
return False
def is_watching_only(self): def is_watching_only(self):
return False return False
@ -57,10 +54,6 @@ class Software_KeyStore(KeyStore):
def __init__(self): def __init__(self):
KeyStore.__init__(self) KeyStore.__init__(self)
self.use_encryption = False
def has_password(self):
return self.use_encryption
def sign_message(self, sequence, message, password): def sign_message(self, sequence, message, password):
sec = self.get_private_key(sequence, password) sec = self.get_private_key(sequence, password)
@ -79,9 +72,11 @@ class Software_KeyStore(KeyStore):
class Imported_KeyStore(Software_KeyStore): class Imported_KeyStore(Software_KeyStore):
# keystore for imported private keys # keystore for imported private keys
def __init__(self): def __init__(self, d):
Software_KeyStore.__init__(self) Software_KeyStore.__init__(self)
self.keypairs = {} self.keypairs = d.get('keypairs', {})
self.receiving_pubkeys = self.keypairs.keys()
self.change_pubkeys = []
def is_deterministic(self): def is_deterministic(self):
return False return False
@ -92,16 +87,11 @@ class Imported_KeyStore(Software_KeyStore):
def get_master_public_key(self): def get_master_public_key(self):
return None return None
def load(self, storage, name): def dump(self):
self.keypairs = storage.get('keypairs', {}) return {
self.use_encryption = storage.get('use_encryption', False) 'type': 'imported',
self.receiving_pubkeys = self.keypairs.keys() 'keypairs': self.keypairs,
self.change_pubkeys = [] }
def save(self, storage, root_name):
storage.put('key_type', 'imported')
storage.put('keypairs', self.keypairs)
storage.put('use_encryption', self.use_encryption)
def can_import(self): def can_import(self):
return True return True
@ -148,25 +138,21 @@ class Imported_KeyStore(Software_KeyStore):
b = pw_decode(v, old_password) b = pw_decode(v, old_password)
c = pw_encode(b, new_password) c = pw_encode(b, new_password)
self.keypairs[k] = b self.keypairs[k] = b
self.use_encryption = (new_password is not None)
class Deterministic_KeyStore(Software_KeyStore): class Deterministic_KeyStore(Software_KeyStore):
def __init__(self): def __init__(self, d):
Software_KeyStore.__init__(self) Software_KeyStore.__init__(self)
self.seed = '' self.seed = d.get('seed', '')
def is_deterministic(self): def is_deterministic(self):
return True return True
def load(self, storage, name): def dump(self):
self.seed = storage.get('seed', '') return {
self.use_encryption = storage.get('use_encryption', False) 'seed': self.seed,
}
def save(self, storage, name):
storage.put('seed', self.seed)
storage.put('use_encryption', self.use_encryption)
def has_seed(self): def has_seed(self):
return self.seed != '' return self.seed != ''
@ -180,7 +166,6 @@ class Deterministic_KeyStore(Software_KeyStore):
self.seed_version, self.seed = self.format_seed(seed) self.seed_version, self.seed = self.format_seed(seed)
if password: if password:
self.seed = pw_encode(self.seed, password) self.seed = pw_encode(self.seed, password)
self.use_encryption = (password is not None)
def get_seed(self, password): def get_seed(self, password):
return pw_decode(self.seed, password).encode('utf8') return pw_decode(self.seed, password).encode('utf8')
@ -235,27 +220,21 @@ class Xpub:
class BIP32_KeyStore(Deterministic_KeyStore, Xpub): class BIP32_KeyStore(Deterministic_KeyStore, Xpub):
def __init__(self): def __init__(self, d):
Xpub.__init__(self) Xpub.__init__(self)
Deterministic_KeyStore.__init__(self) Deterministic_KeyStore.__init__(self, d)
self.xprv = None self.xpub = d.get('xpub')
self.xprv = d.get('xprv')
def format_seed(self, seed): def format_seed(self, seed):
return NEW_SEED_VERSION, ' '.join(seed.split()) return NEW_SEED_VERSION, ' '.join(seed.split())
def load(self, storage, name): def dump(self):
Deterministic_KeyStore.load(self, storage, name) d = Deterministic_KeyStore.dump(self)
self.xpub = storage.get('master_public_keys', {}).get(name) d['type'] = 'bip32'
self.xprv = storage.get('master_private_keys', {}).get(name) d['xpub'] = self.xpub
d['xprv'] = self.xprv
def save(self, storage, name): return d
Deterministic_KeyStore.save(self, storage, name)
d = storage.get('master_public_keys', {})
d[name] = self.xpub
storage.put('master_public_keys', d)
d = storage.get('master_private_keys', {})
d[name] = self.xprv
storage.put('master_private_keys', d)
def add_master_private_key(self, xprv, password): def add_master_private_key(self, xprv, password):
self.xprv = pw_encode(xprv, password) self.xprv = pw_encode(xprv, password)
@ -279,7 +258,6 @@ class BIP32_KeyStore(Deterministic_KeyStore, Xpub):
if self.xprv is not None: if self.xprv is not None:
b = pw_decode(self.xprv, old_password) b = pw_decode(self.xprv, old_password)
self.xprv = pw_encode(b, new_password) self.xprv = pw_encode(b, new_password)
self.use_encryption = (new_password is not None)
def is_watching_only(self): def is_watching_only(self):
return self.xprv is None return self.xprv is None
@ -340,18 +318,14 @@ class BIP32_KeyStore(Deterministic_KeyStore, Xpub):
class Old_KeyStore(Deterministic_KeyStore): class Old_KeyStore(Deterministic_KeyStore):
def __init__(self): def __init__(self, d):
Deterministic_KeyStore.__init__(self) Deterministic_KeyStore.__init__(self, d)
self.mpk = None self.mpk = d.get('mpk').decode('hex')
def load(self, storage, name):
Deterministic_KeyStore.load(self, storage, name)
self.mpk = storage.get('master_public_key').decode('hex')
def save(self, storage, name): def dump(self):
Deterministic_KeyStore.save(self, storage, name) d = Deterministic_KeyStore.dump(self)
storage.put('wallet_type', 'old') d['mpk'] = self.mpk.encode('hex')
storage.put('master_public_key', self.mpk.encode('hex')) return d
def add_seed(self, seed, password): def add_seed(self, seed, password):
Deterministic_KeyStore.add_seed(self, seed, password) Deterministic_KeyStore.add_seed(self, seed, password)
@ -473,7 +447,6 @@ class Old_KeyStore(Deterministic_KeyStore):
if self.has_seed(): if self.has_seed():
decoded = self.get_seed(old_password) decoded = self.get_seed(old_password)
self.seed = pw_encode(decoded, new_password) self.seed = pw_encode(decoded, new_password)
self.use_encryption = (new_password is not None)
class Hardware_KeyStore(KeyStore, Xpub): class Hardware_KeyStore(KeyStore, Xpub):
@ -485,24 +458,26 @@ class Hardware_KeyStore(KeyStore, Xpub):
#restore_wallet_class = BIP32_RD_Wallet #restore_wallet_class = BIP32_RD_Wallet
max_change_outputs = 1 max_change_outputs = 1
def __init__(self): def __init__(self, d):
Xpub.__init__(self) Xpub.__init__(self)
KeyStore.__init__(self) KeyStore.__init__(self)
# Errors and other user interaction is done through the wallet's # Errors and other user interaction is done through the wallet's
# handler. The handler is per-window and preserved across # handler. The handler is per-window and preserved across
# device reconnects # device reconnects
self.xpub = d.get('xpub')
self.derivation = d.get('derivation')
self.handler = None self.handler = None
def is_deterministic(self): def is_deterministic(self):
return True return True
def load(self, storage, name): def dump(self):
self.xpub = storage.get('master_public_keys', {}).get(name) return {
'type': 'hardware',
def save(self, storage, name): 'hw_type': self.hw_type,
d = storage.get('master_public_keys', {}) 'xpub': self.xpub,
d[name] = self.xpub 'derivation':self.derivation,
storage.put('master_public_keys', d) }
def unpaired(self): def unpaired(self):
'''A device paired with the wallet was diconnected. This can be '''A device paired with the wallet was diconnected. This can be
@ -572,37 +547,37 @@ def xpubkey_to_address(x_pubkey):
return pubkey, address return pubkey, address
keystores = [] hw_keystores = {}
def register_keystore(hw_type, constructor):
hw_keystores[hw_type] = constructor
def hardware_keystore(hw_type, d):
if hw_type in hw_keystores:
constructor = hw_keystores[hw_type]
return constructor(d)
raise BaseException('unknown hardware type', hw_type)
def load_keystore(storage, name): def load_keystore(storage, name):
w = storage.get('wallet_type') w = storage.get('wallet_type', 'standard')
t = storage.get('key_type', 'seed') d = storage.get(name, {})
seed_version = storage.get_seed_version() t = d.get('type')
if seed_version == OLD_SEED_VERSION or w == 'old': if not t:
k = Old_KeyStore() raise BaseException('wallet format requires update')
if t == 'old':
k = Old_KeyStore(d)
elif t == 'imported': elif t == 'imported':
k = Imported_KeyStore() k = Imported_KeyStore(d)
elif name and name not in [ 'x/', 'x1/' ]: elif t == 'bip32':
k = BIP32_KeyStore() k = BIP32_KeyStore(d)
elif t in ['seed', 'hw_seed']:
k = BIP32_KeyStore()
elif t == 'hardware': elif t == 'hardware':
hw_type = storage.get('hardware_type') hw_type = d.get('hw_type')
for cat, _type, constructor in keystores: k = hardware_keystore(hw_type, d)
if cat == 'hardware' and _type == hw_type:
k = constructor()
break
else:
raise BaseException('unknown hardware type')
else: else:
raise BaseException('unknown wallet type', t) raise BaseException('unknown wallet type', t)
k.load(storage, name)
return k return k
def register_keystore(category, type, constructor):
keystores.append((category, type, constructor))
def is_old_mpk(mpk): def is_old_mpk(mpk):
try: try:
@ -649,35 +624,35 @@ def bip44_derivation(account_id):
def from_seed(seed, password): def from_seed(seed, password):
if is_old_seed(seed): if is_old_seed(seed):
keystore = Old_KeyStore() keystore = Old_KeyStore({})
keystore.add_seed(seed, password) keystore.add_seed(seed, password)
elif is_new_seed(seed): elif is_new_seed(seed):
keystore = BIP32_KeyStore() keystore = BIP32_KeyStore({})
keystore.add_seed(seed, password) keystore.add_seed(seed, password)
bip32_seed = Mnemonic.mnemonic_to_seed(seed, '') bip32_seed = Mnemonic.mnemonic_to_seed(seed, '')
keystore.add_xprv_from_seed(bip32_seed, "m/", password) keystore.add_xprv_from_seed(bip32_seed, "m/", password)
return keystore return keystore
def from_private_key_list(text, password): def from_private_key_list(text, password):
keystore = Imported_KeyStore() keystore = Imported_KeyStore({})
for x in text.split(): for x in text.split():
keystore.import_key(x, None) keystore.import_key(x, None)
keystore.update_password(None, password) keystore.update_password(None, password)
return keystore return keystore
def from_old_mpk(mpk): def from_old_mpk(mpk):
keystore = Old_KeyStore() keystore = Old_KeyStore({})
keystore.add_master_public_key(mpk) keystore.add_master_public_key(mpk)
return keystore return keystore
def from_xpub(xpub): def from_xpub(xpub):
keystore = BIP32_KeyStore() keystore = BIP32_KeyStore({})
keystore.add_master_public_key(xpub) keystore.add_master_public_key(xpub)
return keystore return keystore
def from_xprv(xprv, password): def from_xprv(xprv, password):
xpub = bitcoin.xpub_from_xprv(xprv) xpub = bitcoin.xpub_from_xprv(xprv)
keystore = BIP32_KeyStore() keystore = BIP32_KeyStore({})
keystore.add_master_private_key(xprv, password) keystore.add_master_private_key(xprv, password)
keystore.add_master_public_key(xpub) keystore.add_master_public_key(xpub)
return keystore return keystore

8
lib/plugins.py

@ -164,12 +164,12 @@ class Plugins(DaemonThread):
def register_keystore(self, name, gui_good, details): def register_keystore(self, name, gui_good, details):
from keystore import register_keystore from keystore import register_keystore
def dynamic_constructor(): def dynamic_constructor(d):
return self.get_plugin(name).keystore_class() return self.get_plugin(name).keystore_class(d)
if details[0] == 'hardware': if details[0] == 'hardware':
self.hw_wallets[name] = (gui_good, details) self.hw_wallets[name] = (gui_good, details)
self.print_error("registering keystore %s: %s" %(name, details)) self.print_error("registering hardware %s: %s" %(name, details))
register_keystore(details[0], details[1], dynamic_constructor) register_keystore(details[1], dynamic_constructor)
def get_plugin(self, name): def get_plugin(self, name):
if not name in self.plugins: if not name in self.plugins:

67
lib/storage.py

@ -37,6 +37,17 @@ from i18n import _
from util import NotEnoughFunds, PrintError, profiler from util import NotEnoughFunds, PrintError, profiler
from plugins import run_hook, plugin_loaders from plugins import run_hook, plugin_loaders
from keystore import bip44_derivation from keystore import bip44_derivation
from version import OLD_SEED_VERSION
def multisig_type(wallet_type):
'''If wallet_type is mofn multi-sig, return [m, n],
otherwise return None.'''
match = re.match('(\d+)of(\d+)', wallet_type)
if match:
match = [int(x) for x in match.group(1, 2)]
return match
class WalletStorage(PrintError): class WalletStorage(PrintError):
@ -198,8 +209,9 @@ class WalletStorage(PrintError):
def requires_upgrade(self): def requires_upgrade(self):
r = False r = False
r |= self.convert_wallet_type(True) if self.file_exists:
r |= self.convert_imported(True) r |= self.convert_wallet_type(True)
r |= self.convert_imported(True)
return r return r
def upgrade(self): def upgrade(self):
@ -209,17 +221,52 @@ class WalletStorage(PrintError):
def convert_wallet_type(self, is_test): def convert_wallet_type(self, is_test):
assert not self.requires_split() assert not self.requires_split()
wallet_type = self.get('wallet_type') d = self.get('keystore', {})
if wallet_type not in ['trezor', 'keepkey']: t = d.get('type')
if t:
return False return False
if is_test: if is_test:
return True return True
self.put('wallet_type', 'standard') wallet_type = self.get('wallet_type')
self.put('key_type', 'hardware') seed_version = self.get_seed_version()
self.put('hardware_type', wallet_type) if seed_version == OLD_SEED_VERSION or wallet_type == 'old':
xpub = self.get('master_public_keys')["x/0'"] seed = self.get('seed')
self.put('master_public_keys', {'x/': xpub}) d = {
self.put('derivation', bip44_derivation(0)) 'type': 'old',
'seed': seed
}
self.put('wallet_type', 'standard')
self.put('keystore', d)
elif wallet_type == 'standard':
xpub = self.get('master_public_keys')["x/"]
xprv = self.get('master_private_keys')["x/"]
d = {
'type': 'bip32',
'xpub': xpub,
'xprv': xprv,
'seed': self.get('seed', '')
}
self.put('wallet_type', 'standard')
self.put('keystore', d)
elif wallet_type in ['trezor', 'keepkey']:
xpub = self.get('master_public_keys')["x/0'"]
d = {
'type': 'hardware',
'hardware_type': wallet_type,
'xpub': xpub,
'derivation': bip44_derivation(0),
}
self.put('wallet_type', 'standard')
self.put('keystore', d)
elif multisig_type(wallet_type):
raise BaseException('not implemented')
elif wallet_type in ['2fa']:
raise BaseException('not implemented')
def convert_imported(self, test): def convert_imported(self, test):
# '/x' is the internal ID for imported accounts # '/x' is the internal ID for imported accounts

42
lib/wallet.py

@ -50,6 +50,7 @@ from util import NotEnoughFunds, PrintError, profiler
from bitcoin import * from bitcoin import *
from version import * from version import *
from keystore import load_keystore from keystore import load_keystore
from storage import multisig_type
from transaction import Transaction from transaction import Transaction
from plugins import run_hook from plugins import run_hook
@ -1164,6 +1165,9 @@ class Abstract_Wallet(PrintError):
if self.synchronizer: if self.synchronizer:
self.synchronizer.add(address) self.synchronizer.add(address)
def has_password(self):
return self.storage.get('use_encryption', False)
class Imported_Wallet(Abstract_Wallet): class Imported_Wallet(Abstract_Wallet):
# wallet made of imported addresses # wallet made of imported addresses
@ -1242,7 +1246,7 @@ class P2PK_Wallet(Abstract_Wallet):
return public_key_to_bc_address(pubkey.decode('hex')) return public_key_to_bc_address(pubkey.decode('hex'))
def load_keystore(self): def load_keystore(self):
self.keystore = load_keystore(self.storage, self.root_name) self.keystore = load_keystore(self.storage, 'keystore')
def get_pubkey(self, c, i): def get_pubkey(self, c, i):
pubkey_list = self.change_pubkeys if c else self.receiving_pubkeys pubkey_list = self.change_pubkeys if c else self.receiving_pubkeys
@ -1402,7 +1406,6 @@ class Deterministic_Wallet(Abstract_Wallet):
class Standard_Wallet(Deterministic_Wallet, P2PK_Wallet): class Standard_Wallet(Deterministic_Wallet, P2PK_Wallet):
root_name = 'x/'
wallet_type = 'standard' wallet_type = 'standard'
def __init__(self, storage): def __init__(self, storage):
@ -1426,22 +1429,23 @@ class Standard_Wallet(Deterministic_Wallet, P2PK_Wallet):
def can_change_password(self): def can_change_password(self):
return self.keystore.can_change_password() return self.keystore.can_change_password()
def has_password(self):
return self.keystore.has_password()
def check_password(self, password): def check_password(self, password):
self.keystore.check_password(password) self.keystore.check_password(password)
def update_password(self, old_pw, new_pw): def update_password(self, old_pw, new_pw):
self.keystore.update_password(old_pw, new_pw) self.keystore.update_password(old_pw, new_pw)
self.keystore.save(self.storage, self.root_name) self.save_keystore()
self.storage.put('use_encryption', (new_pw is not None))
def save_keystore(self):
self.storage.put('keystore', self.keystore.dump())
def can_import_privkey(self): def can_import_privkey(self):
return self.keystore.can_import() return self.keystore.can_import()
def import_key(self, pk, pw): def import_key(self, pk, pw):
pubkey = self.keystore.import_key(pk, pw) pubkey = self.keystore.import_key(pk, pw)
self.keystore.save(self.storage, self.root_name) self.save_keystore()
self.receiving_pubkeys.append(pubkey) self.receiving_pubkeys.append(pubkey)
self.save_pubkeys() self.save_pubkeys()
addr = self.pubkeys_to_address(pubkey) addr = self.pubkeys_to_address(pubkey)
@ -1452,12 +1456,11 @@ class Standard_Wallet(Deterministic_Wallet, P2PK_Wallet):
class Multisig_Wallet(Deterministic_Wallet): class Multisig_Wallet(Deterministic_Wallet):
# generic m of n # generic m of n
root_name = "x1/"
gap_limit = 20 gap_limit = 20
def __init__(self, storage): def __init__(self, storage):
self.wallet_type = storage.get('wallet_type') self.wallet_type = storage.get('wallet_type')
self.m, self.n = Wallet.multisig_type(self.wallet_type) self.m, self.n = multisig_type(self.wallet_type)
Deterministic_Wallet.__init__(self, storage) Deterministic_Wallet.__init__(self, storage)
def get_pubkeys(self, c, i): def get_pubkeys(self, c, i):
@ -1481,10 +1484,10 @@ class Multisig_Wallet(Deterministic_Wallet):
for i in range(self.n): for i in range(self.n):
name = 'x%d/'%(i+1) name = 'x%d/'%(i+1)
self.keystores[name] = load_keystore(self.storage, name) self.keystores[name] = load_keystore(self.storage, name)
self.keystore = self.keystores[self.root_name] self.keystore = self.keystores['x1/']
def get_keystore(self): def get_keystore(self):
return self.keystores.get(self.root_name) return self.keystores.get('x1/')
def get_keystores(self): def get_keystores(self):
return self.keystores.values() return self.keystores.values()
@ -1492,7 +1495,8 @@ class Multisig_Wallet(Deterministic_Wallet):
def update_password(self, old_pw, new_pw): def update_password(self, old_pw, new_pw):
for name, keystore in self.keystores.items(): for name, keystore in self.keystores.items():
keystore.update_password(old_pw, new_pw) keystore.update_password(old_pw, new_pw)
keystore.save(self.storage, name) self.storage.put(name, keystore.dump())
self.storage.put('use_encryption', (new_pw is not None))
def has_seed(self): def has_seed(self):
return self.keystore.has_seed() return self.keystore.has_seed()
@ -1500,9 +1504,6 @@ class Multisig_Wallet(Deterministic_Wallet):
def can_change_password(self): def can_change_password(self):
return self.keystore.can_change_password() return self.keystore.can_change_password()
def has_password(self):
return self.keystore.has_password()
def is_watching_only(self): def is_watching_only(self):
return not any([not k.is_watching_only() for k in self.get_keystores()]) return not any([not k.is_watching_only() for k in self.get_keystores()])
@ -1568,18 +1569,9 @@ class Wallet(object):
@staticmethod @staticmethod
def wallet_class(wallet_type): def wallet_class(wallet_type):
if Wallet.multisig_type(wallet_type): if multisig_type(wallet_type):
return Multisig_Wallet return Multisig_Wallet
if wallet_type in wallet_constructors: if wallet_type in wallet_constructors:
return wallet_constructors[wallet_type] return wallet_constructors[wallet_type]
raise RuntimeError("Unknown wallet type: " + wallet_type) raise RuntimeError("Unknown wallet type: " + wallet_type)
@staticmethod
def multisig_type(wallet_type):
'''If wallet_type is mofn multi-sig, return [m, n],
otherwise return None.'''
match = re.match('(\d+)of(\d+)', wallet_type)
if match:
match = [int(x) for x in match.group(1, 2)]
return match

5
plugins/trezor/plugin.py

@ -20,10 +20,7 @@ from ..hw_wallet import HW_PluginBase
TIM_NEW, TIM_RECOVER, TIM_MNEMONIC, TIM_PRIVKEY = range(0, 4) TIM_NEW, TIM_RECOVER, TIM_MNEMONIC, TIM_PRIVKEY = range(0, 4)
class TrezorCompatibleKeyStore(Hardware_KeyStore): class TrezorCompatibleKeyStore(Hardware_KeyStore):
hw_type = 'trezor'
def load(self, storage, name):
self.xpub = storage.get('master_public_keys', {}).get(name)
self.derivation = storage.get('derivation')
def get_derivation(self): def get_derivation(self):
return self.derivation return self.derivation

17
plugins/trezor/qt_generic.py

@ -284,14 +284,13 @@ def qt_plugin_class(base_plugin_class):
# Trigger a pairing # Trigger a pairing
keystore.thread.add(partial(self.get_client, keystore)) keystore.thread.add(partial(self.get_client, keystore))
def on_create_wallet(self, storage, wizard): def create_keystore(self, hw_type, derivation, wizard):
from electrum.keystore import load_keystore from electrum.keystore import hardware_keystore
handler = self.create_handler(wizard) handler = self.create_handler(wizard)
thread = TaskThread(wizard, wizard.on_error) thread = TaskThread(wizard, wizard.on_error)
# Setup device and create accounts in separate thread; wait until done # Setup device and create accounts in separate thread; wait until done
loop = QEventLoop() loop = QEventLoop()
exc_info = [] exc_info = []
derivation = storage.get('derivation')
self.setup_device(derivation, thread, handler, on_done=loop.quit, self.setup_device(derivation, thread, handler, on_done=loop.quit,
on_error=lambda info: exc_info.extend(info)) on_error=lambda info: exc_info.extend(info))
loop.exec_() loop.exec_()
@ -299,9 +298,15 @@ def qt_plugin_class(base_plugin_class):
if exc_info: if exc_info:
wizard.on_error(exc_info) wizard.on_error(exc_info)
raise UserCancelled raise UserCancelled
storage.put('master_public_keys', {'/x':self.xpub}) # create keystore
keystore = load_keystore(storage, '/x') # this calls the dynamic constructor d = {
wizard.create_wallet(keystore, None) 'xpub': self.xpub,
'type': 'hardware',
'hw_type': hw_type,
'derivation': derivation
}
k = hardware_keystore(hw_type, d)
return k
@hook @hook
def receive_menu(self, menu, addrs, wallet): def receive_menu(self, menu, addrs, wallet):

Loading…
Cancel
Save