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