URI: 
       tMerge pull request #4541 from haarts/preliminaries - electrum - Electrum Bitcoin wallet
  HTML git clone https://git.parazyd.org/electrum
   DIR Log
   DIR Files
   DIR Refs
   DIR Submodules
       ---
   DIR commit 94dc2149821dcf7df2e9f8532c7175f779378ec3
   DIR parent 358722b9ccd1efed17fe96ea6a78b5c850217a18
  HTML Author: ThomasV <thomasv@electrum.org>
       Date:   Thu, 12 Jul 2018 10:12:45 +0200
       
       Merge pull request #4541 from haarts/preliminaries
       
       Preliminaries
       Diffstat:
         M lib/network.py                      |      23 +++++++++++++----------
         M lib/verifier.py                     |      46 ++++++++++++++++---------------
         M lib/wallet.py                       |       5 +----
       
       3 files changed, 38 insertions(+), 36 deletions(-)
       ---
   DIR diff --git a/lib/network.py b/lib/network.py
       t@@ -78,6 +78,7 @@ def parse_servers(result):
                    servers[host] = out
            return servers
        
       +
        def filter_version(servers):
            def is_recent(version):
                try:
       t@@ -87,7 +88,7 @@ def filter_version(servers):
            return {k: v for k, v in servers.items() if is_recent(v.get('version'))}
        
        
       -def filter_protocol(hostmap, protocol = 's'):
       +def filter_protocol(hostmap, protocol='s'):
            '''Filters the hostmap for those implementing protocol.
            The result is a list in serialized form.'''
            eligible = []
       t@@ -97,12 +98,14 @@ def filter_protocol(hostmap, protocol = 's'):
                    eligible.append(serialize_server(host, port, protocol))
            return eligible
        
       +
        def pick_random_server(hostmap = None, protocol = 's', exclude_set = set()):
            if hostmap is None:
                hostmap = constants.net.DEFAULT_SERVERS
            eligible = list(set(filter_protocol(hostmap, protocol)) - exclude_set)
            return random.choice(eligible) if eligible else None
        
       +
        from .simple_config import SimpleConfig
        
        proxy_modes = ['socks4', 'socks5', 'http']
       t@@ -201,7 +204,7 @@ class Network(util.DaemonThread):
                self.pending_sends = []
                self.message_id = 0
                self.debug = False
       -        self.irc_servers = {} # returned by interface (list from irc)
       +        self.irc_servers = {}  # returned by interface (list from irc)
                self.recent_servers = self.read_recent_servers()  # note: needs self.recent_servers_lock
        
                self.banner = ''
       t@@ -213,7 +216,7 @@ class Network(util.DaemonThread):
                # callbacks set by the GUI
                self.callbacks = defaultdict(list)      # note: needs self.callback_lock
        
       -        dir_path = os.path.join( self.config.path, 'certs')
       +        dir_path = os.path.join(self.config.path, 'certs')
                util.make_dir(dir_path)
        
                # subscriptions and requests
       t@@ -312,9 +315,6 @@ class Network(util.DaemonThread):
            def is_connecting(self):
                return self.connection_status == 'connecting'
        
       -    def is_up_to_date(self):
       -        return self.unanswered_requests == {}
       -
            @with_interface_lock
            def queue_request(self, method, params, interface=None):
                # If you want to queue a request on any interface it must go
       t@@ -406,7 +406,7 @@ class Network(util.DaemonThread):
                        except:
                            continue
                        if host not in out:
       -                    out[host] = { protocol:port }
       +                    out[host] = {protocol: port}
                return out
        
            @with_interface_lock
       t@@ -416,7 +416,7 @@ class Network(util.DaemonThread):
                        self.print_error("connecting to %s as new interface" % server)
                        self.set_status('connecting')
                    self.connecting.add(server)
       -            c = Connection(server, self.socket_queue, self.config.path)
       +            Connection(server, self.socket_queue, self.config.path)
        
            def start_random_interface(self):
                with self.interface_lock:
       t@@ -553,7 +553,7 @@ class Network(util.DaemonThread):
                if self.server_is_lagging() and self.auto_connect:
                    # switch to one that has the correct header (not height)
                    header = self.blockchain().read_header(self.get_local_height())
       -            filtered = list(map(lambda x:x[0], filter(lambda x: x[1].tip_header==header, self.interfaces.items())))
       +            filtered = list(map(lambda x: x[0], filter(lambda x: x[1].tip_header == header, self.interfaces.items())))
                    if filtered:
                        choice = random.choice(filtered)
                        self.switch_to_interface(choice)
       t@@ -569,6 +569,7 @@ class Network(util.DaemonThread):
                    self.interface = None
                    self.start_interface(server)
                    return
       +
                i = self.interfaces[server]
                if self.interface != i:
                    self.print_error("switching to", server)
       t@@ -601,7 +602,7 @@ class Network(util.DaemonThread):
        
            def process_response(self, interface, response, callbacks):
                if self.debug:
       -            self.print_error("<--", response)
       +            self.print_error(interface.host, "<--", response)
                error = response.get('error')
                result = response.get('result')
                method = response.get('method')
       t@@ -798,6 +799,7 @@ class Network(util.DaemonThread):
                    server, socket = self.socket_queue.get()
                    if server in self.connecting:
                        self.connecting.remove(server)
       +
                    if socket:
                        self.new_interface(server, socket)
                    else:
       t@@ -1008,6 +1010,7 @@ class Network(util.DaemonThread):
                    interface.mode = 'default'
                    interface.request = None
                    self.notify('updated')
       +
                # refresh network dialog
                self.notify('interfaces')
        
   DIR diff --git a/lib/verifier.py b/lib/verifier.py
       t@@ -42,42 +42,44 @@ class SPV(ThreadJob):
                interface = self.network.interface
                if not interface:
                    return
       +
                blockchain = interface.blockchain
                if not blockchain:
                    return
       -        lh = self.network.get_local_height()
       +
       +        local_height = self.network.get_local_height()
                unverified = self.wallet.get_unverified_txs()
                for tx_hash, tx_height in unverified.items():
                    # do not request merkle branch before headers are available
       -            if (tx_height > 0) and (tx_height <= lh):
       -                header = blockchain.read_header(tx_height)
       -                if header is None:
       -                    index = tx_height // 2016
       -                    if index < len(blockchain.checkpoints):
       -                        self.network.request_chunk(interface, index)
       -                else:
       -                    if (tx_hash not in self.requested_merkle
       -                            and tx_hash not in self.merkle_roots):
       -
       -                        self.network.get_merkle_for_transaction(
       -                                tx_hash,
       -                                tx_height,
       -                                self.verify_merkle)
       -                        self.print_error('requested merkle', tx_hash)
       -                        self.requested_merkle.add(tx_hash)
       +            if tx_height <= 0 or tx_height > local_height:
       +                continue
       +
       +            header = blockchain.read_header(tx_height)
       +            if header is None:
       +                index = tx_height // 2016
       +                if index < len(blockchain.checkpoints):
       +                    self.network.request_chunk(interface, index)
       +            elif (tx_hash not in self.requested_merkle
       +                    and tx_hash not in self.merkle_roots):
       +                self.network.get_merkle_for_transaction(
       +                        tx_hash,
       +                        tx_height,
       +                        self.verify_merkle)
       +                self.print_error('requested merkle', tx_hash)
       +                self.requested_merkle.add(tx_hash)
        
                if self.network.blockchain() != self.blockchain:
                    self.blockchain = self.network.blockchain()
                    self.undo_verifications()
        
       -    def verify_merkle(self, r):
       +    def verify_merkle(self, response):
                if self.wallet.verifier is None:
                    return  # we have been killed, this was just an orphan callback
       -        if r.get('error'):
       -            self.print_error('received an error:', r)
       +        if response.get('error'):
       +            self.print_error('received an error:', response)
                    return
       -        params = r['params']
       -        merkle = r['result']
       +        params = response['params']
       +        merkle = response['result']
                # Verify the hash of the server-provided merkle branch to a
                # transaction matches the merkle root of its block
                tx_hash = params[0]
   DIR diff --git a/lib/wallet.py b/lib/wallet.py
       t@@ -218,10 +218,7 @@ class Abstract_Wallet(PrintError):
                self.load_unverified_transactions()
                self.remove_local_transactions_we_dont_have()
        
       -        # There is a difference between wallet.up_to_date and network.is_up_to_date().
       -        # network.is_up_to_date() returns true when all requests have been answered and processed
       -        # wallet.up_to_date is true when the wallet is synchronized (stronger requirement)
       -        # Neither of them considers the verifier.
       +        # wallet.up_to_date is true when the wallet is synchronized
                self.up_to_date = False
        
                # save wallet type the first time