can_import
[electrum-nvc.git] / lib / wallet.py
1 #!/usr/bin/env python
2 #
3 # Electrum - lightweight Bitcoin client
4 # Copyright (C) 2011 thomasv@gitorious
5 #
6 # This program is free software: you can redistribute it and/or modify
7 # it under the terms of the GNU General Public License as published by
8 # the Free Software Foundation, either version 3 of the License, or
9 # (at your option) any later version.
10 #
11 # This program is distributed in the hope that it will be useful,
12 # but WITHOUT ANY WARRANTY; without even the implied warranty of
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 # GNU General Public License for more details.
15 #
16 # You should have received a copy of the GNU General Public License
17 # along with this program. If not, see <http://www.gnu.org/licenses/>.
18
19 import sys
20 import base64
21 import os
22 import re
23 import hashlib
24 import copy
25 import operator
26 import ast
27 import threading
28 import random
29 import aes
30 import Queue
31 import time
32 import math
33
34 from util import print_msg, print_error, format_satoshis
35 from bitcoin import *
36 from account import *
37 from transaction import Transaction
38 from plugins import run_hook
39 import bitcoin
40 from synchronizer import WalletSynchronizer
41
42 COINBASE_MATURITY = 100
43 DUST_THRESHOLD = 5430
44
45 # internal ID for imported account
46 IMPORTED_ACCOUNT = '/x'
47
48
49
50 from version import *
51
52
53 class WalletStorage:
54
55     def __init__(self, config):
56         self.lock = threading.Lock()
57         self.config = config
58         self.data = {}
59         self.file_exists = False
60         self.path = self.init_path(config)
61         print_error( "wallet path", self.path )
62         if self.path:
63             self.read(self.path)
64
65
66     def init_path(self, config):
67         """Set the path of the wallet."""
68
69         # command line -w option
70         path = config.get('wallet_path')
71         if path:
72             return path
73
74         # path in config file
75         path = config.get('default_wallet_path')
76         if path:
77             return path
78
79         # default path
80         dirpath = os.path.join(config.path, "wallets")
81         if not os.path.exists(dirpath):
82             os.mkdir(dirpath)
83
84         new_path = os.path.join(config.path, "wallets", "default_wallet")
85
86         # default path in pre 1.9 versions
87         old_path = os.path.join(config.path, "electrum.dat")
88         if os.path.exists(old_path) and not os.path.exists(new_path):
89             os.rename(old_path, new_path)
90
91         return new_path
92
93
94     def read(self, path):
95         """Read the contents of the wallet file."""
96         try:
97             with open(self.path, "r") as f:
98                 data = f.read()
99         except IOError:
100             return
101         try:
102             d = ast.literal_eval( data )  #parse raw data from reading wallet file
103         except Exception:
104             raise IOError("Cannot read wallet file.")
105
106         self.data = d
107         self.file_exists = True
108
109
110     def get(self, key, default=None):
111         v = self.data.get(key)
112         if v is None: 
113             v = default
114         return v
115
116     def put(self, key, value, save = True):
117
118         with self.lock:
119             if value is not None:
120                 self.data[key] = value
121             else:
122                 self.data.pop(key)
123             if save: 
124                 self.write()
125
126     def write(self):
127         s = repr(self.data)
128         f = open(self.path,"w")
129         f.write( s )
130         f.close()
131         if 'ANDROID_DATA' not in os.environ:
132             import stat
133             os.chmod(self.path,stat.S_IREAD | stat.S_IWRITE)
134
135
136
137     
138
139         
140
141 class Abstract_Wallet:
142
143     def __init__(self, storage):
144
145         self.storage = storage
146         self.electrum_version = ELECTRUM_VERSION
147         self.gap_limit_for_change = 3 # constant
148         # saved fields
149         self.seed_version          = storage.get('seed_version', NEW_SEED_VERSION)
150         self.gap_limit             = storage.get('gap_limit', 5)
151         self.use_change            = storage.get('use_change',True)
152         self.use_encryption        = storage.get('use_encryption', False)
153         self.seed                  = storage.get('seed', '')               # encrypted
154         self.labels                = storage.get('labels', {})
155         self.frozen_addresses      = storage.get('frozen_addresses',[])
156         self.addressbook           = storage.get('contacts', [])
157
158         self.history               = storage.get('addr_history',{})        # address -> list(txid, height)
159
160         self.fee                   = int(storage.get('fee_per_kb', 10000))
161
162         self.master_public_keys = storage.get('master_public_keys',{})
163         self.master_private_keys = storage.get('master_private_keys', {})
164
165         self.next_addresses = storage.get('next_addresses',{})
166
167
168         # This attribute is set when wallet.start_threads is called.
169         self.synchronizer = None
170
171         self.load_accounts()
172
173         self.transactions = {}
174         tx_list = self.storage.get('transactions',{})
175         for k,v in tx_list.items():
176             try:
177                 tx = Transaction(v)
178             except Exception:
179                 print_msg("Warning: Cannot deserialize transactions. skipping")
180                 continue
181
182             self.add_extra_addresses(tx)
183             self.transactions[k] = tx
184
185         for h,tx in self.transactions.items():
186             if not self.check_new_tx(h, tx):
187                 print_error("removing unreferenced tx", h)
188                 self.transactions.pop(h)
189
190
191         # not saved
192         self.prevout_values = {}     # my own transaction outputs
193         self.spent_outputs = []
194
195         # spv
196         self.verifier = None
197
198         # there is a difference between wallet.up_to_date and interface.is_up_to_date()
199         # interface.is_up_to_date() returns true when all requests have been answered and processed
200         # wallet.up_to_date is true when the wallet is synchronized (stronger requirement)
201         
202         self.up_to_date = False
203         self.lock = threading.Lock()
204         self.transaction_lock = threading.Lock()
205         self.tx_event = threading.Event()
206
207         for tx_hash, tx in self.transactions.items():
208             self.update_tx_outputs(tx_hash)
209
210
211     def add_extra_addresses(self, tx):
212         h = tx.hash()
213         # find the address corresponding to pay-to-pubkey inputs
214         tx.add_extra_addresses(self.transactions)
215         for o in tx.d.get('outputs'):
216             if o.get('is_pubkey'):
217                 for tx2 in self.transactions.values():
218                     tx2.add_extra_addresses({h:tx})
219
220
221     def get_action(self):
222         pass
223
224     def load_accounts(self):
225         self.accounts = {}
226         self.imported_keys = self.storage.get('imported_keys',{})
227         if self.imported_keys:
228             print_error("cannot load imported keys")
229
230         d = self.storage.get('accounts', {})
231         for k, v in d.items():
232             if k == 0:
233                 v['mpk'] = self.storage.get('master_public_key')
234                 self.accounts[k] = OldAccount(v)
235             elif v.get('imported'):
236                 self.accounts[k] = ImportedAccount(v)
237             elif v.get('xpub3'):
238                 self.accounts[k] = BIP32_Account_2of3(v)
239             elif v.get('xpub2'):
240                 self.accounts[k] = BIP32_Account_2of2(v)
241             elif v.get('xpub'):
242                 self.accounts[k] = BIP32_Account(v)
243             elif v.get('pending'):
244                 self.accounts[k] = PendingAccount(v)
245             else:
246                 print_error("cannot load account", v)
247
248
249     def synchronize(self):
250         pass
251
252     def can_create_accounts(self):
253         return False
254
255     def set_up_to_date(self,b):
256         with self.lock: self.up_to_date = b
257
258     def is_up_to_date(self):
259         with self.lock: return self.up_to_date
260
261
262     def update(self):
263         self.up_to_date = False
264         while not self.is_up_to_date(): 
265             time.sleep(0.1)
266
267     def is_imported(self, addr):
268         account = self.accounts.get(IMPORTED_ACCOUNT)
269         if account: 
270             return addr in account.get_addresses(0)
271         else:
272             return False
273
274     def import_key(self, sec, password):
275         try:
276             pubkey = public_key_from_private_key(sec)
277             address = public_key_to_bc_address(pubkey.decode('hex'))
278         except Exception:
279             raise Exception('Invalid private key')
280
281         if self.is_mine(address):
282             raise Exception('Address already in wallet')
283         
284         if self.accounts.get(IMPORTED_ACCOUNT) is None:
285             self.accounts[IMPORTED_ACCOUNT] = ImportedAccount({'imported':{}})
286         self.accounts[IMPORTED_ACCOUNT].add(address, pubkey, sec, password)
287         self.save_accounts()
288         
289         if self.synchronizer:
290             self.synchronizer.subscribe_to_addresses([address])
291         return address
292         
293
294     def delete_imported_key(self, addr):
295         account = self.accounts[IMPORTED_ACCOUNT]
296         account.remove(addr)
297         if not account.get_addresses(0):
298             self.accounts.pop(IMPORTED_ACCOUNT)
299         self.save_accounts()
300
301
302     def set_label(self, name, text = None):
303         changed = False
304         old_text = self.labels.get(name)
305         if text:
306             if old_text != text:
307                 self.labels[name] = text
308                 changed = True
309         else:
310             if old_text:
311                 self.labels.pop(name)
312                 changed = True
313
314         if changed:
315             self.storage.put('labels', self.labels, True)
316
317         run_hook('set_label', name, text, changed)
318         return changed
319
320
321
322
323     def addresses(self, include_change = True, _next=True):
324         o = []
325         for a in self.accounts.keys():
326             o += self.get_account_addresses(a, include_change)
327
328         if _next:
329             for addr in self.next_addresses.values():
330                 if addr not in o:
331                     o += [addr]
332         return o
333
334
335     def is_mine(self, address):
336         return address in self.addresses(True) 
337
338
339     def is_change(self, address):
340         if not self.is_mine(address): return False
341         acct, s = self.get_address_index(address)
342         if s is None: return False
343         return s[0] == 1
344
345
346     def get_address_index(self, address):
347
348         for account in self.accounts.keys():
349             for for_change in [0,1]:
350                 addresses = self.accounts[account].get_addresses(for_change)
351                 for addr in addresses:
352                     if address == addr:
353                         return account, (for_change, addresses.index(addr))
354
355         for k,v in self.next_addresses.items():
356             if v == address:
357                 return k, (0,0)
358
359         raise Exception("Address not found", address)
360
361
362     def getpubkeys(self, addr):
363         assert is_valid(addr) and self.is_mine(addr)
364         account, sequence = self.get_address_index(addr)
365         a = self.accounts[account]
366         return a.get_pubkeys( sequence )
367
368
369     def get_private_key(self, address, password):
370         if self.is_watching_only():
371             return []
372         account_id, sequence = self.get_address_index(address)
373         return self.accounts[account_id].get_private_key(sequence, self, password)
374
375
376     def get_public_keys(self, address):
377         account_id, sequence = self.get_address_index(address)
378         return self.accounts[account_id].get_pubkeys(sequence)
379
380
381     def add_keypairs_from_wallet(self, tx, keypairs, password):
382         for txin in tx.inputs:
383             address = txin['address']
384             if not self.is_mine(address):
385                 continue
386             private_keys = self.get_private_key(address, password)
387             for sec in private_keys:
388                 pubkey = public_key_from_private_key(sec)
389                 keypairs[ pubkey ] = sec
390
391
392
393     def add_keypairs_from_KeyID(self, tx, keypairs, password):
394         # first check the provided password
395         seed = self.get_seed(password)
396
397         for txin in tx.inputs:
398             keyid = txin.get('KeyID')
399             if keyid:
400                 roots = []
401                 for s in keyid.split('&'):
402                     m = re.match("bip32\((.*),(/\d+/\d+)\)", s)
403                     if not m: continue
404                     xpub = m.group(1)
405                     sequence = m.group(2)
406                     root = self.find_root_by_master_key(xpub)
407                     if not root: continue
408                     sequence = map(lambda x:int(x), sequence.strip('/').split('/'))
409                     root = root + '%d'%sequence[0]
410                     sequence = sequence[1:]
411                     roots.append((root,sequence)) 
412
413                 account_id = " & ".join( map(lambda x:x[0], roots) )
414                 account = self.accounts.get(account_id)
415                 if not account: continue
416                 addr = account.get_address(*sequence)
417                 txin['address'] = addr # fixme: side effect
418                 pk = self.get_private_key(addr, password)
419                 for sec in pk:
420                     pubkey = public_key_from_private_key(sec)
421                     keypairs[pubkey] = sec
422
423
424
425     def signrawtransaction(self, tx, input_info, private_keys, password):
426
427         # check that the password is correct
428         seed = self.get_seed(password)
429
430         # if input_info is not known, build it using wallet UTXOs
431         if not input_info:
432             input_info = []
433             unspent_coins = self.get_unspent_coins()
434             for txin in tx.inputs:
435                 for item in unspent_coins:
436                     if txin['prevout_hash'] == item['prevout_hash'] and txin['prevout_n'] == item['prevout_n']:
437                         info = { 'address':item['address'], 'scriptPubKey':item['scriptPubKey'] }
438                         self.add_input_info(info)
439                         input_info.append(info)
440                         break
441                 else:
442                     print_error( "input not in UTXOs" )
443                     input_info.append(None)
444
445         # add input_info to the transaction
446         print_error("input_info", input_info)
447         tx.add_input_info(input_info)
448
449         # build a list of public/private keys
450         keypairs = {}
451
452         # add private keys from parameter
453         for sec in private_keys:
454             pubkey = public_key_from_private_key(sec)
455             keypairs[ pubkey ] = sec
456
457         # add private_keys from KeyID
458         self.add_keypairs_from_KeyID(tx, keypairs, password)
459         # add private keys from wallet
460         self.add_keypairs_from_wallet(tx, keypairs, password)
461         # sign the transaction
462         self.sign_transaction(tx, keypairs, password)
463
464
465     def sign_message(self, address, message, password):
466         keys = self.get_private_key(address, password)
467         assert len(keys) == 1
468         sec = keys[0]
469         key = regenerate_key(sec)
470         compressed = is_compressed(sec)
471         return key.sign_message(message, compressed, address)
472
473
474
475     def decrypt_message(self, pubkey, message, password):
476         address = public_key_to_bc_address(pubkey.decode('hex'))
477         keys = self.get_private_key(address, password)
478         secret = keys[0]
479         ec = regenerate_key(secret)
480         decrypted = ec.decrypt_message(message)
481         return decrypted[0]
482
483
484
485     def is_found(self):
486         return self.history.values() != [[]] * len(self.history) 
487
488
489     def add_contact(self, address, label=None):
490         self.addressbook.append(address)
491         self.storage.put('contacts', self.addressbook, True)
492         if label:  
493             self.set_label(address, label)
494
495
496     def delete_contact(self, addr):
497         if addr in self.addressbook:
498             self.addressbook.remove(addr)
499             self.storage.put('addressbook', self.addressbook, True)
500
501
502     def fill_addressbook(self):
503         for tx_hash, tx in self.transactions.items():
504             is_relevant, is_send, _, _ = self.get_tx_value(tx)
505             if is_send:
506                 for addr, v in tx.outputs:
507                     if not self.is_mine(addr) and addr not in self.addressbook:
508                         self.addressbook.append(addr)
509         # redo labels
510         # self.update_tx_labels()
511
512     def get_num_tx(self, address):
513         n = 0 
514         for tx in self.transactions.values():
515             if address in map(lambda x:x[0], tx.outputs): n += 1
516         return n
517
518
519     def get_address_flags(self, addr):
520         flags = "C" if self.is_change(addr) else "I" if addr in self.imported_keys.keys() else "-" 
521         flags += "F" if addr in self.frozen_addresses else "-"
522         return flags
523         
524
525     def get_tx_value(self, tx, account=None):
526         domain = self.get_account_addresses(account)
527         return tx.get_value(domain, self.prevout_values)
528
529     
530     def update_tx_outputs(self, tx_hash):
531         tx = self.transactions.get(tx_hash)
532
533         for i, (addr, value) in enumerate(tx.outputs):
534             key = tx_hash+ ':%d'%i
535             self.prevout_values[key] = value
536
537         for item in tx.inputs:
538             if self.is_mine(item.get('address')):
539                 key = item['prevout_hash'] + ':%d'%item['prevout_n']
540                 self.spent_outputs.append(key)
541
542
543     def get_addr_balance(self, address):
544         #assert self.is_mine(address)
545         h = self.history.get(address,[])
546         if h == ['*']: return 0,0
547         c = u = 0
548         received_coins = []   # list of coins received at address
549
550         for tx_hash, tx_height in h:
551             tx = self.transactions.get(tx_hash)
552             if not tx: continue
553
554             for i, (addr, value) in enumerate(tx.outputs):
555                 if addr == address:
556                     key = tx_hash + ':%d'%i
557                     received_coins.append(key)
558
559         for tx_hash, tx_height in h:
560             tx = self.transactions.get(tx_hash)
561             if not tx: continue
562             v = 0
563
564             for item in tx.inputs:
565                 addr = item.get('address')
566                 if addr == address:
567                     key = item['prevout_hash']  + ':%d'%item['prevout_n']
568                     value = self.prevout_values.get( key )
569                     if key in received_coins: 
570                         v -= value
571
572             for i, (addr, value) in enumerate(tx.outputs):
573                 key = tx_hash + ':%d'%i
574                 if addr == address:
575                     v += value
576
577             if tx_height:
578                 c += v
579             else:
580                 u += v
581         return c, u
582
583
584     def get_account_name(self, k):
585         return self.labels.get(k, self.accounts[k].get_name(k))
586
587
588     def get_account_names(self):
589         account_names = {}
590         for k in self.accounts.keys():
591             account_names[k] = self.get_account_name(k)
592         return account_names
593
594
595     def get_account_addresses(self, a, include_change=True):
596         if a is None:
597             o = self.addresses(True)
598         elif a in self.accounts:
599             ac = self.accounts[a]
600             o = ac.get_addresses(0)
601             if include_change: o += ac.get_addresses(1)
602         return o
603
604
605     def get_account_balance(self, account):
606         return self.get_balance(self.get_account_addresses(account))
607
608     def get_frozen_balance(self):
609         return self.get_balance(self.frozen_addresses)
610         
611     def get_balance(self, domain=None):
612         if domain is None: domain = self.addresses(True)
613         cc = uu = 0
614         for addr in domain:
615             c, u = self.get_addr_balance(addr)
616             cc += c
617             uu += u
618         return cc, uu
619
620
621     def get_unspent_coins(self, domain=None):
622         coins = []
623         if domain is None: domain = self.addresses(True)
624         for addr in domain:
625             h = self.history.get(addr, [])
626             if h == ['*']: continue
627             for tx_hash, tx_height in h:
628                 tx = self.transactions.get(tx_hash)
629                 if tx is None: raise Exception("Wallet not synchronized")
630                 is_coinbase = tx.inputs[0].get('prevout_hash') == '0'*64
631                 for o in tx.d.get('outputs'):
632                     output = o.copy()
633                     if output.get('address') != addr: continue
634                     key = tx_hash + ":%d" % output.get('prevout_n')
635                     if key in self.spent_outputs: continue
636                     output['prevout_hash'] = tx_hash
637                     output['height'] = tx_height
638                     output['coinbase'] = is_coinbase
639                     coins.append((tx_height, output))
640
641         # sort by age
642         if coins:
643             coins = sorted(coins)
644             if coins[-1][0] != 0:
645                 while coins[0][0] == 0: 
646                     coins = coins[1:] + [ coins[0] ]
647         return [x[1] for x in coins]
648
649
650     def choose_tx_inputs( self, amount, fixed_fee, num_outputs, domain = None ):
651         """ todo: minimize tx size """
652         total = 0
653         fee = self.fee if fixed_fee is None else fixed_fee
654         if domain is None:
655             domain = self.addresses(True)
656
657         for i in self.frozen_addresses:
658             if i in domain: domain.remove(i)
659
660         coins = self.get_unspent_coins(domain)
661         inputs = []
662
663         for item in coins:
664             if item.get('coinbase') and item.get('height') + COINBASE_MATURITY > self.network.get_local_height():
665                 continue
666             addr = item.get('address')
667             v = item.get('value')
668             total += v
669             inputs.append(item)
670             fee = self.estimated_fee(inputs, num_outputs) if fixed_fee is None else fixed_fee
671             if total >= amount + fee: break
672         else:
673             inputs = []
674
675         return inputs, total, fee
676
677
678     def set_fee(self, fee):
679         if self.fee != fee:
680             self.fee = fee
681             self.storage.put('fee_per_kb', self.fee, True)
682         
683     def estimated_fee(self, inputs, num_outputs):
684         estimated_size =  len(inputs) * 180 + num_outputs * 34    # this assumes non-compressed keys
685         fee = self.fee * int(math.ceil(estimated_size/1000.))
686         return fee
687
688
689     def add_tx_change( self, inputs, outputs, amount, fee, total, change_addr=None):
690         "add change to a transaction"
691         change_amount = total - ( amount + fee )
692         if change_amount > DUST_THRESHOLD:
693             if not change_addr:
694
695                 # send change to one of the accounts involved in the tx
696                 address = inputs[0].get('address')
697                 account, _ = self.get_address_index(address)
698
699                 if not self.use_change or account == IMPORTED_ACCOUNT:
700                     change_addr = inputs[-1]['address']
701                 else:
702                     change_addr = self.accounts[account].get_addresses(1)[-self.gap_limit_for_change]
703
704             # Insert the change output at a random position in the outputs
705             posn = random.randint(0, len(outputs))
706             outputs[posn:posn] = [( change_addr,  change_amount)]
707         return outputs
708
709
710     def get_history(self, address):
711         with self.lock:
712             return self.history.get(address)
713
714
715     def get_status(self, h):
716         if not h: return None
717         if h == ['*']: return '*'
718         status = ''
719         for tx_hash, height in h:
720             status += tx_hash + ':%d:' % height
721         return hashlib.sha256( status ).digest().encode('hex')
722
723
724     def receive_tx_callback(self, tx_hash, tx, tx_height):
725
726         with self.transaction_lock:
727             self.add_extra_addresses(tx)
728             if not self.check_new_tx(tx_hash, tx):
729                 # may happen due to pruning
730                 print_error("received transaction that is no longer referenced in history", tx_hash)
731                 return
732             self.transactions[tx_hash] = tx
733             self.network.pending_transactions_for_notifications.append(tx)
734             self.save_transactions()
735             if self.verifier and tx_height>0: 
736                 self.verifier.add(tx_hash, tx_height)
737             self.update_tx_outputs(tx_hash)
738
739
740     def save_transactions(self):
741         tx = {}
742         for k,v in self.transactions.items():
743             tx[k] = str(v)
744         self.storage.put('transactions', tx, True)
745
746     def receive_history_callback(self, addr, hist):
747
748         if not self.check_new_history(addr, hist):
749             raise Exception("error: received history for %s is not consistent with known transactions"%addr)
750             
751         with self.lock:
752             self.history[addr] = hist
753             self.storage.put('addr_history', self.history, True)
754
755         if hist != ['*']:
756             for tx_hash, tx_height in hist:
757                 if tx_height>0:
758                     # add it in case it was previously unconfirmed
759                     if self.verifier: self.verifier.add(tx_hash, tx_height)
760
761
762     def get_tx_history(self, account=None):
763         if not self.verifier:
764             return []
765
766         with self.transaction_lock:
767             history = self.transactions.items()
768             history.sort(key = lambda x: self.verifier.get_txpos(x[0]))
769             result = []
770     
771             balance = 0
772             for tx_hash, tx in history:
773                 is_relevant, is_mine, v, fee = self.get_tx_value(tx, account)
774                 if v is not None: balance += v
775
776             c, u = self.get_account_balance(account)
777
778             if balance != c+u:
779                 result.append( ('', 1000, 0, c+u-balance, None, c+u-balance, None ) )
780
781             balance = c + u - balance
782             for tx_hash, tx in history:
783                 is_relevant, is_mine, value, fee = self.get_tx_value(tx, account)
784                 if not is_relevant:
785                     continue
786                 if value is not None:
787                     balance += value
788
789                 conf, timestamp = self.verifier.get_confirmations(tx_hash) if self.verifier else (None, None)
790                 result.append( (tx_hash, conf, is_mine, value, fee, balance, timestamp) )
791
792         return result
793
794
795     def get_label(self, tx_hash):
796         label = self.labels.get(tx_hash)
797         is_default = (label == '') or (label is None)
798         if is_default: label = self.get_default_label(tx_hash)
799         return label, is_default
800
801
802     def get_default_label(self, tx_hash):
803         tx = self.transactions.get(tx_hash)
804         default_label = ''
805         if tx:
806             is_relevant, is_mine, _, _ = self.get_tx_value(tx)
807             if is_mine:
808                 for o in tx.outputs:
809                     o_addr, _ = o
810                     if not self.is_mine(o_addr):
811                         try:
812                             default_label = self.labels[o_addr]
813                         except KeyError:
814                             default_label = '>' + o_addr
815                         break
816                 else:
817                     default_label = '(internal)'
818             else:
819                 for o in tx.outputs:
820                     o_addr, _ = o
821                     if self.is_mine(o_addr) and not self.is_change(o_addr):
822                         break
823                 else:
824                     for o in tx.outputs:
825                         o_addr, _ = o
826                         if self.is_mine(o_addr):
827                             break
828                     else:
829                         o_addr = None
830
831                 if o_addr:
832                     dest_label = self.labels.get(o_addr)
833                     try:
834                         default_label = self.labels[o_addr]
835                     except KeyError:
836                         default_label = '<' + o_addr
837
838         return default_label
839
840
841     def make_unsigned_transaction(self, outputs, fee=None, change_addr=None, domain=None ):
842         for address, x in outputs:
843             assert is_valid(address), "Address " + address + " is invalid!"
844         amount = sum( map(lambda x:x[1], outputs) )
845         inputs, total, fee = self.choose_tx_inputs( amount, fee, len(outputs), domain )
846         if not inputs:
847             raise ValueError("Not enough funds")
848         for txin in inputs:
849             self.add_input_info(txin)
850         outputs = self.add_tx_change(inputs, outputs, amount, fee, total, change_addr)
851         return Transaction.from_io(inputs, outputs)
852
853
854     def mktx(self, outputs, password, fee=None, change_addr=None, domain= None ):
855         tx = self.make_unsigned_transaction(outputs, fee, change_addr, domain)
856         keypairs = {}
857         self.add_keypairs_from_wallet(tx, keypairs, password)
858         if keypairs:
859             self.sign_transaction(tx, keypairs, password)
860         return tx
861
862
863     def add_input_info(self, txin):
864         address = txin['address']
865         account_id, sequence = self.get_address_index(address)
866         account = self.accounts[account_id]
867         txin['KeyID'] = account.get_keyID(sequence)
868         redeemScript = account.redeem_script(sequence)
869         if redeemScript: 
870             txin['redeemScript'] = redeemScript
871         else:
872             txin['redeemPubkey'] = account.get_pubkey(*sequence)
873
874
875     def sign_transaction(self, tx, keypairs, password):
876         tx.sign(keypairs)
877         run_hook('sign_transaction', tx, password)
878
879
880     def sendtx(self, tx):
881         # synchronous
882         h = self.send_tx(tx)
883         self.tx_event.wait()
884         return self.receive_tx(h, tx)
885
886     def send_tx(self, tx):
887         # asynchronous
888         self.tx_event.clear()
889         self.network.send([('blockchain.transaction.broadcast', [str(tx)])], self.on_broadcast)
890         return tx.hash()
891
892     def on_broadcast(self, i, r):
893         self.tx_result = r.get('result')
894         self.tx_event.set()
895
896     def receive_tx(self, tx_hash, tx):
897         out = self.tx_result 
898         if out != tx_hash:
899             return False, "error: " + out
900         run_hook('receive_tx', tx, self)
901         return True, out
902
903
904     def update_password(self, old_password, new_password):
905         if new_password == '': 
906             new_password = None
907
908         if self.has_seed():
909             decoded = self.get_seed(old_password)
910             self.seed = pw_encode( decoded, new_password)
911             self.storage.put('seed', self.seed, True)
912
913         imported_account = self.accounts.get(IMPORTED_ACCOUNT)
914         if imported_account: 
915             imported_account.update_password(old_password, new_password)
916             self.save_accounts()
917
918         for k, v in self.master_private_keys.items():
919             b = pw_decode(v, old_password)
920             c = pw_encode(b, new_password)
921             self.master_private_keys[k] = c
922         self.storage.put('master_private_keys', self.master_private_keys, True)
923
924         self.use_encryption = (new_password != None)
925         self.storage.put('use_encryption', self.use_encryption,True)
926
927
928     def freeze(self,addr):
929         if self.is_mine(addr) and addr not in self.frozen_addresses:
930             self.frozen_addresses.append(addr)
931             self.storage.put('frozen_addresses', self.frozen_addresses, True)
932             return True
933         else:
934             return False
935
936
937     def unfreeze(self,addr):
938         if self.is_mine(addr) and addr in self.frozen_addresses:
939             self.frozen_addresses.remove(addr)
940             self.storage.put('frozen_addresses', self.frozen_addresses, True)
941             return True
942         else:
943             return False
944
945
946     def set_verifier(self, verifier):
947         self.verifier = verifier
948
949         # review transactions that are in the history
950         for addr, hist in self.history.items():
951             if hist == ['*']: continue
952             for tx_hash, tx_height in hist:
953                 if tx_height>0:
954                     # add it in case it was previously unconfirmed
955                     self.verifier.add(tx_hash, tx_height)
956
957         # if we are on a pruning server, remove unverified transactions
958         vr = self.verifier.transactions.keys() + self.verifier.verified_tx.keys()
959         for tx_hash in self.transactions.keys():
960             if tx_hash not in vr:
961                 self.transactions.pop(tx_hash)
962
963
964     def check_new_history(self, addr, hist):
965         
966         # check that all tx in hist are relevant
967         if hist != ['*']:
968             for tx_hash, height in hist:
969                 tx = self.transactions.get(tx_hash)
970                 if not tx: continue
971                 if not tx.has_address(addr):
972                     return False
973
974         # check that we are not "orphaning" a transaction
975         old_hist = self.history.get(addr,[])
976         if old_hist == ['*']: return True
977
978         for tx_hash, height in old_hist:
979             if tx_hash in map(lambda x:x[0], hist): continue
980             found = False
981             for _addr, _hist in self.history.items():
982                 if _addr == addr: continue
983                 if _hist == ['*']: continue
984                 _tx_hist = map(lambda x:x[0], _hist)
985                 if tx_hash in _tx_hist:
986                     found = True
987                     break
988
989             if not found:
990                 tx = self.transactions.get(tx_hash)
991                 # tx might not be there
992                 if not tx: continue
993                 
994                 # already verified?
995                 if self.verifier.get_height(tx_hash):
996                     continue
997                 # unconfirmed tx
998                 print_error("new history is orphaning transaction:", tx_hash)
999                 # check that all outputs are not mine, request histories
1000                 ext_requests = []
1001                 for _addr, _v in tx.outputs:
1002                     # assert not self.is_mine(_addr)
1003                     ext_requests.append( ('blockchain.address.get_history', [_addr]) )
1004
1005                 ext_h = self.network.synchronous_get(ext_requests)
1006                 print_error("sync:", ext_requests, ext_h)
1007                 height = None
1008                 for h in ext_h:
1009                     if h == ['*']: continue
1010                     for item in h:
1011                         if item.get('tx_hash') == tx_hash:
1012                             height = item.get('height')
1013                 if height:
1014                     print_error("found height for", tx_hash, height)
1015                     self.verifier.add(tx_hash, height)
1016                 else:
1017                     print_error("removing orphaned tx from history", tx_hash)
1018                     self.transactions.pop(tx_hash)
1019
1020         return True
1021
1022
1023     def check_new_tx(self, tx_hash, tx):
1024         # 1 check that tx is referenced in addr_history. 
1025         addresses = []
1026         for addr, hist in self.history.items():
1027             if hist == ['*']:continue
1028             for txh, height in hist:
1029                 if txh == tx_hash: 
1030                     addresses.append(addr)
1031
1032         if not addresses:
1033             return False
1034
1035         # 2 check that referencing addresses are in the tx
1036         for addr in addresses:
1037             if not tx.has_address(addr):
1038                 return False
1039
1040         return True
1041
1042
1043     def start_threads(self, network):
1044         from verifier import TxVerifier
1045         self.network = network
1046         if self.network is not None:
1047             self.verifier = TxVerifier(self.network, self.storage)
1048             self.verifier.start()
1049             self.set_verifier(self.verifier)
1050             self.synchronizer = WalletSynchronizer(self, network)
1051             self.synchronizer.start()
1052         else:
1053             self.verifier = None
1054             self.synchronizer =None
1055
1056     def stop_threads(self):
1057         if self.network:
1058             self.verifier.stop()
1059             self.synchronizer.stop()
1060
1061     def restore(self, cb):
1062         pass
1063
1064     def get_accounts(self):
1065         return self.accounts
1066
1067     def save_accounts(self):
1068         d = {}
1069         for k, v in self.accounts.items():
1070             d[k] = v.dump()
1071         self.storage.put('accounts', d, True)
1072
1073     def can_import(self):
1074         return not self.is_watching_only()
1075
1076     
1077
1078 class Imported_Wallet(Abstract_Wallet):
1079
1080     def __init__(self, storage):
1081         Abstract_Wallet.__init__(self, storage)
1082         a = self.accounts.get(IMPORTED_ACCOUNT)
1083         if not a:
1084             self.accounts[IMPORTED_ACCOUNT] = ImportedAccount({'imported':{}})
1085
1086
1087     def is_watching_only(self):
1088         acc = self.accounts[IMPORTED_ACCOUNT]
1089         n = acc.keypairs.values()
1090         return n == [(None, None)] * len(n)
1091
1092     def has_seed(self):
1093         return False
1094
1095     def is_deterministic(self):
1096         return False
1097
1098     def check_password(self, password):
1099         self.accounts[IMPORTED_ACCOUNT].get_private_key((0,0), self, password)
1100
1101
1102
1103 class Deterministic_Wallet(Abstract_Wallet):
1104
1105     def __init__(self, storage):
1106         Abstract_Wallet.__init__(self, storage)
1107
1108     def has_seed(self):
1109         return self.seed != ''
1110
1111     def is_deterministic(self):
1112         return True
1113
1114     def is_watching_only(self):
1115         return not self.has_seed()
1116
1117     def add_seed(self, seed, password):
1118         if self.seed: 
1119             raise Exception("a seed exists")
1120         
1121         self.seed_version, self.seed = self.prepare_seed(seed)
1122         if password: 
1123             self.seed = pw_encode( self.seed, password)
1124             self.use_encryption = True
1125         else:
1126             self.use_encryption = False
1127
1128         self.storage.put('seed', self.seed, True)
1129         self.storage.put('seed_version', self.seed_version, True)
1130         self.storage.put('use_encryption', self.use_encryption,True)
1131         self.create_master_keys(password)
1132
1133     def get_seed(self, password):
1134         return pw_decode(self.seed, password)
1135
1136     def get_mnemonic(self, password):
1137         return self.get_seed(password)
1138         
1139     def change_gap_limit(self, value):
1140         if value >= self.gap_limit:
1141             self.gap_limit = value
1142             self.storage.put('gap_limit', self.gap_limit, True)
1143             #self.interface.poke('synchronizer')
1144             return True
1145
1146         elif value >= self.min_acceptable_gap():
1147             for key, account in self.accounts.items():
1148                 addresses = account[0]
1149                 k = self.num_unused_trailing_addresses(addresses)
1150                 n = len(addresses) - k + value
1151                 addresses = addresses[0:n]
1152                 self.accounts[key][0] = addresses
1153
1154             self.gap_limit = value
1155             self.storage.put('gap_limit', self.gap_limit, True)
1156             self.save_accounts()
1157             return True
1158         else:
1159             return False
1160
1161     def num_unused_trailing_addresses(self, addresses):
1162         k = 0
1163         for a in addresses[::-1]:
1164             if self.history.get(a):break
1165             k = k + 1
1166         return k
1167
1168     def min_acceptable_gap(self):
1169         # fixme: this assumes wallet is synchronized
1170         n = 0
1171         nmax = 0
1172
1173         for account in self.accounts.values():
1174             addresses = account.get_addresses(0)
1175             k = self.num_unused_trailing_addresses(addresses)
1176             for a in addresses[0:-k]:
1177                 if self.history.get(a):
1178                     n = 0
1179                 else:
1180                     n += 1
1181                     if n > nmax: nmax = n
1182         return nmax + 1
1183
1184
1185     def address_is_old(self, address):
1186         age = -1
1187         h = self.history.get(address, [])
1188         if h == ['*']:
1189             return True
1190         for tx_hash, tx_height in h:
1191             if tx_height == 0:
1192                 tx_age = 0
1193             else:
1194                 tx_age = self.network.get_local_height() - tx_height + 1
1195             if tx_age > age:
1196                 age = tx_age
1197         return age > 2
1198
1199
1200     def synchronize_sequence(self, account, for_change):
1201         limit = self.gap_limit_for_change if for_change else self.gap_limit
1202         new_addresses = []
1203         while True:
1204             addresses = account.get_addresses(for_change)
1205             if len(addresses) < limit:
1206                 address = account.create_new_address(for_change)
1207                 self.history[address] = []
1208                 new_addresses.append( address )
1209                 continue
1210
1211             if map( lambda a: self.address_is_old(a), addresses[-limit:] ) == limit*[False]:
1212                 break
1213             else:
1214                 address = account.create_new_address(for_change)
1215                 self.history[address] = []
1216                 new_addresses.append( address )
1217
1218         return new_addresses
1219         
1220
1221     def check_pending_accounts(self):
1222         for account_id, addr in self.next_addresses.items():
1223             if self.address_is_old(addr):
1224                 print_error( "creating account", account_id )
1225                 xpub = self.master_public_keys[account_id]
1226                 account = BIP32_Account({'xpub':xpub})
1227                 self.add_account(account_id, account)
1228                 self.next_addresses.pop(account_id)
1229
1230
1231     def synchronize_account(self, account):
1232         new = []
1233         new += self.synchronize_sequence(account, 0)
1234         new += self.synchronize_sequence(account, 1)
1235         return new
1236
1237
1238     def synchronize(self):
1239         self.check_pending_accounts()
1240         new = []
1241         for account in self.accounts.values():
1242             if type(account) in [ImportedAccount, PendingAccount]:
1243                 continue
1244             new += self.synchronize_account(account)
1245         if new:
1246             self.save_accounts()
1247             self.storage.put('addr_history', self.history, True)
1248         return new
1249
1250
1251     def restore(self, callback):
1252         from i18n import _
1253         def wait_for_wallet():
1254             self.set_up_to_date(False)
1255             while not self.is_up_to_date():
1256                 msg = "%s\n%s %d\n%s %.1f"%(
1257                     _("Please wait..."),
1258                     _("Addresses generated:"),
1259                     len(self.addresses(True)), 
1260                     _("Kilobytes received:"), 
1261                     self.network.interface.bytes_received/1024.)
1262
1263                 apply(callback, (msg,))
1264                 time.sleep(0.1)
1265
1266         def wait_for_network():
1267             while not self.network.is_connected():
1268                 msg = "%s \n" % (_("Connecting..."))
1269                 apply(callback, (msg,))
1270                 time.sleep(0.1)
1271
1272         # wait until we are connected, because the user might have selected another server
1273         if self.network:
1274             wait_for_network()
1275             wait_for_wallet()
1276         else:
1277             self.synchronize()
1278             
1279         self.fill_addressbook()
1280
1281
1282     def create_account(self, name, password):
1283         i = self.num_accounts()
1284         account_id = self.account_id(i)
1285         account = self.make_account(account_id, password)
1286         self.add_account(account_id, account)
1287         if name:
1288             self.set_label(account_id, name)
1289
1290         # add address of the next account
1291         _, _ = self.next_account_address(password)
1292
1293
1294     def add_account(self, account_id, account):
1295         self.accounts[account_id] = account
1296         self.save_accounts()
1297
1298
1299
1300     def account_is_pending(self, k):
1301         return type(self.accounts.get(k)) == PendingAccount
1302
1303     def delete_pending_account(self, k):
1304         assert self.account_is_pending(k)
1305         self.accounts.pop(k)
1306         self.save_accounts()
1307
1308     def create_pending_account(self, name, password):
1309         account_id, addr = self.next_account_address(password)
1310         self.set_label(account_id, name)
1311         self.accounts[account_id] = PendingAccount({'pending':addr})
1312         self.save_accounts()
1313
1314
1315
1316
1317 class NewWallet(Deterministic_Wallet):
1318
1319     def __init__(self, storage):
1320         Deterministic_Wallet.__init__(self, storage)
1321
1322     def can_create_accounts(self):
1323         return not self.is_watching_only()
1324
1325     def get_master_public_key(self):
1326         return self.master_public_keys["m/"]
1327
1328     def get_master_public_keys(self):
1329         out = {}
1330         for k, account in self.accounts.items():
1331             name = self.get_account_name(k)
1332             mpk_text = '\n\n'.join( account.get_master_pubkeys() )
1333             out[name] = mpk_text
1334         return out
1335
1336     def get_master_private_key(self, account, password):
1337         k = self.master_private_keys.get(account)
1338         if not k: return
1339         xpriv = pw_decode( k, password)
1340         return xpriv
1341
1342     def check_password(self, password):
1343         xpriv = self.get_master_private_key( "m/", password )
1344         xpub = self.master_public_keys["m/"]
1345         assert deserialize_xkey(xpriv)[3] == deserialize_xkey(xpub)[3]
1346
1347     def create_watching_only_wallet(self, xpub):
1348         self.storage.put('seed_version', self.seed_version, True)
1349         self.add_master_public_key("m/", xpub)
1350         account = BIP32_Account({'xpub':xpub})
1351         self.add_account("m/", account)
1352
1353
1354     def create_accounts(self, password):
1355         seed = pw_decode(self.seed, password)
1356         self.create_account('Main account', password)
1357
1358
1359     def add_master_public_key(self, name, mpk):
1360         self.master_public_keys[name] = mpk
1361         self.storage.put('master_public_keys', self.master_public_keys, True)
1362
1363
1364     def add_master_private_key(self, name, xpriv, password):
1365         self.master_private_keys[name] = pw_encode(xpriv, password)
1366         self.storage.put('master_private_keys', self.master_private_keys, True)
1367
1368
1369     def add_master_keys(self, root, account_id, password):
1370         x = self.master_private_keys.get(root)
1371         if x: 
1372             master_xpriv = pw_decode(x, password )
1373             xpriv, xpub = bip32_private_derivation(master_xpriv, root, account_id)
1374             self.add_master_public_key(account_id, xpub)
1375             self.add_master_private_key(account_id, xpriv, password)
1376         else:
1377             master_xpub = self.master_public_keys[root]
1378             xpub = bip32_public_derivation(master_xpub, root, account_id)
1379             self.add_master_public_key(account_id, xpub)
1380         return xpub
1381
1382
1383     def create_master_keys(self, password):
1384         xpriv, xpub = bip32_root(mnemonic_to_seed(self.get_seed(password),'').encode('hex'))
1385         self.add_master_public_key("m/", xpub)
1386         self.add_master_private_key("m/", xpriv, password)
1387
1388
1389     def find_root_by_master_key(self, xpub):
1390         for key, xpub2 in self.master_public_keys.items():
1391             if key == "m/":continue
1392             if xpub == xpub2:
1393                 return key
1394
1395
1396     def num_accounts(self):
1397         keys = []
1398         for k, v in self.accounts.items():
1399             if type(v) != BIP32_Account:
1400                 continue
1401             keys.append(k)
1402
1403         i = 0
1404         while True:
1405             account_id = self.account_id(i)
1406             if account_id not in keys: break
1407             i += 1
1408         return i
1409
1410
1411     def next_account_address(self, password):
1412         i = self.num_accounts()
1413         account_id = self.account_id(i)
1414
1415         addr = self.next_addresses.get(account_id)
1416         if not addr: 
1417             account = self.make_account(account_id, password)
1418             addr = account.first_address()
1419             self.next_addresses[account_id] = addr
1420             self.storage.put('next_addresses', self.next_addresses)
1421
1422         return account_id, addr
1423
1424     def account_id(self, i):
1425         return "m/%d'"%i
1426
1427     def make_account(self, account_id, password):
1428         """Creates and saves the master keys, but does not save the account"""
1429         xpub = self.add_master_keys("m/", account_id, password)
1430         account = BIP32_Account({'xpub':xpub})
1431         return account
1432
1433
1434     def make_seed(self):
1435         import mnemonic, ecdsa
1436         entropy = ecdsa.util.randrange( pow(2,160) )
1437         nonce = 0
1438         while True:
1439             ss = "%040x"%(entropy+nonce)
1440             s = hashlib.sha256(ss.decode('hex')).digest().encode('hex')
1441             # we keep only 13 words, that's approximately 139 bits of entropy
1442             words = mnemonic.mn_encode(s)[0:13] 
1443             seed = ' '.join(words)
1444             if is_new_seed(seed):
1445                 break  # this will remove 8 bits of entropy
1446             nonce += 1
1447         return seed
1448
1449     def prepare_seed(self, seed):
1450         import unicodedata
1451         return NEW_SEED_VERSION, unicodedata.normalize('NFC', unicode(seed.strip()))
1452
1453
1454
1455 class Wallet_2of2(NewWallet):
1456
1457     def __init__(self, storage):
1458         NewWallet.__init__(self, storage)
1459         self.storage.put('wallet_type', '2of2', True)
1460
1461     def can_create_accounts(self):
1462         return False
1463
1464     def can_import(self):
1465         return False
1466
1467     def create_account(self):
1468         xpub1 = self.master_public_keys.get("m/")
1469         xpub2 = self.master_public_keys.get("cold/")
1470         account = BIP32_Account_2of2({'xpub':xpub1, 'xpub2':xpub2})
1471         self.add_account('m/', account)
1472
1473     def get_master_public_keys(self):
1474         xpub1 = self.master_public_keys.get("m/")
1475         xpub2 = self.master_public_keys.get("cold/")
1476         return {'hot':xpub1, 'cold':xpub2}
1477
1478     def get_action(self):
1479         xpub1 = self.master_public_keys.get("m/")
1480         xpub2 = self.master_public_keys.get("cold/")
1481         if xpub1 is None:
1482             return 'create_2of2_1'
1483         if xpub2 is None:
1484             return 'create_2of2_2'
1485
1486
1487
1488 class Wallet_2of3(Wallet_2of2):
1489
1490     def __init__(self, storage):
1491         Wallet_2of2.__init__(self, storage)
1492         self.storage.put('wallet_type', '2of3', True)
1493
1494     def create_account(self):
1495         xpub1 = self.master_public_keys.get("m/")
1496         xpub2 = self.master_public_keys.get("cold/")
1497         xpub3 = self.master_public_keys.get("remote/")
1498         account = BIP32_Account_2of3({'xpub':xpub1, 'xpub2':xpub2, 'xpub3':xpub3})
1499         self.add_account('m/', account)
1500
1501     def get_master_public_keys(self):
1502         xpub1 = self.master_public_keys.get("m/")
1503         xpub2 = self.master_public_keys.get("cold/")
1504         xpub3 = self.master_public_keys.get("remote/")
1505         return {'hot':xpub1, 'cold':xpub2, 'remote':xpub3}
1506
1507     def get_action(self):
1508         xpub1 = self.master_public_keys.get("m/")
1509         xpub2 = self.master_public_keys.get("cold/")
1510         xpub3 = self.master_public_keys.get("remote/")
1511         if xpub2 is None:
1512             return 'create_2of3_1'
1513         if xpub1 is None:
1514             return 'create_2of3_2'
1515         if xpub3 is None:
1516             return 'create_2of3_3'
1517
1518
1519
1520
1521
1522 class OldWallet(Deterministic_Wallet):
1523
1524     def make_seed(self):
1525         import mnemonic
1526         seed = random_seed(128)
1527         return ' '.join(mnemonic.mn_encode(seed))
1528
1529     def prepare_seed(self, seed):
1530         import mnemonic
1531         # see if seed was entered as hex
1532         seed = seed.strip()
1533         try:
1534             assert seed
1535             seed.decode('hex')
1536             return OLD_SEED_VERSION, str(seed)
1537         except Exception:
1538             pass
1539
1540         words = seed.split()
1541         seed = mnemonic.mn_decode(words)
1542         if not seed:
1543             raise Exception("Invalid seed")
1544             
1545         return OLD_SEED_VERSION, seed
1546
1547
1548     def create_master_keys(self, password):
1549         seed = pw_decode(self.seed, password)
1550         mpk = OldAccount.mpk_from_seed(seed)
1551         self.storage.put('master_public_key', mpk, True)
1552
1553     def get_master_public_key(self):
1554         return self.storage.get("master_public_key")
1555
1556     def get_master_public_keys(self):
1557         return {'Main Account':self.get_master_public_key()}
1558
1559     def create_accounts(self, password):
1560         mpk = self.storage.get("master_public_key")
1561         self.create_account(mpk)
1562
1563     def create_account(self, mpk):
1564         self.accounts[0] = OldAccount({'mpk':mpk, 0:[], 1:[]})
1565         self.save_accounts()
1566
1567     def create_watching_only_wallet(self, mpk):
1568         self.seed_version = OLD_SEED_VERSION
1569         self.storage.put('seed_version', self.seed_version, True)
1570         self.storage.put('master_public_key', mpk, True)
1571         self.create_account(mpk)
1572
1573     def get_seed(self, password):
1574         seed = pw_decode(self.seed, password).encode('utf8')
1575         return seed
1576
1577     def check_password(self, password):
1578         seed = pw_decode(self.seed, password)
1579         self.accounts[0].check_seed(seed)
1580
1581     def get_mnemonic(self, password):
1582         import mnemonic
1583         s = self.get_seed(password)
1584         return ' '.join(mnemonic.mn_encode(s))
1585
1586
1587     def add_keypairs_from_KeyID(self, tx, keypairs, password):
1588         # first check the provided password
1589         seed = self.get_seed(password)
1590         for txin in tx.inputs:
1591             keyid = txin.get('KeyID')
1592             if keyid:
1593                 m = re.match("old\(([0-9a-f]+),(\d+),(\d+)", keyid)
1594                 if not m: continue
1595                 mpk = m.group(1)
1596                 if mpk != self.storage.get('master_public_key'): continue 
1597                 for_change = int(m.group(2))
1598                 num = int(m.group(3))
1599                 account = self.accounts[0]
1600                 addr = account.get_address(for_change, num)
1601                 txin['address'] = addr # fixme: side effect
1602                 pk = account.get_private_key(seed, (for_change, num))
1603                 pubkey = public_key_from_private_key(pk)
1604                 keypairs[pubkey] = pk
1605
1606
1607
1608     def check_pending_accounts(self):
1609         pass
1610
1611
1612 # former WalletFactory
1613 class Wallet(object):
1614
1615     def __new__(self, storage):
1616         config = storage.config
1617         if config.get('bitkey', False):
1618             # if user requested support for Bitkey device,
1619             # import Bitkey driver
1620             from wallet_bitkey import WalletBitkey
1621             return WalletBitkey(config)
1622
1623         if storage.get('wallet_type') == '2of2':
1624             return Wallet_2of2(storage)
1625
1626         if storage.get('wallet_type') == '2of3':
1627             return Wallet_2of3(storage)
1628
1629         if storage.file_exists and not storage.get('seed'):
1630             # wallet made of imported keys
1631             return Imported_Wallet(storage)
1632
1633
1634         if not storage.file_exists:
1635             seed_version = NEW_SEED_VERSION if config.get('bip32') is True else OLD_SEED_VERSION
1636         else:
1637             seed_version = storage.get('seed_version')
1638             if not seed_version:
1639                 seed_version = OLD_SEED_VERSION if len(storage.get('master_public_key')) == 128 else NEW_SEED_VERSION
1640
1641         if seed_version == OLD_SEED_VERSION:
1642             return OldWallet(storage)
1643         elif seed_version == NEW_SEED_VERSION:
1644             return NewWallet(storage)
1645         else:
1646             msg = "This wallet seed is not supported."
1647             if seed_version in [5]:
1648                 msg += "\nTo open this wallet, try 'git checkout seed_v%d'"%seed_version
1649             print msg
1650             sys.exit(1)
1651
1652
1653
1654     @classmethod
1655     def is_seed(self, seed):
1656         if not seed:
1657             return False
1658         elif is_old_seed(seed):
1659             return True
1660         elif is_new_seed(seed):
1661             return True
1662         else: 
1663             return False
1664
1665     @classmethod
1666     def is_mpk(self, mpk):
1667         try:
1668             int(mpk, 16)
1669             old = True
1670         except:
1671             old = False
1672             
1673         if old:
1674             return len(mpk) == 128
1675         else:
1676             try:
1677                 deserialize_xkey(mpk)
1678                 return True
1679             except:
1680                 return False
1681
1682     @classmethod
1683     def is_address(self, text):
1684         if not text:
1685             return False
1686         for x in text.split():
1687             if not bitcoin.is_address(x):
1688                 return False
1689         return True
1690
1691     @classmethod
1692     def is_private_key(self, text):
1693         if not text:
1694             return False
1695         for x in text.split():
1696             if not bitcoin.is_private_key(x):
1697                 return False
1698         return True
1699
1700     @classmethod
1701     def from_seed(self, seed, storage):
1702         if is_old_seed(seed):
1703             klass = OldWallet
1704         elif is_new_seed(seed):
1705             klass = NewWallet
1706         w = klass(storage)
1707         return w
1708
1709     @classmethod
1710     def from_address(self, text, storage):
1711         w = Imported_Wallet(storage)
1712         for x in text.split():
1713             w.accounts[IMPORTED_ACCOUNT].add(x, None, None, None)
1714         w.save_accounts()
1715         return w
1716
1717     @classmethod
1718     def from_private_key(self, text, storage):
1719         w = Imported_Wallet(storage)
1720         for x in text.split():
1721             w.import_key(x, None)
1722         return w
1723
1724     @classmethod
1725     def from_mpk(self, mpk, storage):
1726
1727         try:
1728             int(mpk, 16)
1729             old = True
1730         except:
1731             old = False
1732
1733         if old:
1734             w = OldWallet(storage)
1735             w.seed = ''
1736             w.create_watching_only_wallet(mpk)
1737         else:
1738             w = NewWallet(storage)
1739             w.create_watching_only_wallet(mpk)
1740
1741         return w