A few peer handling improvements
based on suggestions from hsmiths Set transport to None if a connection is lost Only subscribe to peers if the peer is verified on same network
This commit is contained in:
parent
9d6b353eec
commit
0149f2785f
@ -776,6 +776,7 @@ class JSONSession(JSONSessionBase, asyncio.Protocol):
|
|||||||
|
|
||||||
def connection_lost(self, exc):
|
def connection_lost(self, exc):
|
||||||
'''Trigger timeouts of all pending requests.'''
|
'''Trigger timeouts of all pending requests.'''
|
||||||
|
self.transport = None
|
||||||
self.timeout_session()
|
self.timeout_session()
|
||||||
|
|
||||||
def is_closing(self):
|
def is_closing(self):
|
||||||
|
|||||||
@ -77,7 +77,6 @@ class PeerSession(JSONSession):
|
|||||||
proto_ver = (version.PROTOCOL_MIN, version.PROTOCOL_MAX)
|
proto_ver = (version.PROTOCOL_MIN, version.PROTOCOL_MAX)
|
||||||
self.send_request(self.on_version, 'server.version',
|
self.send_request(self.on_version, 'server.version',
|
||||||
[version.VERSION, proto_ver])
|
[version.VERSION, proto_ver])
|
||||||
self.send_request(self.on_peers_subscribe, 'server.peers.subscribe')
|
|
||||||
self.send_request(self.on_features, 'server.features')
|
self.send_request(self.on_features, 'server.features')
|
||||||
|
|
||||||
def connection_lost(self, exc):
|
def connection_lost(self, exc):
|
||||||
@ -99,8 +98,6 @@ class PeerSession(JSONSession):
|
|||||||
|
|
||||||
Each update is expected to be of the form:
|
Each update is expected to be of the form:
|
||||||
[ip_addr, hostname, ['v1.0', 't51001', 's51002']]
|
[ip_addr, hostname, ['v1.0', 't51001', 's51002']]
|
||||||
|
|
||||||
Return True if we're in the list of peers.
|
|
||||||
'''
|
'''
|
||||||
try:
|
try:
|
||||||
real_names = [' '.join([u[1]] + u[2]) for u in updates]
|
real_names = [' '.join([u[1]] + u[2]) for u in updates]
|
||||||
@ -108,7 +105,7 @@ class PeerSession(JSONSession):
|
|||||||
for real_name in real_names]
|
for real_name in real_names]
|
||||||
except Exception:
|
except Exception:
|
||||||
self.log_error('bad server.peers.subscribe response')
|
self.log_error('bad server.peers.subscribe response')
|
||||||
return False
|
return
|
||||||
|
|
||||||
self.peer_mgr.add_peers(peers)
|
self.peer_mgr.add_peers(peers)
|
||||||
my = self.peer_mgr.myself
|
my = self.peer_mgr.myself
|
||||||
@ -124,41 +121,51 @@ class PeerSession(JSONSession):
|
|||||||
'''Handle the response to the add_peer message.'''
|
'''Handle the response to the add_peer message.'''
|
||||||
self.close_if_done()
|
self.close_if_done()
|
||||||
|
|
||||||
|
def peer_verified(self, is_good):
|
||||||
|
'''Call when it has been determined whether or not the peer seems to
|
||||||
|
be on the same network.
|
||||||
|
'''
|
||||||
|
if is_good:
|
||||||
|
self.send_request(self.on_peers_subscribe,
|
||||||
|
'server.peers.subscribe')
|
||||||
|
else:
|
||||||
|
self.peer.mark_bad()
|
||||||
|
self.failed = True
|
||||||
|
|
||||||
def on_features(self, features, error):
|
def on_features(self, features, error):
|
||||||
# Several peers don't implement this. If they do, check they are
|
# Several peers don't implement this. If they do, check they are
|
||||||
# the same network with the genesis hash.
|
# the same network with the genesis hash.
|
||||||
verified = False
|
verified = False
|
||||||
if not error and isinstance(features, dict):
|
if not error and isinstance(features, dict):
|
||||||
forget = False
|
|
||||||
our_hash = self.peer_mgr.env.coin.GENESIS_HASH
|
our_hash = self.peer_mgr.env.coin.GENESIS_HASH
|
||||||
their_hash = features.get('genesis_hash')
|
if our_hash != features.get('genesis_hash'):
|
||||||
if their_hash:
|
self.peer_verified(False)
|
||||||
verified = their_hash == our_hash
|
|
||||||
forget = their_hash != our_hash
|
|
||||||
if forget:
|
|
||||||
self.failed = True
|
|
||||||
self.peer.mark_bad()
|
|
||||||
self.log_warning('incorrect genesis hash')
|
self.log_warning('incorrect genesis hash')
|
||||||
else:
|
else:
|
||||||
|
self.peer_verified(True)
|
||||||
self.peer.update_features(features)
|
self.peer.update_features(features)
|
||||||
|
verified = True
|
||||||
# For legacy peers not implementing features, check their height
|
# For legacy peers not implementing features, check their height
|
||||||
# as a proxy to determining they're on our network
|
# as a proxy to determining they're on our network
|
||||||
if not verified:
|
if not verified and not self.peer.bad:
|
||||||
self.send_request(self.on_headers, 'blockchain.headers.subscribe')
|
self.send_request(self.on_headers, 'blockchain.headers.subscribe')
|
||||||
self.close_if_done()
|
self.close_if_done()
|
||||||
|
|
||||||
def on_headers(self, result, error):
|
def on_headers(self, result, error):
|
||||||
'''Handle the response to the version message.'''
|
'''Handle the response to the version message.'''
|
||||||
if error or not isinstance(result, dict):
|
if error:
|
||||||
self.failed = True
|
self.failed = True
|
||||||
|
self.log_error('blockchain.headers.subscribe returned an error')
|
||||||
|
elif not isinstance(result, dict):
|
||||||
self.log_error('bad blockchain.headers.subscribe response')
|
self.log_error('bad blockchain.headers.subscribe response')
|
||||||
|
self.peer_verified(False)
|
||||||
else:
|
else:
|
||||||
our_height = self.peer_mgr.controller.bp.db_height
|
our_height = self.peer_mgr.controller.bp.db_height
|
||||||
their_height = result.get('block_height')
|
their_height = result.get('block_height')
|
||||||
if (not isinstance(their_height, int) or
|
is_good = (isinstance(their_height, int) and
|
||||||
abs(our_height - their_height) > 5):
|
abs(our_height - their_height) <= 5)
|
||||||
self.failed = True
|
self.peer_verified(is_good)
|
||||||
self.peer.mark_bad()
|
if not is_good:
|
||||||
self.log_warning('bad height {}'.format(their_height))
|
self.log_warning('bad height {}'.format(their_height))
|
||||||
self.close_if_done()
|
self.close_if_done()
|
||||||
|
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user