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