diff --git a/gui/installwizard.py b/gui/installwizard.py index 6803ef2e4..68d978e3a 100644 --- a/gui/installwizard.py +++ b/gui/installwizard.py @@ -124,6 +124,15 @@ class InstallWizard(QDialog): wallet.set_up_to_date(False) wallet.interface.poke('synchronizer') waiting_dialog(waiting) + + # try to restore old account + if not wallet.is_found(): + print "trying old method" + wallet.create_old_account() + wallet.set_up_to_date(False) + wallet.interface.poke('synchronizer') + waiting_dialog(waiting) + if wallet.is_found(): QMessageBox.information(None, _('Information'), _("Recovery successful"), _('OK')) else: diff --git a/lib/account.py b/lib/account.py index 8cbca6ba4..303882878 100644 --- a/lib/account.py +++ b/lib/account.py @@ -48,10 +48,13 @@ class Account(object): class OldAccount(Account): """ Privatekey(type,n) = Master_private_key + H(n|S|type) """ - def __init__(self, mpk, mpk2 = None, mpk3 = None): - self.mpk = mpk - self.mpk2 = mpk2 - self.mpk3 = mpk3 + def __init__(self, v): + self.addresses = v.get(0, []) + self.change = v.get(1, []) + self.mpk = v['mpk'].decode('hex') + + def dump(self): + return {0:self.addresses, 1:self.change} @classmethod def mpk_from_seed(klass, seed): @@ -68,48 +71,33 @@ class OldAccount(Account): seed = hashlib.sha256(seed + oldseed).digest() return string_to_number( seed ) - def get_sequence(self, sequence, mpk): - for_change, n = sequence - return string_to_number( Hash( "%d:%d:"%(n,for_change) + mpk.decode('hex') ) ) - - def get_address(self, sequence): - if not self.mpk2: - pubkey = self.get_pubkey(sequence) - address = public_key_to_bc_address( pubkey.decode('hex') ) - elif not self.mpk3: - pubkey1 = self.get_pubkey(sequence) - pubkey2 = self.get_pubkey(sequence, mpk = self.mpk2) - address = Transaction.multisig_script([pubkey1, pubkey2], 2)["address"] - else: - pubkey1 = self.get_pubkey(sequence) - pubkey2 = self.get_pubkey(sequence, mpk = self.mpk2) - pubkey3 = self.get_pubkey(sequence, mpk = self.mpk3) - address = Transaction.multisig_script([pubkey1, pubkey2, pubkey3], 2)["address"] + def get_sequence(self, for_change, n): + return string_to_number( Hash( "%d:%d:"%(n,for_change) + self.mpk ) ) + + def get_address(self, for_change, n): + pubkey = self.get_pubkey(for_change, n) + address = public_key_to_bc_address( pubkey.decode('hex') ) return address - def get_pubkey(self, sequence, mpk=None): + def get_pubkey(self, for_change, n): curve = SECP256k1 - if mpk is None: mpk = self.mpk - z = self.get_sequence(sequence, mpk) - master_public_key = ecdsa.VerifyingKey.from_string( mpk.decode('hex'), curve = SECP256k1 ) + mpk = self.mpk + z = self.get_sequence(for_change, n) + master_public_key = ecdsa.VerifyingKey.from_string( mpk, curve = SECP256k1 ) pubkey_point = master_public_key.pubkey.point + z*curve.generator public_key2 = ecdsa.VerifyingKey.from_public_point( pubkey_point, curve = SECP256k1 ) return '04' + public_key2.to_string().encode('hex') - def get_private_key_from_stretched_exponent(self, sequence, secexp): + def get_private_key_from_stretched_exponent(self, for_change, n, secexp): order = generator_secp256k1.order() - secexp = ( secexp + self.get_sequence(sequence, self.mpk) ) % order + secexp = ( secexp + self.get_sequence(for_change, n) ) % order pk = number_to_string( secexp, generator_secp256k1.order() ) compressed = False return SecretToASecret( pk, compressed ) - def get_private_key(self, sequence, seed): - secexp = self.stretch_key(seed) - return self.get_private_key_from_stretched_exponent(sequence, secexp) - - def get_private_keys(self, sequence_list, seed): + def get_private_key(self, for_change, n, seed): secexp = self.stretch_key(seed) - return [ self.get_private_key_from_stretched_exponent( sequence, secexp) for sequence in sequence_list] + return self.get_private_key_from_stretched_exponent(for_change, n, secexp) def check_seed(self, seed): curve = SECP256k1 @@ -121,23 +109,8 @@ class OldAccount(Account): raise BaseException('Invalid password') return True - def get_input_info(self, sequence): - if not self.mpk2: - pk_addr = self.get_address(sequence) - redeemScript = None - elif not self.mpk3: - pubkey1 = self.get_pubkey(sequence) - pubkey2 = self.get_pubkey(sequence,mpk=self.mpk2) - pk_addr = public_key_to_bc_address( pubkey1.decode('hex') ) # we need to return that address to get the right private key - redeemScript = Transaction.multisig_script([pubkey1, pubkey2], 2)['redeemScript'] - else: - pubkey1 = self.get_pubkey(sequence) - pubkey2 = self.get_pubkey(sequence, mpk=self.mpk2) - pubkey3 = self.get_pubkey(sequence, mpk=self.mpk3) - pk_addr = public_key_to_bc_address( pubkey1.decode('hex') ) # we need to return that address to get the right private key - redeemScript = Transaction.multisig_script([pubkey1, pubkey2, pubkey3], 2)['redeemScript'] - return pk_addr, redeemScript - + def redeem_script(self, sequence): + return None class BIP32_Account(Account): diff --git a/lib/simple_config.py b/lib/simple_config.py index f8a9e00e9..15b121671 100644 --- a/lib/simple_config.py +++ b/lib/simple_config.py @@ -206,8 +206,8 @@ a SimpleConfig instance then reads the wallet file. def save_wallet_config(self): # prevent the creation of incomplete wallets - if self.wallet_config.get('master_public_keys') is None: - return + #if self.wallet_config.get('master_public_keys') is None: + # return s = repr(self.wallet_config) f = open(self.path,"w") diff --git a/lib/version.py b/lib/version.py index 3d72061cf..fe5fffae1 100644 --- a/lib/version.py +++ b/lib/version.py @@ -1,4 +1,4 @@ ELECTRUM_VERSION = "1.9" # version of the client package PROTOCOL_VERSION = '0.6' # protocol version requested -SEED_VERSION = 4 # bump this every time the seed generation is modified +SEED_VERSION = 5 # bump this every time the seed generation is modified TRANSLATION_ID = 4101 # version of the wiki page diff --git a/lib/wallet.py b/lib/wallet.py index b5d25a0f4..5333505ae 100644 --- a/lib/wallet.py +++ b/lib/wallet.py @@ -72,6 +72,7 @@ class Wallet: # saved fields self.seed_version = config.get('seed_version', SEED_VERSION) + self.gap_limit = config.get('gap_limit', 5) self.use_change = config.get('use_change',True) self.fee = int(config.get('fee_per_kb',20000)) @@ -92,6 +93,9 @@ class Wallet: self.first_addresses = config.get('first_addresses',{}) + #if self.seed_version != SEED_VERSION: + # raise ValueError("This wallet seed is deprecated. Please restore from seed.") + self.load_accounts(config) self.transactions = {} @@ -117,9 +121,6 @@ class Wallet: self.transaction_lock = threading.Lock() self.tx_event = threading.Event() - if self.seed_version != SEED_VERSION: - raise ValueError("This wallet seed is deprecated. Please run upgrade.py for a diagnostic.") - for tx_hash, tx in self.transactions.items(): if self.check_new_tx(tx_hash, tx): self.update_tx_outputs(tx_hash) @@ -294,26 +295,39 @@ class Wallet: return account_id, account - def create_account(self, account_type = '1', name = 'unnamed'): + def create_account(self, account_type = '1', name = None): account_id, account = self.next_account(account_type) self.accounts[account_id] = account self.save_accounts() - self.labels[account_id] = name + if name: + self.labels[account_id] = name self.config.set_key('labels', self.labels, True) + def create_old_account(self): + print self.seed + mpk = OldAccount.mpk_from_seed(self.seed) + self.config.set_key('master_public_key', mpk, True) + self.accounts[0] = OldAccount({'mpk':mpk, 0:[], 1:[]}) + self.save_accounts() + + def save_accounts(self): d = {} for k, v in self.accounts.items(): d[k] = v.dump() self.config.set_key('accounts', d, True) + def load_accounts(self, config): d = config.get('accounts', {}) self.accounts = {} for k, v in d.items(): - if '&' in k: + if k == 0: + v['mpk'] = config.get('master_public_key') + self.accounts[k] = OldAccount(v) + elif '&' in k: self.accounts[k] = BIP32_Account_2of2(v) else: self.accounts[k] = BIP32_Account(v) @@ -616,7 +630,8 @@ class Wallet: def synchronize(self): - self.create_pending_accounts() + if self.master_public_keys: + self.create_pending_accounts() new = [] for account in self.accounts.values(): new += self.synchronize_account(account)