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