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