restore from xprv
authorThomasV <thomasv@gitorious>
Wed, 25 Jun 2014 14:45:55 +0000 (16:45 +0200)
committerThomasV <thomasv@gitorious>
Wed, 25 Jun 2014 14:45:55 +0000 (16:45 +0200)
gui/qt/installwizard.py
lib/bitcoin.py
lib/wallet.py

index e697d3a..e379978 100644 (file)
@@ -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):
@@ -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)
@@ -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):
index 7153ccd..33631ff 100644 (file)
@@ -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
index 467a11c..67676b5 100644 (file)
@@ -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/"]
@@ -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):
@@ -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):
@@ -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