URI: 
       tfix recovery procedure - electrum - Electrum Bitcoin wallet
  HTML git clone https://git.parazyd.org/electrum
   DIR Log
   DIR Files
   DIR Refs
   DIR Submodules
       ---
   DIR commit 81bb04378f7f2a0d00ec0c904f110a4dba6f0143
   DIR parent d0dd8c847a2f79c1131e937ebcb8db6394722f57
  HTML Author: ThomasV <thomasv@gitorious>
       Date:   Fri, 30 Mar 2012 14:15:05 +0200
       
       fix recovery procedure
       
       Diffstat:
         M client/gui_qt.py                    |      25 ++++++++-----------------
         M client/interface.py                 |      53 ++++++++++++-------------------
         M client/wallet.py                    |      77 +++++++++++++++++++------------
       
       3 files changed, 76 insertions(+), 79 deletions(-)
       ---
   DIR diff --git a/client/gui_qt.py b/client/gui_qt.py
       t@@ -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)
       t@@ -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)
       t@@ -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:
       t@@ -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:
       t@@ -908,7 +899,7 @@ class ElectrumWindow(QMainWindow):
                    else:
                        return
        
       -        wallet.set_server(host, port, protocol) 
       +        wallet.set_server(server)
                return True
        
        
   DIR diff --git a/client/interface.py b/client/interface.py
       t@@ -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)
       t@@ -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)
        
        
       t@@ -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:
       t@@ -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
       t@@ -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]
       t@@ -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})
        
        
       t@@ -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:
       t@@ -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
        
       t@@ -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 = ''
       t@@ -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 )
   DIR diff --git a/client/wallet.py b/client/wallet.py
       t@@ -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
       t@@ -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 = {}
       t@@ -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):
       t@@ -460,7 +463,6 @@ class Wallet:
                    self.addresses.append(address)
        
                self.history[address] = []
       -        self.status[address] = None
                print address
                return address
        
       t@@ -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,
       t@@ -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')
       t@@ -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()
       t@@ -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
        
       t@@ -980,6 +989,7 @@ class Wallet:
        
        
            def update(self):
       +        self.interface.poke()
                self.up_to_date_event.wait()
        
        
       t@@ -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:
       t@@ -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)