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