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