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