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