electrum

Electrum Bitcoin wallet
git clone https://git.parazyd.org/electrum
Log | Files | Refs | Submodules

commit 81bb04378f7f2a0d00ec0c904f110a4dba6f0143
parent d0dd8c847a2f79c1131e937ebcb8db6394722f57
Author: ThomasV <thomasv@gitorious>
Date:   Fri, 30 Mar 2012 14:15:05 +0200

fix recovery procedure

Diffstat:
Mclient/gui_qt.py | 25++++++++-----------------
Mclient/interface.py | 53++++++++++++++++++++---------------------------------
Mclient/wallet.py | 77++++++++++++++++++++++++++++++++++++++++++++++++-----------------------------
3 files changed, 76 insertions(+), 79 deletions(-)

diff --git a/client/gui_qt.py b/client/gui_qt.py @@ -839,15 +839,11 @@ class ElectrumWindow(QMainWindow): status = "Connected to %s:%d\n%d blocks\nresponse time: %f"%(interface.host, interface.port, wallet.blocks, interface.rtime) else: status = "Not connected" - host = wallet.host - port = wallet.port - protocol = wallet.protocol + server = wallet.server else: import random status = "Please choose a server." - host = random.choice( interface.servers ) - port = wallet.port - protocol = 's' + server = random.choice( interface.servers ) d = QDialog(parent) d.setModal(1) @@ -867,7 +863,7 @@ class ElectrumWindow(QMainWindow): hbox = QHBoxLayout() host_line = QLineEdit() - host_line.setText("%s:%d:%s"% (host,port,protocol) ) + host_line.setText(server) hbox.addWidget(QLabel('Connect to:')) hbox.addWidget(host_line) vbox.addLayout(hbox) @@ -877,7 +873,7 @@ class ElectrumWindow(QMainWindow): servers_list.setHeaderLabels( [ 'Active servers'] ) servers_list.setMaximumHeight(150) for item in wallet.interface.servers: - servers_list.addTopLevelItem(QTreeWidgetItem( [ item[1] + ':' + item[0] ] )) + servers_list.addTopLevelItem(QTreeWidgetItem( [ item ] )) servers_list.connect(servers_list, SIGNAL('itemClicked(QTreeWidgetItem*, int)'), lambda x:host_line.setText( x.text(0) )) vbox.addWidget(servers_list) else: @@ -891,16 +887,11 @@ class ElectrumWindow(QMainWindow): d.setLayout(vbox) if not d.exec_(): return - hh = unicode( host_line.text() ) + server = unicode( host_line.text() ) try: - if ':' in hh: - host, port, protocol = hh.split(':') - port = int(port) - else: - host = hh - port = wallet.port - protocol = wallet.protocol + a,b,c = server.split(':') + b = int(b) except: QMessageBox.information(None, 'Error', 'error', 'OK') if parent == None: @@ -908,7 +899,7 @@ class ElectrumWindow(QMainWindow): else: return - wallet.set_server(host, port, protocol) + wallet.set_server(server) return True diff --git a/client/interface.py b/client/interface.py @@ -42,20 +42,15 @@ class Interface: self.rtime = 0 self.is_connected = True - - #only asynchrnous - self.addresses_waiting_for_status = [] - self.addresses_waiting_for_history = [] + self.poll_interval = 1 #json self.message_id = 0 self.responses = Queue.Queue() - - def is_up_to_date(self): - return self.responses.empty() and not ( self.addresses_waiting_for_status or self.addresses_waiting_for_history ) - - + def poke(self): + # push a fake response so that the getting thread exits its loop + self.responses.put(None) def queue_json_response(self, c): #print repr(c) @@ -70,26 +65,13 @@ class Interface: if error: print "received error:", c, method, params else: - self.update_waiting_lists(method, params) self.responses.put({'method':method, 'params':params, 'result':result}) - def update_waiting_lists(self, method, params): - if method == 'blockchain.address.subscribe': - addr = params[-1] - if addr in self.addresses_waiting_for_status: - self.addresses_waiting_for_status.remove(addr) - elif method == 'blockchain.address.get_history': - addr = params[0] - if addr in self.addresses_waiting_for_history: - self.addresses_waiting_for_history.remove(addr) - - def subscribe(self, addresses): messages = [] for addr in addresses: messages.append(('blockchain.address.subscribe', [addr])) - self.addresses_waiting_for_status.append(addr) self.send(messages) @@ -140,11 +122,11 @@ class PollingInterface(Interface): #else: # return False - def poll_thread(self, poll_interval): + def poll_thread(self): while self.is_connected: try: self.poll() - time.sleep(poll_interval) + time.sleep(self.poll_interval) except socket.gaierror: break except socket.error: @@ -166,7 +148,7 @@ class NativeInterface(PollingInterface): def start_session(self, addresses, version): self.send([('session.new', [ version, addresses ])] ) self.send([('server.peers.subscribe',[])]) - thread.start_new_thread(self.poll_thread, (5,)) + thread.start_new_thread(self.poll_thread, ()) def send(self, messages): import time @@ -186,7 +168,7 @@ class NativeInterface(PollingInterface): params = self.session_id if cmd == 'address.subscribe': - params = [ self.session_id] + params + params = [ self.session_id ] + params if cmd in ['h', 'tx']: str_params = params[0] @@ -212,16 +194,16 @@ class NativeInterface(PollingInterface): if cmd == 'h': out = old_to_new(out) - if cmd in[ 'peers','h','poll']: + if cmd in ['peers','h','poll']: out = ast.literal_eval( out ) - if out=='': out=None #fixme + if out == '': + out = None if cmd == 'new_session': self.session_id, msg = ast.literal_eval( out ) self.responses.put({'method':'server.banner', 'params':[], 'result':msg}) else: - self.update_waiting_lists(method, params) self.responses.put({'method':method, 'params':params, 'result':out}) @@ -231,7 +213,7 @@ class HttpInterface(PollingInterface): def start(self): self.session_id = None - thread.start_new_thread(self.poll_thread, (15,)) + thread.start_new_thread(self.poll_thread, ()) def poll(self): if self.session_id: @@ -280,6 +262,13 @@ class HttpInterface(PollingInterface): for item in response: self.queue_json_response(item) + if response: + self.poll_interval = 1 + else: + if self.poll_interval < 15: + self.poll_interval += 1 + #print self.poll_interval, response + self.rtime = time.time() - t1 self.is_connected = True @@ -313,8 +302,7 @@ class AsynchronousInterface(Interface): traceback.print_exc(file=sys.stdout) self.is_connected = False - # push None so that the getting thread exits its loop - self.responses.put(None) + self.poke() def send(self, messages): out = '' @@ -327,7 +315,6 @@ class AsynchronousInterface(Interface): def get_history(self, addr): self.send([('blockchain.address.get_history', [addr])]) - self.addresses_waiting_for_history.append(addr) def start(self): self.s = socket.socket( socket.AF_INET, socket.SOCK_STREAM ) diff --git a/client/wallet.py b/client/wallet.py @@ -251,7 +251,6 @@ class Wallet: self.addresses = [] # receiving addresses visible for user self.change_addresses = [] # addresses used as change self.seed = '' # encrypted - self.status = {} # current status of addresses self.history = {} self.labels = {} # labels for addresses and transactions self.aliases = {} # aliases for addresses @@ -261,9 +260,7 @@ class Wallet: self.receipt = None # next receipt self.addressbook = [] # outgoing addresses, for payments - self.host = random.choice( DEFAULT_SERVERS ) # random choice when the wallet is created - self.port = DEFAULT_PORT - self.protocol = 'n' + self.server = random.choice( DEFAULT_SERVERS ) + ':50000:n' # random choice when the wallet is created # not saved self.tx_history = {} @@ -280,12 +277,18 @@ class Wallet: self.interface_lock = threading.Lock() self.tx_event = threading.Event() + # + self.addresses_waiting_for_status = [] + self.addresses_waiting_for_history = [] - def set_server(self, host, port, protocol): - if host!= self.host or port!=self.port or protocol!=self.protocol: - self.host = host - self.port = port - self.protocol = protocol + + def is_up_to_date(self): + return self.interface.responses.empty() and not ( self.addresses_waiting_for_status or self.addresses_waiting_for_history ) + + + def set_server(self, server): + if server != self.server: + self.server = server self.interface.is_connected = False # this exits the polling loop def set_path(self, wallet_path): @@ -460,7 +463,6 @@ class Wallet: self.addresses.append(address) self.history[address] = [] - self.status[address] = None print address return address @@ -530,13 +532,10 @@ class Wallet: 'use_encryption':self.use_encryption, 'master_public_key': self.master_public_key.encode('hex'), 'fee':self.fee, - 'host':self.host, - 'port':self.port, - 'protocol':self.protocol, + 'server':self.server, 'seed':self.seed, 'addresses':self.addresses, 'change_addresses':self.change_addresses, - 'status':self.status, 'history':self.history, 'labels':self.labels, 'contacts':self.addressbook, @@ -568,13 +567,10 @@ class Wallet: self.use_encryption = d.get('use_encryption') self.fee = int( d.get('fee') ) self.seed = d.get('seed') - self.host = d.get('host') - self.protocol = d.get('protocol','n') - self.port = d.get('port') + self.server = d.get('server') blocks = d.get('blocks') self.addresses = d.get('addresses') self.change_addresses = d.get('change_addresses') - self.status = d.get('status') self.history = d.get('history') self.labels = d.get('labels') self.addressbook = d.get('contacts') @@ -692,17 +688,30 @@ class Wallet: else: return s + def get_status(self, address): + h = self.history.get(address) + if not h: + status = None + else: + lastpoint = h[-1] + status = lastpoint['block_hash'] + if status == 'mempool': + status = status + ':%d'% len(h) + return status + def receive_status_callback(self, addr, status): - if self.status.get(addr) != status: - #print "updating status for", addr, repr(self.status.get(addr)), repr(status) - self.status[addr] = status + if self.get_status(addr) != status: + #print "updating status for", addr, status + self.addresses_waiting_for_history.append(addr) self.interface.get_history(addr) + if addr in self.addresses_waiting_for_status: self.addresses_waiting_for_status.remove(addr) def receive_history_callback(self, addr, data): #print "updating history for", addr self.history[addr] = data self.update_tx_history() self.save() + if addr in self.addresses_waiting_for_history: self.addresses_waiting_for_history.remove(addr) def get_tx_history(self): lines = self.tx_history.values() @@ -948,11 +957,11 @@ class Wallet: if len(item)>2: for v in item[2]: if re.match("[nsh]\d+",v): - s.append((v[0],host+":"+v[1:])) + s.append(host+":"+v[1:]+":"+v[0]) if not s: - s.append(("n",host+":50000")) + s.append(host+":50000:n") else: - s.append(("n",host+":50000")) + s.append(host+":50000:n") servers = servers + s self.interface.servers = servers @@ -980,6 +989,7 @@ class Wallet: def update(self): + self.interface.poke() self.up_to_date_event.wait() @@ -988,7 +998,10 @@ class Wallet: new_addresses = self.synchronize() if new_addresses: self.interface.subscribe(new_addresses) - if self.interface.is_up_to_date() and not new_addresses: + for addr in new_addresses: + self.addresses_waiting_for_status.append(addr) + + if self.is_up_to_date(): self.up_to_date = True self.up_to_date_event.set() else: @@ -999,19 +1012,25 @@ class Wallet: def start_interface(self): - if self.protocol == 'n': + + host, port, protocol = self.server.split(':') + port = int(port) + + if protocol == 'n': InterfaceClass = NativeInterface - elif self.protocol == 's': + elif protocol == 's': InterfaceClass = AsynchronousInterface - elif self.protocol == 'h': + elif protocol == 'h': InterfaceClass = HttpInterface else: print "unknown protocol" InterfaceClass = NativeInterface - self.interface = InterfaceClass(self.host, self.port) + self.interface = InterfaceClass(host, port) addresses = self.all_addresses() version = self.electrum_version + for addr in addresses: + self.addresses_waiting_for_status.append(addr) self.interface.start_session(addresses,version)