From 0b4f6b3d6d8f34b38c3abd8fcc3e03b5a6bb980a Mon Sep 17 00:00:00 2001 From: Neil Booth Date: Sat, 28 Jul 2018 16:35:38 +0800 Subject: [PATCH] Prepare 1.7.1 --- docs/changelog.rst | 13 ++++++ docs/conf.py | 2 +- electrumx/__init__.py | 2 +- electrumx/server/peers.py | 86 +++++++++++++++++++-------------------- setup.py | 4 +- 5 files changed, 60 insertions(+), 47 deletions(-) diff --git a/docs/changelog.rst b/docs/changelog.rst index 9a59356..0cdebb4 100644 --- a/docs/changelog.rst +++ b/docs/changelog.rst @@ -7,6 +7,18 @@ and memory consumption whilst serving clients. Those problems should not occur with Python 3.7. +Version 1.7.1 (28 Jul 2018) +============================ + +* switch to aiorpcX 0.5.8 which implements some curio task management + primitives on top of asyncio that make writing correct async code + much easier, as well as making it simpler to reason about +* use those primitives to restructure the peer manager, which is now + fully concurrent again, as well as the block processor and + controller +* fix `#534`_ introduced in 1.7 +* minor coin tweaks (ghost43, cipig) + Version 1.7 (25 Jul 2018) ========================== @@ -160,3 +172,4 @@ bitcoincash:qzxpdlt8ehu9ehftw6rqsy2jgfq4nsltxvhrdmdfpn .. _#506: https://github.com/kyuupichan/electrumx/issues/506 .. _#519: https://github.com/kyuupichan/electrumx/issues/519 .. _#523: https://github.com/kyuupichan/electrumx/issues/523 +.. _#534: https://github.com/kyuupichan/electrumx/issues/534 diff --git a/docs/conf.py b/docs/conf.py index f5d9c79..6935659 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -15,7 +15,7 @@ import os import sys sys.path.insert(0, os.path.abspath('..')) -VERSION="ElectrumX 1.7" +VERSION="ElectrumX 1.7.1" # -- Project information ----------------------------------------------------- diff --git a/electrumx/__init__.py b/electrumx/__init__.py index 24702bd..2781152 100644 --- a/electrumx/__init__.py +++ b/electrumx/__init__.py @@ -1,4 +1,4 @@ -version = 'ElectrumX 1.7' +version = 'ElectrumX 1.7.1' version_short = version.split()[-1] from electrumx.server.controller import Controller diff --git a/electrumx/server/peers.py b/electrumx/server/peers.py index 0f672ac..3f1bad6 100644 --- a/electrumx/server/peers.py +++ b/electrumx/server/peers.py @@ -185,8 +185,8 @@ class PeerManager(object): async def _monitor_peer(self, peer): # Stop monitoring if we were dropped (a duplicate peer) while peer in self.peers: - is_good = await self._is_peer_good(peer) - if self._should_drop_peer(peer, is_good): + if await self._should_drop_peer(peer): + self.peers.discard(peer) break # Figure out how long to sleep before retrying. Retry a # good connection when it is about to turn stale, otherwise @@ -198,47 +198,9 @@ class PeerManager(object): async with ignore_after(pause): await peer.retry_event.wait() - async def _should_drop_peer(self, peer, is_good): - now = time.time() - if self.env.force_proxy or peer.is_tor: - how = f'via {kind} over Tor' - else: - how = f'via {kind} at {peer.ip_addr}' - status = 'verified' if good else 'failed to verify' - elapsed = now - peer.last_try - self.logger.info(f'{status} {peer} {how} in {elapsed:.1f}s') - - if good: - peer.try_count = 0 - peer.last_good = now - peer.source = 'peer' - # At most 2 matches if we're a host name, potentially - # several if we're an IP address (several instances - # can share a NAT). - matches = peer.matches(self.peers) - for match in matches: - if match.ip_address: - if len(matches) > 1: - self.peers.remove(match) - # Force the peer's monitoring task to exit - match.retry_event.set() - elif peer.host in match.features['hosts']: - match.update_features_from_peer(peer) - else: - # Forget the peer if long-term unreachable - if peer.last_good and not peer.bad: - try_limit = 10 - else: - try_limit = 3 - if peer.try_count >= try_limit: - desc = 'bad' if peer.bad else 'unreachable' - self.logger.info(f'forgetting {desc} peer: {peer}') - self.peers.discard(peer) - return True - return False - - async def _is_peer_good(self, peer): + async def _should_drop_peer(self, peer): peer.try_count += 1 + is_good = False for kind, port in peer.connection_port_pairs(): peer.last_try = time.time() @@ -263,7 +225,8 @@ class PeerManager(object): try: async with PeerSession(peer.host, port, **kwargs) as session: await self._verify_peer(session, peer) - return True + is_good = True + break except BadPeerError as e: self.logger.error(f'[{peer}] marking bad: ({e})') peer.mark_bad() @@ -277,6 +240,43 @@ class PeerManager(object): self.logger.info(f'[{peer}] {kind} connection to ' f'port {port} failed: {e}') + now = time.time() + if self.env.force_proxy or peer.is_tor: + how = f'via {kind} over Tor' + else: + how = f'via {kind} at {peer.ip_addr}' + status = 'verified' if is_good else 'failed to verify' + elapsed = now - peer.last_try + self.logger.info(f'{status} {peer} {how} in {elapsed:.1f}s') + + if is_good: + peer.try_count = 0 + peer.last_good = now + peer.source = 'peer' + # At most 2 matches if we're a host name, potentially + # several if we're an IP address (several instances + # can share a NAT). + matches = peer.matches(self.peers) + for match in matches: + if match.ip_address: + if len(matches) > 1: + self.peers.remove(match) + # Force the peer's monitoring task to exit + match.retry_event.set() + elif peer.host in match.features['hosts']: + match.update_features_from_peer(peer) + else: + # Forget the peer if long-term unreachable + if peer.last_good and not peer.bad: + try_limit = 10 + else: + try_limit = 3 + if peer.try_count >= try_limit: + desc = 'bad' if peer.bad else 'unreachable' + self.logger.info(f'forgetting {desc} peer: {peer}') + return True + return False + async def _verify_peer(self, session, peer): if not peer.is_tor: address = session.peer_address() diff --git a/setup.py b/setup.py index 2f54368..fe4afbd 100644 --- a/setup.py +++ b/setup.py @@ -1,5 +1,5 @@ import setuptools -version = '1.7' +version = '1.7.1' setuptools.setup( name='electrumX', @@ -11,7 +11,7 @@ setuptools.setup( # "tribus_hash" package is required to sync Denarius network. # "blake256" package is required to sync Decred network. # "xevan_hash" package is required to sync Xuez network. - install_requires=['aiorpcX == 0.5.6', 'attrs>=15', + install_requires=['aiorpcX == 0.5.8', 'attrs>=15', 'plyvel', 'pylru', 'aiohttp >= 2'], packages=setuptools.find_packages(include=('electrumx*',)), description='ElectrumX Server',