electrum

Electrum Bitcoin wallet
git clone https://git.parazyd.org/electrum
Log | Files | Refs | Submodules

commit 54973062bd903bda787bb94a66bc4eff7b35b77b
parent ace101e4f5d1ff98a722640cf4a0329e2480136c
Author: ThomasV <thomasv@gitorious>
Date:   Wed, 25 Jun 2014 16:45:55 +0200

restore from xprv

Diffstat:
Mgui/qt/installwizard.py | 15++++++++++-----
Mlib/bitcoin.py | 21+++++++++++++++++++++
Mlib/wallet.py | 84+++++++++++++++++++++++++++++++++++++++++++++++++++----------------------------
3 files changed, 85 insertions(+), 35 deletions(-)

diff --git a/gui/qt/installwizard.py b/gui/qt/installwizard.py @@ -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): diff --git a/lib/bitcoin.py b/lib/bitcoin.py @@ -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 diff --git a/lib/wallet.py b/lib/wallet.py @@ -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