Merge pull request #4541 from haarts/preliminaries

Preliminaries
This commit is contained in:
ThomasV 2018-07-12 10:12:45 +02:00 committed by GitHub
commit 94dc214982
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 37 additions and 35 deletions

View file

@ -78,6 +78,7 @@ def parse_servers(result):
servers[host] = out servers[host] = out
return servers return servers
def filter_version(servers): def filter_version(servers):
def is_recent(version): def is_recent(version):
try: try:
@ -87,7 +88,7 @@ def filter_version(servers):
return {k: v for k, v in servers.items() if is_recent(v.get('version'))} 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. '''Filters the hostmap for those implementing protocol.
The result is a list in serialized form.''' The result is a list in serialized form.'''
eligible = [] eligible = []
@ -97,12 +98,14 @@ def filter_protocol(hostmap, protocol = 's'):
eligible.append(serialize_server(host, port, protocol)) eligible.append(serialize_server(host, port, protocol))
return eligible return eligible
def pick_random_server(hostmap = None, protocol = 's', exclude_set = set()): def pick_random_server(hostmap = None, protocol = 's', exclude_set = set()):
if hostmap is None: if hostmap is None:
hostmap = constants.net.DEFAULT_SERVERS hostmap = constants.net.DEFAULT_SERVERS
eligible = list(set(filter_protocol(hostmap, protocol)) - exclude_set) eligible = list(set(filter_protocol(hostmap, protocol)) - exclude_set)
return random.choice(eligible) if eligible else None return random.choice(eligible) if eligible else None
from .simple_config import SimpleConfig from .simple_config import SimpleConfig
proxy_modes = ['socks4', 'socks5', 'http'] proxy_modes = ['socks4', 'socks5', 'http']
@ -201,7 +204,7 @@ class Network(util.DaemonThread):
self.pending_sends = [] self.pending_sends = []
self.message_id = 0 self.message_id = 0
self.debug = False 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.recent_servers = self.read_recent_servers() # note: needs self.recent_servers_lock
self.banner = '' self.banner = ''
@ -213,7 +216,7 @@ class Network(util.DaemonThread):
# callbacks set by the GUI # callbacks set by the GUI
self.callbacks = defaultdict(list) # note: needs self.callback_lock 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) util.make_dir(dir_path)
# subscriptions and requests # subscriptions and requests
@ -312,9 +315,6 @@ class Network(util.DaemonThread):
def is_connecting(self): def is_connecting(self):
return self.connection_status == 'connecting' return self.connection_status == 'connecting'
def is_up_to_date(self):
return self.unanswered_requests == {}
@with_interface_lock @with_interface_lock
def queue_request(self, method, params, interface=None): def queue_request(self, method, params, interface=None):
# If you want to queue a request on any interface it must go # If you want to queue a request on any interface it must go
@ -406,7 +406,7 @@ class Network(util.DaemonThread):
except: except:
continue continue
if host not in out: if host not in out:
out[host] = { protocol:port } out[host] = {protocol: port}
return out return out
@with_interface_lock @with_interface_lock
@ -416,7 +416,7 @@ class Network(util.DaemonThread):
self.print_error("connecting to %s as new interface" % server) self.print_error("connecting to %s as new interface" % server)
self.set_status('connecting') self.set_status('connecting')
self.connecting.add(server) 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): def start_random_interface(self):
with self.interface_lock: with self.interface_lock:
@ -553,7 +553,7 @@ class Network(util.DaemonThread):
if self.server_is_lagging() and self.auto_connect: if self.server_is_lagging() and self.auto_connect:
# switch to one that has the correct header (not height) # switch to one that has the correct header (not height)
header = self.blockchain().read_header(self.get_local_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: if filtered:
choice = random.choice(filtered) choice = random.choice(filtered)
self.switch_to_interface(choice) self.switch_to_interface(choice)
@ -569,6 +569,7 @@ class Network(util.DaemonThread):
self.interface = None self.interface = None
self.start_interface(server) self.start_interface(server)
return return
i = self.interfaces[server] i = self.interfaces[server]
if self.interface != i: if self.interface != i:
self.print_error("switching to", server) self.print_error("switching to", server)
@ -601,7 +602,7 @@ class Network(util.DaemonThread):
def process_response(self, interface, response, callbacks): def process_response(self, interface, response, callbacks):
if self.debug: if self.debug:
self.print_error("<--", response) self.print_error(interface.host, "<--", response)
error = response.get('error') error = response.get('error')
result = response.get('result') result = response.get('result')
method = response.get('method') method = response.get('method')
@ -798,6 +799,7 @@ class Network(util.DaemonThread):
server, socket = self.socket_queue.get() server, socket = self.socket_queue.get()
if server in self.connecting: if server in self.connecting:
self.connecting.remove(server) self.connecting.remove(server)
if socket: if socket:
self.new_interface(server, socket) self.new_interface(server, socket)
else: else:
@ -1008,6 +1010,7 @@ class Network(util.DaemonThread):
interface.mode = 'default' interface.mode = 'default'
interface.request = None interface.request = None
self.notify('updated') self.notify('updated')
# refresh network dialog # refresh network dialog
self.notify('interfaces') self.notify('interfaces')

View file

@ -42,42 +42,44 @@ class SPV(ThreadJob):
interface = self.network.interface interface = self.network.interface
if not interface: if not interface:
return return
blockchain = interface.blockchain blockchain = interface.blockchain
if not blockchain: if not blockchain:
return return
lh = self.network.get_local_height()
local_height = self.network.get_local_height()
unverified = self.wallet.get_unverified_txs() unverified = self.wallet.get_unverified_txs()
for tx_hash, tx_height in unverified.items(): for tx_hash, tx_height in unverified.items():
# do not request merkle branch before headers are available # do not request merkle branch before headers are available
if (tx_height > 0) and (tx_height <= lh): if tx_height <= 0 or tx_height > local_height:
header = blockchain.read_header(tx_height) continue
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( header = blockchain.read_header(tx_height)
tx_hash, if header is None:
tx_height, index = tx_height // 2016
self.verify_merkle) if index < len(blockchain.checkpoints):
self.print_error('requested merkle', tx_hash) self.network.request_chunk(interface, index)
self.requested_merkle.add(tx_hash) 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: if self.network.blockchain() != self.blockchain:
self.blockchain = self.network.blockchain() self.blockchain = self.network.blockchain()
self.undo_verifications() self.undo_verifications()
def verify_merkle(self, r): def verify_merkle(self, response):
if self.wallet.verifier is None: if self.wallet.verifier is None:
return # we have been killed, this was just an orphan callback return # we have been killed, this was just an orphan callback
if r.get('error'): if response.get('error'):
self.print_error('received an error:', r) self.print_error('received an error:', response)
return return
params = r['params'] params = response['params']
merkle = r['result'] merkle = response['result']
# Verify the hash of the server-provided merkle branch to a # Verify the hash of the server-provided merkle branch to a
# transaction matches the merkle root of its block # transaction matches the merkle root of its block
tx_hash = params[0] tx_hash = params[0]

View file

@ -218,10 +218,7 @@ class Abstract_Wallet(PrintError):
self.load_unverified_transactions() self.load_unverified_transactions()
self.remove_local_transactions_we_dont_have() self.remove_local_transactions_we_dont_have()
# There is a difference between wallet.up_to_date and network.is_up_to_date(). # wallet.up_to_date is true when the wallet is synchronized
# 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.
self.up_to_date = False self.up_to_date = False
# save wallet type the first time # save wallet type the first time