From 35dd1f61996b02a84691ea71ff50f0900df969bc Mon Sep 17 00:00:00 2001 From: Neil Booth Date: Mon, 27 Nov 2017 15:05:42 +0900 Subject: [PATCH] Remove IRC support --- contrib/raspberrypi3/install_electrumx.sh | 1 - contrib/raspberrypi3/run_electrumx.sh | 2 - docs/ARCHITECTURE.rst | 5 - docs/ENVIRONMENT.rst | 29 +---- docs/HOWTO.rst | 5 - docs/PEER_DISCOVERY.rst | 25 +---- docs/PROTOCOL.rst | 3 +- docs/RPC-INTERFACE.rst | 10 +- lib/coins.py | 39 +------ server/env.py | 6 +- server/irc.py | 126 ---------------------- server/peers.py | 22 ---- setup.py | 3 +- tests/server/test_env.py | 14 +-- 14 files changed, 20 insertions(+), 270 deletions(-) delete mode 100644 server/irc.py diff --git a/contrib/raspberrypi3/install_electrumx.sh b/contrib/raspberrypi3/install_electrumx.sh index 2e5ca76..638643e 100644 --- a/contrib/raspberrypi3/install_electrumx.sh +++ b/contrib/raspberrypi3/install_electrumx.sh @@ -17,7 +17,6 @@ sudo apt install libreadline6-dev/stable libreadline6/stable sudo apt-get install libleveldb-dev sudo apt-get install git sudo pip3 install plyvel -sudo pip3 install irc # install electrumx git clone https://github.com/kyuupichan/electrumx.git diff --git a/contrib/raspberrypi3/run_electrumx.sh b/contrib/raspberrypi3/run_electrumx.sh index 7b4ade4..408e69d 100644 --- a/contrib/raspberrypi3/run_electrumx.sh +++ b/contrib/raspberrypi3/run_electrumx.sh @@ -20,8 +20,6 @@ export TCP_PORT=50001 export SSL_PORT=50002 # visibility -export IRC= -export IRC_NICK=hostname export REPORT_HOST=hostname.com export RPC_PORT=8000 diff --git a/docs/ARCHITECTURE.rst b/docs/ARCHITECTURE.rst index b796d8c..2701d83 100644 --- a/docs/ARCHITECTURE.rst +++ b/docs/ARCHITECTURE.rst @@ -81,8 +81,3 @@ Database The underlying data store, made up of the DB backend (such as `leveldb`) and the host filesystem. - -IRC ---- - -Handles advertising of ElectrumX services via IRC. diff --git a/docs/ENVIRONMENT.rst b/docs/ENVIRONMENT.rst index 3553348..2d5446f 100644 --- a/docs/ENVIRONMENT.rst +++ b/docs/ENVIRONMENT.rst @@ -296,9 +296,7 @@ some of this. By default peer discovery happens over the clear internet. Set this to non-empty to force peer discovery to be done via the proxy. This might be useful if you are running a Tor service exclusively and - wish to keep your IP address private. **NOTE**: in such a case you - should leave **IRC** unset as IRC connections are *always* over the - normal internet. + wish to keep your IP address private. * **TOR_PROXY_HOST** @@ -317,8 +315,8 @@ some of this. Server Advertising ------------------ -These environment variables affect how your server is advertised, both -by peer discovery (if enabled) and IRC (if enabled). +These environment variables affect how your server is advertised +by peer discovery (if enabled). * **REPORT_HOST** @@ -357,27 +355,6 @@ by peer discovery (if enabled) and IRC (if enabled). self-signed. -IRC ---- - -Use the following environment variables if you want to advertise -connectivity on IRC: - -* **IRC** - - Set to anything non-empty to advertise on IRC. ElectrumX connects - to IRC over the clear internet, always. - -* **IRC_NICK** - - The nick to use when connecting to IRC. The default is a hash of - **REPORT_HOST**. Either way a prefix will be prepended depending on - **COIN** and **NET**. - - If **REPORT_HOST_TOR** is set, an additional connection to IRC - happens with '_tor' appended to **IRC_NICK**. - - Cache ----- diff --git a/docs/HOWTO.rst b/docs/HOWTO.rst index 1671100..3bd1086 100644 --- a/docs/HOWTO.rst +++ b/docs/HOWTO.rst @@ -18,10 +18,6 @@ Python3 ElectrumX uses asyncio. Python version >= 3.6 is DB Engine I use `plyvel`_ 0.9, a Python interface to LevelDB. A database engine package is required but others are supported (see **Database Engine** below). -`IRC`_ Python IRC package. Only required if you enable - IRC; ElectrumX will happily serve clients that - try to connect directly. I use 15.0.4 but - older versions likely are fine. `x11_hash`_ Only required for DASH. Python X11 Hash package. Only required if for Dash. Version 1.4 tested. ================ ======================== @@ -414,7 +410,6 @@ You can then set the port as follows and advertise the service externally on the .. _`runit`: http://smarden.org/runit/index.html .. _`aiohttp`: https://pypi.python.org/pypi/aiohttp .. _`pylru`: https://pypi.python.org/pypi/pylru -.. _`IRC`: https://pypi.python.org/pypi/irc .. _`x11_hash`: https://pypi.python.org/pypi/x11_hash .. _`contrib/python3.6/python-3.6.sh`: https://github.com/kyuupichan/electrumx/blob/master/contrib/python3.6/python-3.6.sh .. _`contrib/raspberrypi3/install_electrumx.sh`: https://github.com/kyuupichan/electrumx/blob/master/contrib/raspberrypi3/install_electrumx.sh diff --git a/docs/PEER_DISCOVERY.rst b/docs/PEER_DISCOVERY.rst index 909e0e2..bb477f4 100644 --- a/docs/PEER_DISCOVERY.rst +++ b/docs/PEER_DISCOVERY.rst @@ -1,11 +1,8 @@ Peer Discovery ============== -This is a suggestion of a peer discovery prtocol as a way to gradually -move off depending on IRC. - -It will be implemented in ElectrumX from version 0.11.0 -onwards. +This was imlpemented in ElectrumX as of version 0.11.0. Support for +IRC peer discovery was removed in ElectrumX version 1.2.1. Peer Database @@ -154,14 +151,12 @@ Unknown keys should be silently ignored. * **protocol_min** Strings that are the minimum and maximum Electrum protocol versions - this server speaks. The maximum value should be the same as what - would suffix the letter **v** in the IRC real name. Example: "1.1". + this server speaks. Example: "1.1". * **pruning** An integer, the pruning limit. Omit or set to *null* if there is no - pruning limit. Should be the same as what would suffix the letter - **p** in the IRC real name. + pruning limit. server.add_peer RPC call @@ -184,18 +179,6 @@ calls to this method from a single connection. The result should be True if accepted and False otherwise. -IRC ---- - -Other server implementations may not have implemented the peer -discovery protocol yet. Whilst we transition away from IRC, in order -to keep these servers in the connected peer set, having one or two in -the hard-coded peer list used to seed this process should suffice. -Any peer on IRC will report other peers on IRC, and so if any one of -them is known to any single peer implementing this protocol, they will -all become known to all peers quite rapidly. - - Notes to Implementators ----------------------- diff --git a/docs/PROTOCOL.rst b/docs/PROTOCOL.rst index 597ecfb..6009d3d 100644 --- a/docs/PROTOCOL.rst +++ b/docs/PROTOCOL.rst @@ -846,8 +846,7 @@ Get a list of features and services supported by the server. * **protocol_min** Strings that are the minimum and maximum Electrum protocol versions - this server speaks. The maximum value should be the same as what - would suffix the letter **v** in the IRC real name. Example: "1.1". + this server speaks. Example: "1.1". * **pruning** diff --git a/docs/RPC-INTERFACE.rst b/docs/RPC-INTERFACE.rst index b5dc960..83cc13e 100644 --- a/docs/RPC-INTERFACE.rst +++ b/docs/RPC-INTERFACE.rst @@ -38,7 +38,7 @@ The following commands are available: "groups": 2, # The number of session groups "logged": 0, # The number of sessions being logged "paused": 0, # The number of paused sessions. - "peers": 62, # Number of peer servers (from IRC) + "peers": 62, # Number of peer servers "pid": 126275, # The server's process ID "requests": 0, # Number of unprocessed requests "sessions": 85, # Number of current sessions (connections) @@ -153,14 +153,14 @@ The following commands are available: Returns a list of peer electrum servers. This command takes no arguments. - Currently peer data is obtained via a peer discovery protocol; it - used to be taken from IRC. + Peer data is obtained via a peer discovery protocol documented in + `docs/PEER_DISCOVERY.rst`_. * **add_peer** Add a peer to the peers list. ElectrumX will schdule an immediate connection attempt. This command takes a single argument: the - peer's "real name" as it would advertise itself on IRC. + peer's "real name" as it used to advertise itself on IRC. .. code:: @@ -186,3 +186,5 @@ The following commands are available: Force a block chain reorg. This command takes an optional argument - the number of blocks to reorg - which defaults to 3. + +.. _docs/PEER_DISCOVERY.rst: https://github.com/kyuupichan/electrumx/blob/master/docs/PEER_DISCOVERY.rst diff --git a/lib/coins.py b/lib/coins.py index a982839..757dd7d 100644 --- a/lib/coins.py +++ b/lib/coins.py @@ -70,9 +70,6 @@ class Coin(object): BLOCK_PROCESSOR = BlockProcessor XPUB_VERBYTES = bytes('????', 'utf-8') XPRV_VERBYTES = bytes('????', 'utf-8') - IRC_PREFIX = None - IRC_SERVER = "irc.freenode.net" - IRC_PORT = 6667 # Peer discovery PEER_DEFAULT_PORTS = {'t': '50001', 's': '50002'} PEERS = [] @@ -87,8 +84,6 @@ class Coin(object): if (coin.NAME.lower() == name.lower() and coin.NET.lower() == net.lower()): coin_req_attrs = req_attrs.copy() - if coin.IRC_PREFIX is not None: - coin_req_attrs.append('IRC_CHANNEL') missing = [attr for attr in coin_req_attrs if not hasattr(coin, attr)] if missing: @@ -616,8 +611,6 @@ class Viacoin(AuxPowMixin, Coin): TX_COUNT = 113638 TX_COUNT_HEIGHT = 3473674 TX_PER_BLOCK = 30 - IRC_PREFIX = "E_" - IRC_CHANNEL="#vialectrum" RPC_PORT = 5222 REORG_LIMIT = 5000 DESERIALIZER = lib_tx.DeserializerAuxPowSegWit @@ -665,8 +658,9 @@ class Namecoin(AuxPowMixin, Coin): TX_COUNT = 4415768 TX_COUNT_HEIGHT = 329065 TX_PER_BLOCK = 10 - IRC_PREFIX = "E_" - IRC_CHANNEL = "#electrum-nmc" + PEERS = [ + 'elec.luggs.co s446', + ] class NamecoinTestnet(Namecoin): @@ -694,8 +688,6 @@ class Dogecoin(AuxPowMixin, Coin): TX_COUNT = 27583427 TX_COUNT_HEIGHT = 1604979 TX_PER_BLOCK = 20 - IRC_PREFIX = "E_" - IRC_CHANNEL = "#electrum-doge" REORG_LIMIT = 2000 @@ -726,8 +718,6 @@ class Dash(Coin): TX_COUNT = 2157510 TX_PER_BLOCK = 4 RPC_PORT = 9998 - IRC_PREFIX = "D_" - IRC_CHANNEL = "#electrum-dash" PEERS = [ 'electrum.dash.org s t', 'electrum.masternode.io s t', @@ -760,7 +750,6 @@ class DashTestnet(Dash): TX_COUNT = 132681 TX_PER_BLOCK = 1 RPC_PORT = 19998 - IRC_PREFIX = "d_" PEER_DEFAULT_PORTS = {'t': '51001', 's': '51002'} PEERS = [ 'electrum.dash.siampm.com s t', @@ -779,8 +768,6 @@ class Argentum(AuxPowMixin, Coin): TX_COUNT = 2263089 TX_COUNT_HEIGHT = 2050260 TX_PER_BLOCK = 2000 - IRC_PREFIX = "A_" - IRC_CHANNEL = "#electrum-arg" RPC_PORT = 13581 @@ -806,8 +793,6 @@ class DigiByte(Coin): TX_COUNT = 1046018 TX_COUNT_HEIGHT = 1435000 TX_PER_BLOCK = 1000 - IRC_PREFIX = "DE_" - IRC_CHANNEL = "#electrum-dgb" RPC_PORT = 12022 @@ -818,8 +803,6 @@ class DigiByteTestnet(DigiByte): WIF_BYTE = bytes.fromhex("ef") GENESIS_HASH = ('b5dca8039e300198e5fe7cd23bdd1728' 'e2a444af34c447dbd0916fa3430a68c2') - IRC_PREFIX = "DET_" - IRC_CHANNEL = "#electrum-dgb" RPC_PORT = 15022 REORG_LIMIT = 2000 @@ -837,8 +820,6 @@ class FairCoin(Coin): TX_COUNT = 505 TX_COUNT_HEIGHT = 470 TX_PER_BLOCK = 1 - IRC_PREFIX = "E_" - IRC_CHANNEL = "#fairlectrum" RPC_PORT = 40405 PEER_DEFAULT_PORTS = {'t': '51811', 's': '51812'} PEERS = [ @@ -882,8 +863,6 @@ class Zcash(EquihashMixin, Coin): TX_COUNT = 329196 TX_COUNT_HEIGHT = 68379 TX_PER_BLOCK = 5 - IRC_PREFIX = "E_" - IRC_CHANNEL = "#electrum-zcash" RPC_PORT = 8232 REORG_LIMIT = 800 @@ -939,8 +918,6 @@ class Einsteinium(Coin): TX_COUNT = 2087559 TX_COUNT_HEIGHT = 1358517 TX_PER_BLOCK = 2 - IRC_PREFIX = "E_" - IRC_CHANNEL = "#electrum-emc2" RPC_PORT = 41879 REORG_LIMIT = 2000 @@ -958,8 +935,6 @@ class Blackcoin(ScryptMixin, Coin): TX_COUNT = 4594999 TX_COUNT_HEIGHT = 1667070 TX_PER_BLOCK = 3 - IRC_PREFIX = "E_" - IRC_CHANNEL = "#electrum-blk" RPC_PORT = 15715 REORG_LIMIT = 5000 @@ -977,8 +952,6 @@ class Bitbay(ScryptMixin, Coin): TX_COUNT = 4594999 TX_COUNT_HEIGHT = 1667070 TX_PER_BLOCK = 3 - IRC_PREFIX = "E_" - IRC_CHANNEL = "#electrum-bay" RPC_PORT = 19914 REORG_LIMIT = 5000 @@ -997,8 +970,6 @@ class Peercoin(Coin): TX_COUNT = 1207356 TX_COUNT_HEIGHT = 306425 TX_PER_BLOCK = 4 - IRC_PREFIX = "E_" - IRC_CHANNEL = "#electrum-ppc" RPC_PORT = 9902 REORG_LIMIT = 5000 @@ -1016,8 +987,6 @@ class Reddcoin(Coin): TX_COUNT = 5413508 TX_COUNT_HEIGHT = 1717382 TX_PER_BLOCK = 3 - IRC_PREFIX = "E_" - IRC_CHANNEL = "#electrum-rdd" RPC_PORT = 45443 @@ -1197,8 +1166,6 @@ class CanadaeCoin(AuxPowMixin, Coin): TX_COUNT = 3455905 TX_COUNT_HEIGHT = 3645419 TX_PER_BLOCK = 1 - IRC_PREFIX = "E_" - IRC_CHANNEL="#electrum-cdn" RPC_PORT = 34330 REORG_LIMIT = 1000 diff --git a/server/env.py b/server/env.py index c82aab2..ff74f24 100644 --- a/server/env.py +++ b/server/env.py @@ -68,10 +68,6 @@ class Env(EnvBase): self.bandwidth_limit = self.integer('BANDWIDTH_LIMIT', 2000000) self.session_timeout = self.integer('SESSION_TIMEOUT', 600) - # IRC - self.irc = self.boolean('IRC', False) - self.irc_nick = self.default('IRC_NICK', None) - # Identities clearnet_identity = self.clearnet_identity() tor_identity = self.tor_identity(clearnet_identity) @@ -104,7 +100,7 @@ class Env(EnvBase): or host.lower() == 'localhost') else: bad = (ip.is_multicast or ip.is_unspecified - or (ip.is_private and (self.irc or self.peer_announce))) + or (ip.is_private and self.peer_announce)) if bad: raise self.Error('"{}" is not a valid REPORT_HOST'.format(host)) tcp_port = self.integer('REPORT_TCP_PORT', self.tcp_port) or None diff --git a/server/irc.py b/server/irc.py deleted file mode 100644 index 6507c3b..0000000 --- a/server/irc.py +++ /dev/null @@ -1,126 +0,0 @@ -# Copyright (c) 2016-2017, Neil Booth -# -# All rights reserved. -# -# See the file "LICENCE" for information about the copyright -# and warranty status of this software. - -'''IRC connectivity to discover peers. - -Only calling start() requires the IRC Python module. -''' - -import asyncio -import re - -from collections import namedtuple - -from lib.hash import double_sha256 -from lib.util import LoggedClass - - -class IRC(LoggedClass): - - class DisconnectedError(Exception): - pass - - def __init__(self, env, peer_mgr): - super().__init__() - self.coin = env.coin - self.peer_mgr = peer_mgr - - # If this isn't something a peer or client expects - # then you won't appear in the client's network dialog box - self.channel = env.coin.IRC_CHANNEL - self.prefix = env.coin.IRC_PREFIX - self.nick = '{}{}'.format(self.prefix, - env.irc_nick if env.irc_nick else - double_sha256(env.host.encode()) - [:5].hex()) - self.peer_regexp = re.compile('({}[^!]*)!'.format(self.prefix)) - - async def start(self, name_pairs): - '''Start IRC connections if enabled in environment.''' - import irc.client as irc_client - from jaraco.stream import buffer - - # see https://pypi.python.org/pypi/irc under DecodingInput - irc_client.ServerConnection.buffer_class = \ - buffer.LenientDecodingLineBuffer - - # Register handlers for events we're interested in - reactor = irc_client.Reactor() - for event in 'welcome join whoreply disconnect'.split(): - reactor.add_global_handler(event, getattr(self, 'on_' + event)) - - # Note: Multiple nicks in same channel will trigger duplicate events - clients = [IrcClient(self.coin, real_name, self.nick + suffix, - reactor.server()) - for (real_name, suffix) in name_pairs] - - while True: - try: - for client in clients: - client.connect(self) - while True: - reactor.process_once() - await asyncio.sleep(2) - except irc_client.ServerConnectionError as e: - self.logger.error('connection error: {}'.format(e)) - except self.DisconnectedError: - self.logger.error('disconnected') - await asyncio.sleep(10) - - def log_event(self, event): - self.logger.info('IRC event type {} source {} args {}' - .format(event.type, event.source, event.arguments)) - - def on_welcome(self, connection, event): - '''Called when we connect to irc server.''' - connection.join(self.channel) - - def on_disconnect(self, connection, event): - '''Called if we are disconnected.''' - self.log_event(event) - raise self.DisconnectedError - - def on_join(self, connection, event): - '''Called when someone new connects to our channel, including us.''' - # /who the channel when we join. We used to /who on each - # namreply event, but the IRC server would frequently kick us - # for flooding. This requests only once including the tor case. - if event.source.startswith(self.nick + '!'): - connection.who(self.channel) - else: - match = self.peer_regexp.match(event.source) - if match: - connection.who(match.group(1)) - - def on_whoreply(self, connection, event): - '''Called when a response to our who requests arrives. - - The nick is the 4th argument, and real name is in the 6th - argument preceeded by '0 ' for some reason. - ''' - nick = event.arguments[4] - if nick.startswith(self.prefix): - line = event.arguments[6].split() - hp_string = ' '.join(line[1:]) # hostname, ports, version etc. - self.peer_mgr.add_irc_peer(nick, hp_string) - - -class IrcClient(object): - - def __init__(self, coin, real_name, nick, server): - self.irc_host = coin.IRC_SERVER - self.irc_port = coin.IRC_PORT - self.nick = nick - self.real_name = real_name - self.server = server - - def connect(self, irc): - '''Connect this client to its IRC server''' - irc.logger.info('joining {} as "{}" with real name "{}"' - .format(irc.channel, self.nick, self.real_name)) - self.server.connect(self.irc_host, self.irc_port, self.nick, - ircname=self.real_name) diff --git a/server/peers.py b/server/peers.py index 8503496..9d15b75 100644 --- a/server/peers.py +++ b/server/peers.py @@ -19,7 +19,6 @@ from lib.jsonrpc import JSONSession from lib.peer import Peer from lib.socks import SocksProxy import lib.util as util -from server.irc import IRC import server.version as version @@ -228,10 +227,6 @@ class PeerManager(util.LoggedClass): self.env = env self.controller = controller self.loop = controller.loop - if env.irc and env.coin.IRC_PREFIX: - self.irc = IRC(env, self) - else: - self.irc = None # Our clearnet and Tor Peers, if any self.myselves = [Peer(ident.host, env.server_features(), 'env') @@ -417,22 +412,6 @@ class PeerManager(util.LoggedClass): for real_name in coin_peers] self.add_peers(peers, limit=None) - def connect_to_irc(self): - '''Connect to IRC if not disabled.''' - if self.irc: - pairs = [(peer.real_name(), ident.nick_suffix) for peer, ident - in zip(self.myselves, self.env.identities)] - self.ensure_future(self.irc.start(pairs)) - elif self.env.irc: - self.logger.info('IRC is disabled for this coin') - else: - self.logger.info('IRC is disabled') - - def add_irc_peer(self, nick, real_name): - '''Add an IRC peer.''' - peer = Peer.from_real_name(real_name, '{}'.format(nick)) - self.add_peers([peer]) - def ensure_future(self, coro, callback=None): '''Schedule the coro to be run.''' return self.controller.ensure_future(coro, callback=callback) @@ -444,7 +423,6 @@ class PeerManager(util.LoggedClass): 2) Verifying connectivity of new peers. 3) Retrying old peers at regular intervals. ''' - self.connect_to_irc() if self.env.peer_discovery != self.env.PD_ON: self.logger.info('peer discovery is disabled') return diff --git a/setup.py b/setup.py index 777b993..6f7becf 100644 --- a/setup.py +++ b/setup.py @@ -7,10 +7,9 @@ setuptools.setup( version=VERSION.split()[-1], scripts=['electrumx_server.py', 'electrumx_rpc.py'], python_requires='>=3.6', - # "irc" package is only required if IRC connectivity is enabled # via environment variables, in which case I've tested with 15.0.4 # "x11_hash" package (1.4) is required to sync DASH network. - install_requires=['plyvel', 'pylru', 'irc', 'aiohttp >= 1'], + install_requires=['plyvel', 'pylru', 'aiohttp >= 1'], packages=setuptools.find_packages(exclude=['tests']), description='ElectrumX Server', author='Neil Booth', diff --git a/tests/server/test_env.py b/tests/server/test_env.py index 323eed3..dd07d46 100644 --- a/tests/server/test_env.py +++ b/tests/server/test_env.py @@ -231,12 +231,6 @@ def test_TOR_PROXY_HOST(): def test_TOR_PROXY_PORT(): assert_integer('TOR_PROXY_PORT', 'tor_proxy_port', None) -def test_IRC(): - assert_boolean('IRC', 'irc', False) - -def test_IRC_NICK(): - assert_default('IRC_NICK', 'irc_nick', None) - def test_clearnet_identity(): os.environ['REPORT_TCP_PORT'] = '456' e = Env() @@ -263,18 +257,12 @@ def test_clearnet_identity(): os.environ['REPORT_HOST'] = '$HOST' with pytest.raises(Env.Error): Env() - # Accept private IP, unless IRC or PEER_ANNOUNCE - os.environ.pop('IRC', None) + # Accept private IP, unless PEER_ANNOUNCE os.environ['PEER_ANNOUNCE'] = '' os.environ['REPORT_HOST'] = '192.168.0.1' os.environ['SSL_CERTFILE'] = 'certfile' os.environ['SSL_KEYFILE'] = 'keyfile' Env() - os.environ['IRC'] = 'OK' - with pytest.raises(Env.Error) as err: - Env() - assert 'not a valid REPORT_HOST' in str(err) - os.environ.pop('IRC', None) os.environ['PEER_ANNOUNCE'] = 'OK' with pytest.raises(Env.Error) as err: Env()