URI: 
       trestore from xprv - electrum - Electrum Bitcoin wallet
  HTML git clone https://git.parazyd.org/electrum
   DIR Log
   DIR Files
   DIR Refs
   DIR Submodules
       ---
   DIR commit 54973062bd903bda787bb94a66bc4eff7b35b77b
   DIR parent ace101e4f5d1ff98a722640cf4a0329e2480136c
  HTML Author: ThomasV <thomasv@gitorious>
       Date:   Wed, 25 Jun 2014 16:45:55 +0200
       
       restore from xprv
       
       Diffstat:
         M gui/qt/installwizard.py             |      15 ++++++++++-----
         M lib/bitcoin.py                      |      21 +++++++++++++++++++++
         M lib/wallet.py                       |      84 ++++++++++++++++++++-----------
       
       3 files changed, 85 insertions(+), 35 deletions(-)
       ---
   DIR diff --git a/gui/qt/installwizard.py b/gui/qt/installwizard.py
       t@@ -176,11 +176,11 @@ class InstallWizard(QDialog):
        
            def is_any(self, seed_e):
                text = self.get_seed_text(seed_e)
       -        return Wallet.is_seed(text) or Wallet.is_mpk(text) or Wallet.is_address(text) or Wallet.is_private_key(text)
       +        return Wallet.is_seed(text) or Wallet.is_old_mpk(text) or Wallet.is_xpub(text) or Wallet.is_xprv(text) or Wallet.is_address(text) or Wallet.is_private_key(text)
        
            def is_mpk(self, seed_e):
                text = self.get_seed_text(seed_e)
       -        return Wallet.is_mpk(text)
       +        return Wallet.is_xpub(text) or Wallet.is_old_mpk(text)
        
        
            def enter_seed_dialog(self, msg, sid):
       t@@ -211,7 +211,7 @@ class InstallWizard(QDialog):
                hbox, button = ok_cancel_buttons2(self, _('Next'))
                vbox.addLayout(hbox)
                button.setEnabled(False)
       -        f = lambda: button.setEnabled( map(lambda e: self.is_mpk(e), entries) == [True]*len(entries))
       +        f = lambda: button.setEnabled( map(lambda e: self.is_xpub(e), entries) == [True]*len(entries))
                for e in entries:
                    e.textChanged.connect(f)
                self.set_layout(vbox)
       t@@ -476,8 +476,13 @@ class InstallWizard(QDialog):
                            wallet = Wallet.from_seed(text, self.storage)
                            wallet.add_seed(text, password)
                            wallet.create_accounts(password)
       -                elif Wallet.is_mpk(text):
       -                    wallet = Wallet.from_mpk(text, self.storage)
       +                elif Wallet.is_xprv(text):
       +                    password = self.password_dialog()
       +                    wallet = Wallet.from_xprv(text, password, self.storage)
       +                elif Wallet.is_old_mpk(text):
       +                    wallet = Wallet.from_old_mpk(text, self.storage)
       +                elif Wallet.is_xpub(text):
       +                    wallet = Wallet.from_xpub(text, self.storage)
                        elif Wallet.is_address(text):
                            wallet = Wallet.from_address(text, self.storage)
                        elif Wallet.is_private_key(text):
   DIR diff --git a/lib/bitcoin.py b/lib/bitcoin.py
       t@@ -656,6 +656,27 @@ def deserialize_xkey(xkey):
            return depth, fingerprint, child_number, c, K_or_k
        
        
       +def get_xkey_name(xkey):
       +    depth, fingerprint, child_number, c, K = deserialize_xkey(xkey)
       +    n = int(child_number.encode('hex'), 16)
       +    if n & BIP32_PRIME:
       +        child_id = "%d'"%(n - BIP32_PRIME)
       +    else:
       +        child_id = "%d"%n
       +    if depth == 0:
       +        return ''
       +    elif depth == 1:
       +        return child_id
       +    else:
       +        raise BaseException("xpub depth error")
       +
       +
       +def xpub_from_xprv(xprv):
       +    depth, fingerprint, child_number, c, k = deserialize_xkey(xprv)
       +    K, cK = get_pubkeys_from_secret(k)
       +    xpub = "0488B21E".decode('hex') + chr(depth) + fingerprint + child_number + c + cK
       +    return EncodeBase58Check(xpub)
       +
        
        def bip32_root(seed):
            import hmac
   DIR diff --git a/lib/wallet.py b/lib/wallet.py
       t@@ -1266,8 +1266,11 @@ class NewWallet(Deterministic_Wallet):
            def __init__(self, storage):
                Deterministic_Wallet.__init__(self, storage)
        
       +    def is_watching_only(self):
       +        return self.master_private_keys is {}
       +
            def can_create_accounts(self):
       -        return not self.is_watching_only()
       +        return 'm/' in self.master_private_keys.keys()
        
            def get_master_public_key(self):
                return self.master_public_keys["m/"]
       t@@ -1291,19 +1294,29 @@ class NewWallet(Deterministic_Wallet):
                xpub = self.master_public_keys["m/"]
                assert deserialize_xkey(xpriv)[3] == deserialize_xkey(xpub)[3]
        
       -    def create_watching_only_wallet(self, xpub):
       +    def create_xprv_wallet(self, xprv, password):
       +        xpub = bitcoin.xpub_from_xprv(xprv)
       +        account = BIP32_Account({'xpub':xpub})
       +        account_id = 'm/' + bitcoin.get_xkey_name(xpub)
                self.storage.put('seed_version', self.seed_version, True)
       -        self.add_master_public_key("m/", xpub)
       +        self.add_master_private_key(account_id, xprv, password)
       +        self.add_master_public_key(account_id, xpub)
       +        self.add_account(account_id, account)
       +
       +    def create_watching_only_wallet(self, xpub):
                account = BIP32_Account({'xpub':xpub})
       -        self.add_account("m/", account)
       +        account_id = 'm/' + bitcoin.get_xkey_name(xpub)
       +        self.storage.put('seed_version', self.seed_version, True)
       +        self.add_master_public_key(account_id, xpub)
       +        self.add_account(account_id, account)
        
            def create_accounts(self, password):
                # First check the password is valid (this raises if it isn't).
                self.check_password(password)
                self.create_account('Main account', password)
        
       -    def add_master_public_key(self, name, mpk):
       -        self.master_public_keys[name] = mpk
       +    def add_master_public_key(self, name, xpub):
       +        self.master_public_keys[name] = xpub
                self.storage.put('master_public_keys', self.master_public_keys, True)
        
            def add_master_private_key(self, name, xpriv, password):
       t@@ -1576,21 +1589,31 @@ class Wallet(object):
                    return False
        
            @classmethod
       -    def is_mpk(self, mpk):
       +    def is_old_mpk(self, mpk):
                try:
                    int(mpk, 16)
       -            old = True
       +            assert len(mpk) == 128
       +            return True
                except:
       -            old = False
       +            return False
        
       -        if old:
       -            return len(mpk) == 128
       -        else:
       -            try:
       -                deserialize_xkey(mpk)
       -                return True
       -            except:
       -                return False
       +    @classmethod
       +    def is_xpub(self, text):
       +        try:
       +            assert text[0:4] == 'xpub'
       +            deserialize_xkey(text)
       +            return True
       +        except:
       +            return False
       +
       +    @classmethod
       +    def is_xprv(self, text):
       +        try:
       +            assert text[0:4] == 'xprv'
       +            deserialize_xkey(text)
       +            return True
       +        except:
       +            return False
        
            @classmethod
            def is_address(self, text):
       t@@ -1635,19 +1658,20 @@ class Wallet(object):
                return w
        
            @classmethod
       -    def from_mpk(self, mpk, storage):
       -        try:
       -            int(mpk, 16)
       -            old = True
       -        except:
       -            old = False
       +    def from_old_mpk(self, mpk, storage):
       +        w = OldWallet(storage)
       +        w.seed = ''
       +        w.create_watching_only_wallet(mpk)
       +        return w
        
       -        if old:
       -            w = OldWallet(storage)
       -            w.seed = ''
       -            w.create_watching_only_wallet(mpk)
       -        else:
       -            w = NewWallet(storage)
       -            w.create_watching_only_wallet(mpk)
       +    @classmethod
       +    def from_xpub(self, xpub, storage):
       +        w = NewWallet(storage)
       +        w.create_watching_only_wallet(xpub)
       +        return w
        
       +    @classmethod
       +    def from_xprv(self, xprv, password, storage):
       +        w = NewWallet(storage)
       +        w.create_xprv_wallet(xprv, password)
                return w