wallet.has_seed
[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
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_watching_only(self):
1132         return self.has_seed()
1133
1134     def check_password(self, password):
1135         self.get_seed(password)
1136
1137     def get_seed(self, password):
1138         s = pw_decode(self.seed, password)
1139         seed = mnemonic_to_seed(s,'').encode('hex')
1140         return seed
1141
1142     def get_mnemonic(self, password):
1143         return pw_decode(self.seed, password)
1144         
1145     def change_gap_limit(self, value):
1146         if value >= self.gap_limit:
1147             self.gap_limit = value
1148             self.storage.put('gap_limit', self.gap_limit, True)
1149             #self.interface.poke('synchronizer')
1150             return True
1151
1152         elif value >= self.min_acceptable_gap():
1153             for key, account in self.accounts.items():
1154                 addresses = account[0]
1155                 k = self.num_unused_trailing_addresses(addresses)
1156                 n = len(addresses) - k + value
1157                 addresses = addresses[0:n]
1158                 self.accounts[key][0] = addresses
1159
1160             self.gap_limit = value
1161             self.storage.put('gap_limit', self.gap_limit, True)
1162             self.save_accounts()
1163             return True
1164         else:
1165             return False
1166
1167     def num_unused_trailing_addresses(self, addresses):
1168         k = 0
1169         for a in addresses[::-1]:
1170             if self.history.get(a):break
1171             k = k + 1
1172         return k
1173
1174     def min_acceptable_gap(self):
1175         # fixme: this assumes wallet is synchronized
1176         n = 0
1177         nmax = 0
1178
1179         for account in self.accounts.values():
1180             addresses = account.get_addresses(0)
1181             k = self.num_unused_trailing_addresses(addresses)
1182             for a in addresses[0:-k]:
1183                 if self.history.get(a):
1184                     n = 0
1185                 else:
1186                     n += 1
1187                     if n > nmax: nmax = n
1188         return nmax + 1
1189
1190
1191     def address_is_old(self, address):
1192         age = -1
1193         h = self.history.get(address, [])
1194         if h == ['*']:
1195             return True
1196         for tx_hash, tx_height in h:
1197             if tx_height == 0:
1198                 tx_age = 0
1199             else:
1200                 tx_age = self.network.get_local_height() - tx_height + 1
1201             if tx_age > age:
1202                 age = tx_age
1203         return age > 2
1204
1205
1206     def synchronize_sequence(self, account, for_change):
1207         limit = self.gap_limit_for_change if for_change else self.gap_limit
1208         new_addresses = []
1209         while True:
1210             addresses = account.get_addresses(for_change)
1211             if len(addresses) < limit:
1212                 address = account.create_new_address(for_change)
1213                 self.history[address] = []
1214                 new_addresses.append( address )
1215                 continue
1216
1217             if map( lambda a: self.address_is_old(a), addresses[-limit:] ) == limit*[False]:
1218                 break
1219             else:
1220                 address = account.create_new_address(for_change)
1221                 self.history[address] = []
1222                 new_addresses.append( address )
1223
1224         return new_addresses
1225         
1226
1227     def check_pending_accounts(self):
1228         for account_id, addr in self.next_addresses.items():
1229             if self.address_is_old(addr):
1230                 print_error( "creating account", account_id )
1231                 xpub = self.master_public_keys[account_id]
1232                 account = BIP32_Account({'xpub':xpub})
1233                 self.add_account(account_id, account)
1234                 self.next_addresses.pop(account_id)
1235
1236
1237     def synchronize_account(self, account):
1238         new = []
1239         new += self.synchronize_sequence(account, 0)
1240         new += self.synchronize_sequence(account, 1)
1241         return new
1242
1243
1244     def synchronize(self):
1245         self.check_pending_accounts()
1246         new = []
1247         for account in self.accounts.values():
1248             new += self.synchronize_account(account)
1249         if new:
1250             self.save_accounts()
1251             self.storage.put('addr_history', self.history, True)
1252         return new
1253
1254
1255     def restore(self, callback):
1256         from i18n import _
1257         def wait_for_wallet():
1258             self.set_up_to_date(False)
1259             while not self.is_up_to_date():
1260                 msg = "%s\n%s %d\n%s %.1f"%(
1261                     _("Please wait..."),
1262                     _("Addresses generated:"),
1263                     len(self.addresses(True)), 
1264                     _("Kilobytes received:"), 
1265                     self.network.interface.bytes_received/1024.)
1266
1267                 apply(callback, (msg,))
1268                 time.sleep(0.1)
1269
1270         def wait_for_network():
1271             while not self.network.is_connected():
1272                 msg = "%s \n" % (_("Connecting..."))
1273                 apply(callback, (msg,))
1274                 time.sleep(0.1)
1275
1276         # wait until we are connected, because the user might have selected another server
1277         if self.network:
1278             wait_for_network()
1279             wait_for_wallet()
1280         else:
1281             self.synchronize()
1282             
1283         self.fill_addressbook()
1284
1285
1286     def create_account(self, name, password):
1287         i = self.num_accounts()
1288         account_id = self.account_id(i)
1289         account = self.make_account(account_id, password)
1290         self.add_account(account_id, account)
1291         if name:
1292             self.set_label(account_id, name)
1293
1294         # add address of the next account
1295         _, _ = self.next_account_address(password)
1296
1297
1298     def add_account(self, account_id, account):
1299         self.accounts[account_id] = account
1300         if account_id in self.pending_accounts:
1301             self.pending_accounts.pop(account_id)
1302             self.storage.put('pending_accounts', self.pending_accounts)
1303         self.save_accounts()
1304
1305
1306     def save_accounts(self):
1307         d = {}
1308         for k, v in self.accounts.items():
1309             d[k] = v.dump()
1310         self.storage.put('accounts', d, True)
1311
1312     
1313
1314     def load_accounts(self):
1315         d = self.storage.get('accounts', {})
1316         self.accounts = {}
1317         for k, v in d.items():
1318             if k == 0:
1319                 v['mpk'] = self.storage.get('master_public_key')
1320                 self.accounts[k] = OldAccount(v)
1321             elif v.get('xpub3'):
1322                 self.accounts[k] = BIP32_Account_2of3(v)
1323             elif v.get('xpub2'):
1324                 self.accounts[k] = BIP32_Account_2of2(v)
1325             elif v.get('xpub'):
1326                 self.accounts[k] = BIP32_Account(v)
1327             else:
1328                 raise
1329
1330         self.pending_accounts = self.storage.get('pending_accounts',{})
1331
1332
1333     def delete_pending_account(self, k):
1334         self.pending_accounts.pop(k)
1335         self.storage.put('pending_accounts', self.pending_accounts)
1336
1337     def account_is_pending(self, k):
1338         return k in self.pending_accounts
1339
1340     def create_pending_account(self, name, password):
1341         account_id, addr = self.next_account_address(password)
1342         self.set_label(account_id, name)
1343         self.pending_accounts[account_id] = addr
1344         self.storage.put('pending_accounts', self.pending_accounts)
1345
1346     def get_pending_accounts(self):
1347         return self.pending_accounts.items()
1348
1349
1350
1351 class NewWallet(Deterministic_Wallet):
1352
1353     def __init__(self, storage):
1354         Deterministic_Wallet.__init__(self, storage)
1355
1356     def can_create_accounts(self):
1357         return not self.is_watching_only()
1358
1359     def get_master_public_key(self):
1360         return self.master_public_keys["m/"]
1361
1362     def get_master_public_keys(self):
1363         out = {}
1364         for k, account in self.accounts.items():
1365             name = self.get_account_name(k)
1366             mpk_text = '\n\n'.join( account.get_master_pubkeys() )
1367             out[name] = mpk_text
1368         return out
1369
1370     def get_master_private_key(self, account, password):
1371         k = self.master_private_keys.get(account)
1372         if not k: return
1373         xpriv = pw_decode( k, password)
1374         return xpriv
1375
1376     def add_seed(self, seed, password):
1377         if self.seed: 
1378             raise Exception("a seed exists")
1379         
1380         self.seed_version, self.seed = self.prepare_seed(seed)
1381         if password: 
1382             self.seed = pw_encode( self.seed, password)
1383             self.use_encryption = True
1384         else:
1385             self.use_encryption = False
1386
1387         self.storage.put('seed', self.seed, True)
1388         self.storage.put('seed_version', self.seed_version, True)
1389         self.storage.put('use_encryption', self.use_encryption,True)
1390         self.create_master_keys(password)
1391
1392
1393     def create_watching_only_wallet(self, xpub):
1394         self.storage.put('seed_version', self.seed_version, True)
1395         self.add_master_public_key("m/", xpub)
1396         account = BIP32_Account({'xpub':xpub})
1397         self.add_account("m/", account)
1398
1399
1400     def create_accounts(self, password):
1401         seed = pw_decode(self.seed, password)
1402         self.create_account('Main account', password)
1403
1404
1405     def add_master_public_key(self, name, mpk):
1406         self.master_public_keys[name] = mpk
1407         self.storage.put('master_public_keys', self.master_public_keys, True)
1408
1409
1410     def add_master_private_key(self, name, xpriv, password):
1411         self.master_private_keys[name] = pw_encode(xpriv, password)
1412         self.storage.put('master_private_keys', self.master_private_keys, True)
1413
1414
1415     def add_master_keys(self, root, account_id, password):
1416         x = self.master_private_keys.get(root)
1417         if x: 
1418             master_xpriv = pw_decode(x, password )
1419             xpriv, xpub = bip32_private_derivation(master_xpriv, root, account_id)
1420             self.add_master_public_key(account_id, xpub)
1421             self.add_master_private_key(account_id, xpriv, password)
1422         else:
1423             master_xpub = self.master_public_keys[root]
1424             xpub = bip32_public_derivation(master_xpub, root, account_id)
1425             self.add_master_public_key(account_id, xpub)
1426         return xpub
1427
1428
1429     def create_master_keys(self, password):
1430         xpriv, xpub = bip32_root(self.get_seed(password))
1431         self.add_master_public_key("m/", xpub)
1432         self.add_master_private_key("m/", xpriv, password)
1433
1434
1435     def find_root_by_master_key(self, xpub):
1436         for key, xpub2 in self.master_public_keys.items():
1437             if key == "m/":continue
1438             if xpub == xpub2:
1439                 return key
1440
1441
1442     def num_accounts(self):
1443         keys = self.accounts.keys()
1444         i = 0
1445         while True:
1446             account_id = self.account_id(i)
1447             if account_id not in keys: break
1448             i += 1
1449         return i
1450
1451
1452     def next_account_address(self, password):
1453         i = self.num_accounts()
1454         account_id = self.account_id(i)
1455
1456         addr = self.next_addresses.get(account_id)
1457         if not addr: 
1458             account = self.make_account(account_id, password)
1459             addr = account.first_address()
1460             self.next_addresses[account_id] = addr
1461             self.storage.put('next_addresses', self.next_addresses)
1462
1463         return account_id, addr
1464
1465     def account_id(self, i):
1466         return "m/%d'"%i
1467
1468     def make_account(self, account_id, password):
1469         """Creates and saves the master keys, but does not save the account"""
1470         xpub = self.add_master_keys("m/", account_id, password)
1471         account = BIP32_Account({'xpub':xpub})
1472         return account
1473
1474
1475     def make_seed(self):
1476         import mnemonic, ecdsa
1477         entropy = ecdsa.util.randrange( pow(2,160) )
1478         nonce = 0
1479         while True:
1480             ss = "%040x"%(entropy+nonce)
1481             s = hashlib.sha256(ss.decode('hex')).digest().encode('hex')
1482             # we keep only 13 words, that's approximately 139 bits of entropy
1483             words = mnemonic.mn_encode(s)[0:13] 
1484             seed = ' '.join(words)
1485             if is_new_seed(seed):
1486                 break  # this will remove 8 bits of entropy
1487             nonce += 1
1488         return seed
1489
1490     def prepare_seed(self, seed):
1491         import unicodedata
1492         return NEW_SEED_VERSION, unicodedata.normalize('NFC', unicode(seed.strip()))
1493
1494
1495
1496 class Wallet_2of2(NewWallet):
1497
1498     def __init__(self, storage):
1499         NewWallet.__init__(self, storage)
1500         self.storage.put('wallet_type', '2of2', True)
1501
1502     def create_account(self):
1503         xpub1 = self.master_public_keys.get("m/")
1504         xpub2 = self.master_public_keys.get("cold/")
1505         account = BIP32_Account_2of2({'xpub':xpub1, 'xpub2':xpub2})
1506         self.add_account('m/', account)
1507
1508     def get_master_public_keys(self):
1509         xpub1 = self.master_public_keys.get("m/")
1510         xpub2 = self.master_public_keys.get("cold/")
1511         return {'hot':xpub1, 'cold':xpub2}
1512
1513     def get_action(self):
1514         xpub1 = self.master_public_keys.get("m/")
1515         xpub2 = self.master_public_keys.get("cold/")
1516         if xpub1 is None:
1517             return 'create_2of2_1'
1518         if xpub2 is None:
1519             return 'create_2of2_2'
1520
1521
1522
1523 class Wallet_2of3(Wallet_2of2):
1524
1525     def __init__(self, storage):
1526         Wallet_2of2.__init__(self, storage)
1527         self.storage.put('wallet_type', '2of3', True)
1528
1529     def create_account(self):
1530         xpub1 = self.master_public_keys.get("m/")
1531         xpub2 = self.master_public_keys.get("cold/")
1532         xpub3 = self.master_public_keys.get("remote/")
1533         account = BIP32_Account_2of3({'xpub':xpub1, 'xpub2':xpub2, 'xpub3':xpub3})
1534         self.add_account('m/', account)
1535
1536     def get_master_public_keys(self):
1537         xpub1 = self.master_public_keys.get("m/")
1538         xpub2 = self.master_public_keys.get("cold/")
1539         xpub3 = self.master_public_keys.get("remote/")
1540         return {'hot':xpub1, 'cold':xpub2, 'remote':xpub3}
1541
1542     def get_action(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         if xpub2 is None:
1547             return 'create_2of3_1'
1548         if xpub1 is None:
1549             return 'create_2of3_2'
1550         if xpub3 is None:
1551             return 'create_2of3_3'
1552
1553
1554
1555
1556
1557 class OldWallet(Deterministic_Wallet):
1558
1559     def make_seed(self):
1560         import mnemonic
1561         seed = random_seed(128)
1562         return ' '.join(mnemonic.mn_encode(seed))
1563
1564     def prepare_seed(self, seed):
1565         import mnemonic
1566         # see if seed was entered as hex
1567         seed = seed.strip()
1568         try:
1569             assert seed
1570             seed.decode('hex')
1571             return OLD_SEED_VERSION, str(seed)
1572         except Exception:
1573             pass
1574
1575         words = seed.split()
1576         seed = mnemonic.mn_decode(words)
1577         if not seed:
1578             raise Exception("Invalid seed")
1579             
1580         return OLD_SEED_VERSION, seed
1581
1582
1583     def create_master_keys(self, password):
1584         seed = pw_decode(self.seed, password)
1585         mpk = OldAccount.mpk_from_seed(seed)
1586         self.storage.put('master_public_key', mpk, True)
1587
1588     def get_master_public_key(self):
1589         return self.storage.get("master_public_key")
1590
1591     def get_master_public_keys(self):
1592         return {'Main Account':self.get_master_public_key()}
1593
1594     def create_accounts(self, password):
1595         mpk = self.storage.get("master_public_key")
1596         self.create_account(mpk)
1597
1598     def create_account(self, mpk):
1599         self.accounts[0] = OldAccount({'mpk':mpk, 0:[], 1:[]})
1600         self.save_accounts()
1601
1602     def create_watching_only_wallet(self, mpk):
1603         self.seed_version = OLD_SEED_VERSION
1604         self.storage.put('seed_version', self.seed_version, True)
1605         self.storage.put('master_public_key', mpk, True)
1606         self.create_account(mpk)
1607
1608     def get_seed(self, password):
1609         seed = pw_decode(self.seed, password)
1610         self.accounts[0].check_seed(seed)
1611         return seed
1612
1613     def get_mnemonic(self, password):
1614         import mnemonic
1615         s = pw_decode(self.seed, password)
1616         return ' '.join(mnemonic.mn_encode(s))
1617
1618
1619     def add_keypairs_from_KeyID(self, tx, keypairs, password):
1620         # first check the provided password
1621         seed = self.get_seed(password)
1622         for txin in tx.inputs:
1623             keyid = txin.get('KeyID')
1624             if keyid:
1625                 m = re.match("old\(([0-9a-f]+),(\d+),(\d+)", keyid)
1626                 if not m: continue
1627                 mpk = m.group(1)
1628                 if mpk != self.storage.get('master_public_key'): continue 
1629                 for_change = int(m.group(2))
1630                 num = int(m.group(3))
1631                 account = self.accounts[0]
1632                 addr = account.get_address(for_change, num)
1633                 txin['address'] = addr # fixme: side effect
1634                 pk = account.get_private_key(seed, (for_change, num))
1635                 pubkey = public_key_from_private_key(pk)
1636                 keypairs[pubkey] = pk
1637
1638
1639     def get_account_name(self, k):
1640         assert k == 0
1641         return 'Main account'
1642
1643
1644     def get_private_key(self, address, password):
1645         if self.is_watching_only():
1646             return []
1647
1648         # first check the provided password
1649         seed = self.get_seed(password)
1650         
1651         out = []
1652         if address in self.imported_keys.keys():
1653             out.append( pw_decode( self.imported_keys[address], password ) )
1654         else:
1655             account_id, sequence = self.get_address_index(address)
1656             pk = self.accounts[0].get_private_key(seed, sequence)
1657             out.append(pk)
1658         return out
1659
1660     def check_pending_accounts(self):
1661         pass
1662
1663
1664 # former WalletFactory
1665 class Wallet(object):
1666
1667     def __new__(self, storage):
1668         config = storage.config
1669         if config.get('bitkey', False):
1670             # if user requested support for Bitkey device,
1671             # import Bitkey driver
1672             from wallet_bitkey import WalletBitkey
1673             return WalletBitkey(config)
1674
1675         if storage.get('wallet_type') == '2of2':
1676             return Wallet_2of2(storage)
1677
1678         if storage.get('wallet_type') == '2of3':
1679             return Wallet_2of3(storage)
1680
1681         if storage.file_exists and not storage.get('seed'):
1682             # wallet made of imported keys
1683             return Imported_Wallet(storage)
1684
1685
1686         if not storage.file_exists:
1687             seed_version = NEW_SEED_VERSION if config.get('bip32') is True else OLD_SEED_VERSION
1688         else:
1689             seed_version = storage.get('seed_version')
1690             if not seed_version:
1691                 seed_version = OLD_SEED_VERSION if len(storage.get('master_public_key')) == 128 else NEW_SEED_VERSION
1692
1693         if seed_version == OLD_SEED_VERSION:
1694             return OldWallet(storage)
1695         elif seed_version == NEW_SEED_VERSION:
1696             return NewWallet(storage)
1697         else:
1698             msg = "This wallet seed is not supported."
1699             if seed_version in [5]:
1700                 msg += "\nTo open this wallet, try 'git checkout seed_v%d'"%seed_version
1701             print msg
1702             sys.exit(1)
1703
1704
1705
1706     @classmethod
1707     def is_seed(self, seed):
1708         if not seed:
1709             return False
1710         elif is_old_seed(seed):
1711             return True
1712         elif is_new_seed(seed):
1713             return True
1714         else: 
1715             return False
1716
1717     @classmethod
1718     def is_mpk(self, mpk):
1719         try:
1720             int(mpk, 16)
1721             old = True
1722         except:
1723             old = False
1724             
1725         if old:
1726             return len(mpk) == 128
1727         else:
1728             try:
1729                 deserialize_xkey(mpk)
1730                 return True
1731             except:
1732                 return False
1733
1734     @classmethod
1735     def is_address(self, text):
1736         for x in text.split():
1737             if not bitcoin.is_address(x):
1738                 return False
1739         return True
1740
1741     @classmethod
1742     def is_private_key(self, text):
1743         for x in text.split():
1744             if not bitcoin.is_private_key(x):
1745                 return False
1746         return True
1747
1748     @classmethod
1749     def from_seed(self, seed, storage):
1750         if is_old_seed(seed):
1751             klass = OldWallet
1752         elif is_new_seed(seed):
1753             klass = NewWallet
1754         w = klass(storage)
1755         return w
1756
1757     @classmethod
1758     def from_address(self, text, storage):
1759         w = Imported_Wallet(storage)
1760         for x in text.split():
1761             w.imported_keys[x] = ''
1762         w.storage.put('imported_keys', w.imported_keys, True)
1763         return w
1764
1765     @classmethod
1766     def from_private_key(self, text, storage):
1767         w = Imported_Wallet(storage)
1768         for x in text.split():
1769             w.import_key(x, None)
1770         return w
1771
1772     @classmethod
1773     def from_mpk(self, mpk, storage):
1774
1775         try:
1776             int(mpk, 16)
1777             old = True
1778         except:
1779             old = False
1780
1781         if old:
1782             w = OldWallet(storage)
1783             w.seed = ''
1784             w.create_watching_only_wallet(mpk)
1785         else:
1786             w = NewWallet(storage)
1787             w.create_watching_only_wallet(mpk)
1788
1789         return w