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