URI: 
       tupdate bip32 accounts and wallet - electrum - Electrum Bitcoin wallet
  HTML git clone https://git.parazyd.org/electrum
   DIR Log
   DIR Files
   DIR Refs
   DIR Submodules
       ---
   DIR commit 5a43b633d625611db5074bb1759d14b577286f4f
   DIR parent ffc72e65df01bb397d51ca70ff04eb60fab9b8a2
  HTML Author: ThomasV <thomasv@gitorious>
       Date:   Tue,  1 Apr 2014 11:25:12 +0200
       
       update bip32 accounts and wallet
       
       Diffstat:
         M electrum                            |       2 +-
         M gui/qt/main_window.py               |      50 +++++++++++++-------------------
         M lib/account.py                      |      74 ++++++++++++++++++-------------
         M lib/version.py                      |       2 +-
         M lib/wallet.py                       |     300 +++++++++++++------------------
       
       5 files changed, 190 insertions(+), 238 deletions(-)
       ---
   DIR diff --git a/electrum b/electrum
       t@@ -90,7 +90,7 @@ def arg_parser():
            parser.add_option("-G", "--gap", dest="gap_limit", default=None, help="gap limit")
            parser.add_option("-W", "--password", dest="password", default=None, help="set password for usage with commands (currently only implemented for create command, do not use it for longrunning gui session since the password is visible in /proc)")
            parser.add_option("-1", "--oneserver", action="store_true", dest="oneserver", default=False, help="connect to one server only")
       -    #parser.add_option("--bip32", action="store_true", dest="bip32", default=False, help="bip32 (not final)")
       +    parser.add_option("--bip32", action="store_true", dest="bip32", default=False, help="bip32 (not final)")
            parser.add_option("--mpk", dest="mpk", default=False, help="restore from master public key")
            return parser
        
   DIR diff --git a/gui/qt/main_window.py b/gui/qt/main_window.py
       t@@ -1477,7 +1477,8 @@ class ElectrumWindow(QMainWindow):
                self.tabs.setCurrentIndex(3)
        
        
       -    def new_account_dialog(self):
       +    @protected
       +    def new_account_dialog(self, password):
        
                dialog = QDialog(self)
                dialog.setModal(1)
       t@@ -1501,7 +1502,7 @@ class ElectrumWindow(QMainWindow):
                name = str(e.text())
                if not name: return
        
       -        self.wallet.create_pending_account('1', name)
       +        self.wallet.create_pending_account('1of1', name, password)
                self.update_receive_tab()
                self.tabs.setCurrentIndex(2)
        
       t@@ -1545,11 +1546,6 @@ class ElectrumWindow(QMainWindow):
                dialog.setModal(1)
                dialog.setWindowTitle(_("Master Public Keys"))
        
       -        chain_text = QTextEdit()
       -        chain_text.setReadOnly(True)
       -        chain_text.setMaximumHeight(170)
       -        chain_qrw = QRCodeWidget()
       -
                mpk_text = QTextEdit()
                mpk_text.setReadOnly(True)
                mpk_text.setMaximumHeight(170)
       t@@ -1561,17 +1557,10 @@ class ElectrumWindow(QMainWindow):
                main_layout.addWidget(mpk_text, 1, 1)
                main_layout.addWidget(mpk_qrw, 1, 2)
        
       -        main_layout.addWidget(QLabel(_('Chain')), 2, 0)
       -        main_layout.addWidget(chain_text, 2, 1)
       -        main_layout.addWidget(chain_qrw, 2, 2)
       -
                def update(key):
       -            c, K, cK = self.wallet.master_public_keys[str(key)]
       -            chain_text.setText(c)
       -            chain_qrw.set_addr(c)
       -            chain_qrw.update_qr()
       -            mpk_text.setText(K)
       -            mpk_qrw.set_addr(K)
       +            xpub = self.wallet.master_public_keys[str(key)]
       +            mpk_text.setText(xpub)
       +            mpk_qrw.set_addr(xpub)
                    mpk_qrw.update_qr()
        
                key_selector = QComboBox()
       t@@ -1683,6 +1672,7 @@ class ElectrumWindow(QMainWindow):
                try:
                    pk_list = self.wallet.get_private_key(address, password)
                except Exception as e:
       +            traceback.print_exc(file=sys.stdout)
                    self.show_message(str(e))
                    return
        
       t@@ -2269,30 +2259,30 @@ class ElectrumWindow(QMainWindow):
        
        
            def show_account_details(self, k):
       +        account = self.wallet.accounts[k]
       +
                d = QDialog(self)
                d.setWindowTitle(_('Account Details'))
                d.setModal(1)
        
                vbox = QVBoxLayout(d)
       -        roots = self.wallet.get_roots(k)
       -
                name = self.wallet.get_account_name(k)
                label = QLabel('Name: ' + name)
                vbox.addWidget(label)
        
       -        acctype = '2 of 2' if len(roots) == 2 else '2 of 3' if len(roots) == 3 else 'Single key'
       -        vbox.addWidget(QLabel('Type: ' + acctype))
       +        vbox.addWidget(QLabel(_('Address type') + ': ' + account.get_type()))
        
       -        label = QLabel('Derivation: ' + k)
       -        vbox.addWidget(label)
       +        vbox.addWidget(QLabel(_('Derivation') + ': ' + k))
       +
       +        vbox.addWidget(QLabel(_('Master Public Key:')))
       +
       +        text = QTextEdit()
       +        text.setReadOnly(True)
       +        text.setMaximumHeight(170)
       +        vbox.addWidget(text)
        
       -        #for root in roots:
       -        #    mpk = self.wallet.master_public_keys[root]
       -        #    text = QTextEdit()
       -        #    text.setReadOnly(True)
       -        #    text.setMaximumHeight(120)
       -        #    text.setText(repr(mpk))
       -        #    vbox.addWidget(text)
       +        mpk_text = '\n'.join( account.get_master_pubkeys() )
       +        text.setText(mpk_text)
        
                vbox.addLayout(close_button(d))
                d.exec_()
   DIR diff --git a/lib/account.py b/lib/account.py
       t@@ -18,6 +18,7 @@
        
        
        from bitcoin import *
       +from i18n import _
        from transaction import Transaction
        
        class Account(object):
       t@@ -115,20 +116,23 @@ class OldAccount(Account):
            def redeem_script(self, sequence):
                return None
        
       +    def get_master_pubkeys(self):
       +        return [self.mpk]
       +
       +    def get_type(self):
       +        return _('Old Electrum format')
       +
       +
        
        class BIP32_Account(Account):
        
            def __init__(self, v):
                Account.__init__(self, v)
       -        self.c = v['c'].decode('hex')
       -        self.K = v['K'].decode('hex')
       -        self.cK = v['cK'].decode('hex')
       +        self.xpub = v['xpub']
        
            def dump(self):
                d = Account.dump(self)
       -        d['c'] = self.c.encode('hex')
       -        d['K'] = self.K.encode('hex')
       -        d['cK'] = self.cK.encode('hex')
       +        d['xpub'] = self.xpub
                return d
        
            def get_address(self, for_change, n):
       t@@ -140,39 +144,41 @@ class BIP32_Account(Account):
                return self.get_address(0,0)
        
            def get_pubkey(self, for_change, n):
       -        K = self.K
       -        chain = self.c
       +        _, _, _, c, cK = deserialize_xkey(self.xpub)
                for i in [for_change, n]:
       -            K, K_compressed, chain = CKD_prime(K, chain, i)
       -        return K_compressed.encode('hex')
       +            cK, c = CKD_pub(cK, c, i)
       +        return cK.encode('hex')
        
            def redeem_script(self, sequence):
                return None
        
       +    def get_pubkeys(self, sequence):
       +        return [self.get_pubkey(*sequence)]
       +
       +    def get_master_pubkeys(self):
       +        return [self.xpub]
        
       +    def get_type(self):
       +        return _('Standard 1 of 1')
       +        #acctype = 'multisig 2 of 2' if len(roots) == 2 else 'multisig 2 of 3' if len(roots) == 3 else 'standard 1 of 1'
        
        
        class BIP32_Account_2of2(BIP32_Account):
        
            def __init__(self, v):
                BIP32_Account.__init__(self, v)
       -        self.c2 = v['c2'].decode('hex')
       -        self.K2 = v['K2'].decode('hex')
       -        self.cK2 = v['cK2'].decode('hex')
       +        self.xpub2 = v['xpub2']
        
            def dump(self):
                d = BIP32_Account.dump(self)
       -        d['c2'] = self.c2.encode('hex')
       -        d['K2'] = self.K2.encode('hex')
       -        d['cK2'] = self.cK2.encode('hex')
       +        d['xpub2'] = self.xpub2
                return d
        
            def get_pubkey2(self, for_change, n):
       -        K = self.K2
       -        chain = self.c2
       +        _, _, _, c, cK = deserialize_xkey(self.xpub2)
                for i in [for_change, n]:
       -            K, K_compressed, chain = CKD_prime(K, chain, i)
       -        return K_compressed.encode('hex')
       +            cK, c = CKD_prime(cK, c, i)
       +        return cK.encode('hex')
        
            def redeem_script(self, sequence):
                chain, i = sequence
       t@@ -187,27 +193,29 @@ class BIP32_Account_2of2(BIP32_Account):
            def get_pubkeys(self, sequence):
                return [ self.get_pubkey( *sequence ), self.get_pubkey2( *sequence )]
        
       +    def get_master_pubkeys(self):
       +        return [self.xpub, self.xpub2]
       +
       +    def get_type(self):
       +        return _('Multisig 2 of 2')
       +
       +
        class BIP32_Account_2of3(BIP32_Account_2of2):
        
            def __init__(self, v):
                BIP32_Account_2of2.__init__(self, v)
       -        self.c3 = v['c3'].decode('hex')
       -        self.K3 = v['K3'].decode('hex')
       -        self.cK3 = v['cK3'].decode('hex')
       +        self.xpub3 = v['xpub3']
        
            def dump(self):
                d = BIP32_Account_2of2.dump(self)
       -        d['c3'] = self.c3.encode('hex')
       -        d['K3'] = self.K3.encode('hex')
       -        d['cK3'] = self.cK3.encode('hex')
       +        d['xpub3'] = self.xpub3
                return d
        
            def get_pubkey3(self, for_change, n):
       -        K = self.K3
       -        chain = self.c3
       +        _, _, _, c, cK = deserialize_xkey(self.xpub3)
                for i in [for_change, n]:
       -            K, K_compressed, chain = CKD_prime(K, chain, i)
       -        return K_compressed.encode('hex')
       +            cK, c = CKD_prime(cK, c, i)
       +        return cK.encode('hex')
        
            def get_redeem_script(self, sequence):
                chain, i = sequence
       t@@ -219,5 +227,11 @@ class BIP32_Account_2of3(BIP32_Account_2of2):
            def get_pubkeys(self, sequence):
                return [ self.get_pubkey( *sequence ), self.get_pubkey2( *sequence ), self.get_pubkey3( *sequence )]
        
       +    def get_master_pubkeys(self):
       +        return [self.xpub, self.xpub2, self.xpub3]
       +
       +    def get_type(self):
       +        return _('Multisig 2 of 3')
       +
        
        
   DIR diff --git a/lib/version.py b/lib/version.py
       t@@ -1,5 +1,5 @@
        ELECTRUM_VERSION = "1.9.8"  # version of the client package
        PROTOCOL_VERSION = '0.9'    # protocol version requested
       -NEW_SEED_VERSION = 6        # bip32 wallets
       +NEW_SEED_VERSION = 7        # bip32 wallets
        OLD_SEED_VERSION = 4        # old electrum deterministic generation
        SEED_PREFIX      = '01'     # the hash of the mnemonic seed must begin with this
   DIR diff --git a/lib/wallet.py b/lib/wallet.py
       t@@ -321,96 +321,40 @@ class NewWallet:
                self.create_accounts(password)
        
        
       -    def create_watching_only_wallet(self, K0, c0):
       -        cK0 = "" #FIXME
       -        self.master_public_keys = {
       -            "m/0'/": (c0, K0, cK0),
       -            }
       +    def create_watching_only_wallet(self, xpub):
       +        self.master_public_keys = { "m/": xpub }
                self.storage.put('master_public_keys', self.master_public_keys, True)
                self.storage.put('seed_version', self.seed_version, True)
       -        self.create_account('1of1','Main account')
       +        account = BIP32_Account({'xpub':xpub})
       +        self.add_account("m/", account)
        
        
            def create_accounts(self, password):
                seed = pw_decode(self.seed, password)
                # create default account
       -        self.create_master_keys('1of1', password)
       -        self.create_account('1of1','Main account')
       +        self.create_master_keys(password)
       +        self.create_account('Main account', password)
        
        
       -    def create_master_keys(self, account_type, password):
       -        master_k, master_c, master_K, master_cK = bip32_init(self.get_seed(password))
       -        if account_type == '1of1':
       -            k0, c0, K0, cK0 = bip32_private_derivation(master_k, master_c, "m/", "m/0'/")
       -            self.master_public_keys["m/0'/"] = (c0, K0, cK0)
       -            self.master_private_keys["m/0'/"] = pw_encode(k0, password)
       -        elif account_type == '2of2':
       -            k1, c1, K1, cK1 = bip32_private_derivation(master_k, master_c, "m/", "m/1'/")
       -            k2, c2, K2, cK2 = bip32_private_derivation(master_k, master_c, "m/", "m/2'/")
       -            self.master_public_keys["m/1'/"] = (c1, K1, cK1)
       -            self.master_public_keys["m/2'/"] = (c2, K2, cK2)
       -            self.master_private_keys["m/1'/"] = pw_encode(k1, password)
       -            self.master_private_keys["m/2'/"] = pw_encode(k2, password)
       -        elif account_type == '2of3':
       -            k3, c3, K3, cK3 = bip32_private_derivation(master_k, master_c, "m/", "m/3'/")
       -            k4, c4, K4, cK4 = bip32_private_derivation(master_k, master_c, "m/", "m/4'/")
       -            k5, c5, K5, cK5 = bip32_private_derivation(master_k, master_c, "m/", "m/5'/")
       -            self.master_public_keys["m/3'/"] = (c3, K3, cK3)
       -            self.master_public_keys["m/4'/"] = (c4, K4, cK4)
       -            self.master_public_keys["m/5'/"] = (c5, K5, cK5)
       -            self.master_private_keys["m/3'/"] = pw_encode(k3, password)
       -            self.master_private_keys["m/4'/"] = pw_encode(k4, password)
       -            self.master_private_keys["m/5'/"] = pw_encode(k5, password)
       -
       +    def create_master_keys(self, password):
       +        xpriv, xpub = bip32_root(self.get_seed(password))
       +        self.master_public_keys["m/"] = xpub
       +        self.master_private_keys["m/"] = pw_encode(xpriv, password)
                self.storage.put('master_public_keys', self.master_public_keys, True)
                self.storage.put('master_private_keys', self.master_private_keys, True)
        
       -    def has_master_public_keys(self, account_type):
       -        if account_type == '1of1':
       -            return "m/0'/" in self.master_public_keys
       -        elif account_type == '2of2':
       -            return set(["m/1'/", "m/2'/"]) <= set(self.master_public_keys.keys())
       -        elif account_type == '2of3':
       -            return set(["m/3'/", "m/4'/", "m/5'/"]) <= set(self.master_public_keys.keys())
       -
       -    def find_root_by_master_key(self, c, K):
       -        for key, v in self.master_public_keys.items():
       +
       +    def find_root_by_master_key(self, xpub):
       +        for key, xpub2 in self.master_public_keys.items():
                    if key == "m/":continue
       -            cc, KK, _ = v
       -            if (c == cc) and (K == KK):
       +            if xpub == xpub2:
                        return key
        
       -    def deseed_root(self, seed, password):
       -        # for safety, we ask the user to enter their seed
       -        assert seed == self.get_seed(password)
       -        self.seed = ''
       -        self.storage.put('seed', '', True)
       -
       -
       -    def deseed_branch(self, k):
       -        # check that parent has no seed
       -        # assert self.seed == ''
       -        self.master_private_keys.pop(k)
       -        self.storage.put('master_private_keys', self.master_private_keys, True)
       -
       -
            def is_watching_only(self):
                return (self.seed == '') and (self.master_private_keys == {})
        
        
       -
       -    def account_id(self, account_type, i):
       -        if account_type == '1of1':
       -            return "m/0'/%d"%i
       -        elif account_type == '2of2':
       -            return "m/1'/%d & m/2'/%d"%(i,i)
       -        elif account_type == '2of3':
       -            return "m/3'/%d & m/4'/%d & m/5'/%d"%(i,i,i)
       -        else:
       -            raise Exception('unknown account type')
       -
       -
       -    def num_accounts(self, account_type):
       +    def num_accounts(self, account_type = '1of1'):
                keys = self.accounts.keys()
                i = 0
                while True:
       t@@ -420,47 +364,35 @@ class NewWallet:
                return i
        
        
       -    def new_account_address(self, account_type = '1of1'):
       +    def next_account_address(self, account_type, password):
                i = self.num_accounts(account_type)
       -        k = self.account_id(account_type,i)
       +        account_id = self.account_id(account_type, i)
        
       -        addr = self.next_addresses.get(k)
       +        addr = self.next_addresses.get(account_id)
                if not addr: 
       -            account_id, account = self.next_account(account_type)
       +            account = self.make_account(account_id, password)
                    addr = account.first_address()
       -            self.next_addresses[k] = addr
       -            self.storage.put('next_addresses',self.next_addresses)
       -
       -        return k, addr
       +            self.next_addresses[account_id] = addr
       +            self.storage.put('next_addresses', self.next_addresses)
        
       +        return account_id, addr
        
       -    def next_account(self, account_type = '1of1'):
       -
       -        i = self.num_accounts(account_type)
       -        account_id = self.account_id(account_type,i)
       -
       -        if account_type is '1of1':
       -            master_c0, master_K0, _ = self.master_public_keys["m/0'/"]
       -            c0, K0, cK0 = bip32_public_derivation(master_c0.decode('hex'), master_K0.decode('hex'), "m/0'/", "m/0'/%d"%i)
       -            account = BIP32_Account({ 'c':c0, 'K':K0, 'cK':cK0 })
       -
       -        elif account_type == '2of2':
       -            master_c1, master_K1, _ = self.master_public_keys["m/1'/"]
       -            c1, K1, cK1 = bip32_public_derivation(master_c1.decode('hex'), master_K1.decode('hex'), "m/1'/", "m/1'/%d"%i)
       -            master_c2, master_K2, _ = self.master_public_keys["m/2'/"]
       -            c2, K2, cK2 = bip32_public_derivation(master_c2.decode('hex'), master_K2.decode('hex'), "m/2'/", "m/2'/%d"%i)
       -            account = BIP32_Account_2of2({ 'c':c1, 'K':K1, 'cK':cK1, 'c2':c2, 'K2':K2, 'cK2':cK2 })
       -
       -        elif account_type == '2of3':
       -            master_c3, master_K3, _ = self.master_public_keys["m/3'/"]
       -            c3, K3, cK3 = bip32_public_derivation(master_c3.decode('hex'), master_K3.decode('hex'), "m/3'/", "m/3'/%d"%i)
       -            master_c4, master_K4, _ = self.master_public_keys["m/4'/"]
       -            c4, K4, cK4 = bip32_public_derivation(master_c4.decode('hex'), master_K4.decode('hex'), "m/4'/", "m/4'/%d"%i)
       -            master_c5, master_K5, _ = self.master_public_keys["m/5'/"]
       -            c5, K5, cK5 = bip32_public_derivation(master_c5.decode('hex'), master_K5.decode('hex'), "m/5'/", "m/5'/%d"%i)
       -            account = BIP32_Account_2of3({ 'c':c3, 'K':K3, 'cK':cK3, 'c2':c4, 'K2':K4, 'cK2':cK4, 'c3':c5, 'K3':K5, 'cK3':cK5 })
       +    def account_id(self, account_type, i):
       +        if account_type == '1of1':
       +            return "m/%d'"%i
       +        else:
       +            raise
        
       -        return account_id, account
       +    def make_account(self, account_id, password):
       +        """Creates and saves the master keys, but does not save the account"""
       +        master_xpriv = pw_decode( self.master_private_keys["m/"] , password )
       +        xpriv, xpub = bip32_private_derivation(master_xpriv, "m/", account_id)
       +        self.master_private_keys[account_id] = pw_encode(xpriv, password)
       +        self.master_public_keys[account_id] = xpub
       +        self.storage.put('master_public_keys', self.master_public_keys, True)
       +        self.storage.put('master_private_keys', self.master_private_keys, True)
       +        account = BIP32_Account({'xpub':xpub})
       +        return account
        
        
            def set_label(self, name, text = None):
       t@@ -482,17 +414,24 @@ class NewWallet:
                return changed
        
        
       +    def create_account(self, name, password):
       +        i = self.num_accounts('1of1')
       +        account_id = self.account_id('1of1', i)
       +        account = self.make_account(account_id, password)
       +        self.add_account(account_id, account)
       +        if name:
       +            self.set_label(account_id, name)
        
       -    def create_account(self, account_type = '1of1', name = None):
       -        k, account = self.next_account(account_type)
       -        if k in self.pending_accounts:
       -            self.pending_accounts.pop(k)
       -            self.storage.put('pending_accounts', self.pending_accounts)
       +        # add address of the next account
       +        _, _ = self.next_account_address('1of1', password)
        
       -        self.accounts[k] = account
       +
       +    def add_account(self, account_id, account):
       +        self.accounts[account_id] = account
       +        if account_id in self.pending_accounts:
       +            self.pending_accounts.pop(account_id)
       +            self.storage.put('pending_accounts', self.pending_accounts)
                self.save_accounts()
       -        if name:
       -            self.set_label(k, name)
        
        
            def save_accounts(self):
       t@@ -525,10 +464,10 @@ class NewWallet:
            def account_is_pending(self, k):
                return k in self.pending_accounts
        
       -    def create_pending_account(self, acct_type, name):
       -        k, addr = self.new_account_address(acct_type)
       -        self.set_label(k, name)
       -        self.pending_accounts[k] = addr
       +    def create_pending_account(self, acct_type, name, password):
       +        account_id, addr = self.next_account_address(acct_type, password)
       +        self.set_label(account_id, name)
       +        self.pending_accounts[account_id] = addr
                self.storage.put('pending_accounts', self.pending_accounts)
        
            def get_pending_accounts(self):
       t@@ -559,20 +498,13 @@ class NewWallet:
                return s[0] == 1
        
            def get_master_public_key(self):
       -        c, K, cK = self.storage.get("master_public_keys")["m/0'/"]
       -        return repr((c, K))
       +        return self.storage.get("master_public_keys")["m/"]
        
            def get_master_private_key(self, account, password):
                k = self.master_private_keys.get(account)
                if not k: return
       -        master_k = pw_decode( k, password)
       -        master_c, master_K, master_Kc = self.master_public_keys[account]
       -        try:
       -            K, Kc = get_pubkeys_from_secret(master_k.decode('hex'))
       -            assert K.encode('hex') == master_K
       -        except Exception:
       -            raise Exception("Invalid password")
       -        return master_k
       +        xpriv = pw_decode( k, password)
       +        return xpriv
        
        
            def get_address_index(self, address):
       t@@ -605,13 +537,14 @@ class NewWallet:
                roots = []
                for a in account.split('&'):
                    s = a.strip()
       -            m = re.match("(m/\d+'/)(\d+)", s)
       +            m = re.match("m/(\d+')", s)
                    roots.append( m.group(1) )
                return roots
        
       +
            def is_seeded(self, account):
       -        if type(account) is int:
       -            return self.seed is not None
       +        return True
       +
        
                for root in self.get_roots(account):
                    if root not in self.master_private_keys.keys(): 
       t@@ -619,29 +552,27 @@ class NewWallet:
                return True
        
            def rebase_sequence(self, account, sequence):
       +        # account has one or more xpub
       +        # sequence is a sequence of public derivations
                c, i = sequence
                dd = []
                for a in account.split('&'):
                    s = a.strip()
       -            m = re.match("(m/\d+'/)(\d+)", s)
       -            root = m.group(1)
       -            num = int(m.group(2))
       +            m = re.match("m/(\d+)'", s)
       +            root = "m/"
       +            num = int(m.group(1))
                    dd.append( (root, [num,c,i] ) )
                return dd
                
        
       -    def get_keyID(self, account, sequence):
       -        if account == 0:
       -            a, b = sequence
       -            mpk = self.storage.get('master_public_key')
       -            return 'old(%s,%d,%d)'%(mpk,a,b)
        
       +    def get_keyID(self, account, sequence):
                rs = self.rebase_sequence(account, sequence)
                dd = []
                for root, public_sequence in rs:
       -            c, K, cK = self.master_public_keys[root]
       +            xpub = self.master_public_keys[root]
                    s = '/' + '/'.join( map(lambda x:str(x), public_sequence) )
       -            dd.append( 'bip32(%s,%s,%s)'%(c, cK, s) )
       +            dd.append( 'bip32(%s,%s)'%(xpub, s) )
                return '&'.join(dd)
        
        
       t@@ -666,20 +597,14 @@ class NewWallet:
                if address in self.imported_keys.keys():
                    out.append( pw_decode( self.imported_keys[address], password ) )
                else:
       -            account, sequence = self.get_address_index(address)
       -            if account == 0:
       -                pk = self.accounts[account].get_private_key(seed, sequence)
       -                out.append(pk)
       -                return out
       -
       -            # assert address == self.accounts[account].get_address(*sequence)
       -            rs = self.rebase_sequence( account, sequence)
       +            account_id, sequence = self.get_address_index(address)
       +            #rs = self.rebase_sequence( account, sequence)
       +            rs = [(account_id, sequence)]
                    for root, public_sequence in rs:
       -
       -                if root not in self.master_private_keys.keys(): continue
       -                master_k = self.get_master_private_key(root, password)
       -                master_c, _, _ = self.master_public_keys[root]
       -                pk = bip32_private_key( public_sequence, master_k.decode('hex'), master_c.decode('hex'))
       +                xpriv = self.get_master_private_key(root, password)
       +                if not xpriv: continue
       +                _, _, _, c, k = deserialize_xkey(xpriv)
       +                pk = bip32_private_key( public_sequence, k, c )
                        out.append(pk)
                            
                return out
       t@@ -849,7 +774,7 @@ class NewWallet:
                for tx_hash, tx_height in h:
                    if tx_height == 0:
                        tx_age = 0
       -            else: 
       +            else:
                        tx_age = self.network.get_local_height() - tx_height + 1
                    if tx_age > age:
                        age = tx_age
       t@@ -877,16 +802,14 @@ class NewWallet:
                return new_addresses
                
        
       -
       -    def create_pending_accounts(self):
       -        for account_type in ['1of1','2of2','2of3']:
       -            if not self.has_master_public_keys(account_type):
       -                continue
       -            k, a = self.new_account_address(account_type)
       -            if self.address_is_old(a):
       -                print_error( "creating account", a )
       -                self.create_account(account_type)
       -                self.next_addresses.pop(k)
       +    def check_pending_accounts(self):
       +        for account_id, addr in self.next_addresses.items():
       +            if self.address_is_old(addr):
       +                print_error( "creating account", account_id )
       +                xpub = self.master_public_keys[account_id]
       +                account = BIP32_Account({'xpub':xpub})
       +                self.add_account(account_id, account)
       +                self.next_addresses.pop(account_id)
        
        
            def synchronize_account(self, account):
       t@@ -897,8 +820,7 @@ class NewWallet:
        
        
            def synchronize(self):
       -        if self.master_public_keys:
       -            self.create_pending_accounts()
       +        self.check_pending_accounts()
                new = []
                for account in self.accounts.values():
                    new += self.synchronize_account(account)
       t@@ -1761,10 +1683,10 @@ class OldWallet(NewWallet):
                self.accounts[0] = OldAccount({'mpk':mpk, 0:[], 1:[]})
                self.save_accounts()
        
       -    def create_watching_only_wallet(self, K0):
       +    def create_watching_only_wallet(self, mpk):
                self.seed_version = OLD_SEED_VERSION
                self.storage.put('seed_version', self.seed_version, True)
       -        self.create_account(K0)
       +        self.create_account(mpk)
        
            def get_seed(self, password):
                seed = pw_decode(self.seed, password)
       t@@ -1801,7 +1723,32 @@ class OldWallet(NewWallet):
                assert k == 0
                return 'Main account'
        
       +    def is_seeded(self, account):
       +        return self.seed is not None
       +
       +    def get_private_key(self, address, password):
       +        if self.is_watching_only():
       +            return []
       +
       +        # first check the provided password
       +        seed = self.get_seed(password)
       +        
       +        out = []
       +        if address in self.imported_keys.keys():
       +            out.append( pw_decode( self.imported_keys[address], password ) )
       +        else:
       +            account_id, sequence = self.get_address_index(address)
       +            pk = self.accounts[0].get_private_key(seed, sequence)
       +            out.append(pk)
       +        return out
        
       +    def get_keyID(self, account, sequence):
       +        a, b = sequence
       +        mpk = self.storage.get('master_public_key')
       +        return 'old(%s,%d,%d)'%(mpk,a,b)
       +
       +    def check_pending_accounts(self):
       +        pass
        
        
        # former WalletFactory
       t@@ -1867,19 +1814,20 @@ class Wallet(object):
        
        
            @classmethod
       -    def from_mpk(self, s, storage):
       +    def from_mpk(self, mpk, storage):
       +
                try:
       -            mpk, chain = s.split(':')
       +            int(mpk, 16)
       +            old = True
                except:
       -            mpk = s
       -            chain = False
       +            old = False
        
       -        if chain:
       -            w = NewWallet(storage)
       -            w.create_watching_only_wallet(mpk, chain)
       -        else:
       +        if old:
                    w = OldWallet(storage)
                    w.seed = ''
                    w.create_watching_only_wallet(mpk)
       +        else:
       +            w = NewWallet(storage)
       +            w.create_watching_only_wallet(mpk)
        
                return w