Browse Source

Remove IRC support

patch-1
Neil Booth 7 years ago
parent
commit
35dd1f6199
  1. 1
      contrib/raspberrypi3/install_electrumx.sh
  2. 2
      contrib/raspberrypi3/run_electrumx.sh
  3. 5
      docs/ARCHITECTURE.rst
  4. 29
      docs/ENVIRONMENT.rst
  5. 5
      docs/HOWTO.rst
  6. 25
      docs/PEER_DISCOVERY.rst
  7. 3
      docs/PROTOCOL.rst
  8. 10
      docs/RPC-INTERFACE.rst
  9. 39
      lib/coins.py
  10. 6
      server/env.py
  11. 126
      server/irc.py
  12. 22
      server/peers.py
  13. 3
      setup.py
  14. 14
      tests/server/test_env.py

1
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

2
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

5
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.

29
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
-----

5
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

25
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
-----------------------

3
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**

10
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

39
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

6
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

126
server/irc.py

@ -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)

22
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

3
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',

14
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()

Loading…
Cancel
Save