Browse Source

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
master
Neil Booth 8 years ago
parent
commit
0149f2785f
  1. 1
      lib/jsonrpc.py
  2. 43
      server/peers.py

1
lib/jsonrpc.py

@ -776,6 +776,7 @@ class JSONSession(JSONSessionBase, asyncio.Protocol):
def connection_lost(self, exc):
'''Trigger timeouts of all pending requests.'''
self.transport = None
self.timeout_session()
def is_closing(self):

43
server/peers.py

@ -77,7 +77,6 @@ class PeerSession(JSONSession):
proto_ver = (version.PROTOCOL_MIN, version.PROTOCOL_MAX)
self.send_request(self.on_version, 'server.version',
[version.VERSION, proto_ver])
self.send_request(self.on_peers_subscribe, 'server.peers.subscribe')
self.send_request(self.on_features, 'server.features')
def connection_lost(self, exc):
@ -99,8 +98,6 @@ class PeerSession(JSONSession):
Each update is expected to be of the form:
[ip_addr, hostname, ['v1.0', 't51001', 's51002']]
Return True if we're in the list of peers.
'''
try:
real_names = [' '.join([u[1]] + u[2]) for u in updates]
@ -108,7 +105,7 @@ class PeerSession(JSONSession):
for real_name in real_names]
except Exception:
self.log_error('bad server.peers.subscribe response')
return False
return
self.peer_mgr.add_peers(peers)
my = self.peer_mgr.myself
@ -124,41 +121,51 @@ class PeerSession(JSONSession):
'''Handle the response to the add_peer message.'''
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):
# Several peers don't implement this. If they do, check they are
# the same network with the genesis hash.
verified = False
if not error and isinstance(features, dict):
forget = False
our_hash = self.peer_mgr.env.coin.GENESIS_HASH
their_hash = features.get('genesis_hash')
if their_hash:
verified = their_hash == our_hash
forget = their_hash != our_hash
if forget:
self.failed = True
self.peer.mark_bad()
if our_hash != features.get('genesis_hash'):
self.peer_verified(False)
self.log_warning('incorrect genesis hash')
else:
self.peer_verified(True)
self.peer.update_features(features)
verified = True
# For legacy peers not implementing features, check their height
# 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.close_if_done()
def on_headers(self, result, error):
'''Handle the response to the version message.'''
if error or not isinstance(result, dict):
if error:
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.peer_verified(False)
else:
our_height = self.peer_mgr.controller.bp.db_height
their_height = result.get('block_height')
if (not isinstance(their_height, int) or
abs(our_height - their_height) > 5):
self.failed = True
self.peer.mark_bad()
is_good = (isinstance(their_height, int) and
abs(our_height - their_height) <= 5)
self.peer_verified(is_good)
if not is_good:
self.log_warning('bad height {}'.format(their_height))
self.close_if_done()

Loading…
Cancel
Save