From 5aae539476fe1a81979ecfcfcd1c5941b628dafe Mon Sep 17 00:00:00 2001 From: TheLazieR Yip Date: Sun, 20 Nov 2016 19:05:42 +0700 Subject: [PATCH 1/5] Add DEFAULT_RPC_PORT for DASH --- lib/coins.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/coins.py b/lib/coins.py index f4dae22..4e56894 100644 --- a/lib/coins.py +++ b/lib/coins.py @@ -358,6 +358,7 @@ class Dash(Coin): TX_COUNT_HEIGHT = 569399 TX_COUNT = 2157510 TX_PER_BLOCK = 4 + DEFAULT_RPC_PORT = 9998 @classmethod def header_hashes(cls, header): @@ -379,3 +380,4 @@ class DashTestnet(Dash): TX_COUNT_HEIGHT = 101619 TX_COUNT = 132681 TX_PER_BLOCK = 1 + DEFAULT_RPC_PORT = 19998 From aa9f106865298a28c0097420317ff1f2daf629e1 Mon Sep 17 00:00:00 2001 From: Neil Booth Date: Sun, 20 Nov 2016 22:13:21 +0900 Subject: [PATCH 2/5] Add missing self; use max_secs where intended. --- server/daemon.py | 2 +- server/db.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/server/daemon.py b/server/daemon.py index 3c9e545..c1ab980 100644 --- a/server/daemon.py +++ b/server/daemon.py @@ -99,7 +99,7 @@ class Daemon(util.LoggedClass): secs = 1 else: await asyncio.sleep(secs) - secs = min(16, secs * 2) + secs = min(max_secs, secs * 2) def logged_url(self, url): '''The host and port part, for logging.''' diff --git a/server/db.py b/server/db.py index aa5e129..58c7d9e 100644 --- a/server/db.py +++ b/server/db.py @@ -93,7 +93,7 @@ class DB(LoggedClass): if self.db_version not in self.DB_VERSIONS: raise self.DBError('your DB version is {} but this software ' 'only handles versions {}' - .format(db_version, self.DB_VERSIONS)) + .format(self.db_version, self.DB_VERSIONS)) if state['genesis'] != self.coin.GENESIS_HASH: raise self.DBError('DB genesis hash {} does not match coin {}' .format(state['genesis_hash'], From 84faf6cc8dcf21be7a1dd218d090a84aa9104b65 Mon Sep 17 00:00:00 2001 From: cluelessperson Date: Sun, 20 Nov 2016 08:51:27 -0600 Subject: [PATCH 3/5] Reorganization of init systems files, adding systemd sample config --- docs/HOWTO.rst | 4 +- samples/{scripts => daemontools}/env/COIN | 0 .../{scripts => daemontools}/env/DAEMON_HOST | 0 .../env/DAEMON_PASSWORD | 0 .../{scripts => daemontools}/env/DAEMON_PORT | 0 .../env/DAEMON_USERNAME | 0 .../{scripts => daemontools}/env/DB_DIRECTORY | 0 .../{scripts => daemontools}/env/ELECTRUMX | 0 samples/{scripts => daemontools}/env/HIST_MB | 0 samples/{scripts => daemontools}/env/NETWORK | 0 samples/{scripts => daemontools}/env/USERNAME | 0 samples/{scripts => daemontools}/env/UTXO_MB | 0 samples/{scripts => daemontools}/log/run | 0 samples/{scripts => daemontools}/run | 0 samples/systemd/electrumx.conf | 95 +++++++++++++++++++ .../electrumx.service} | 0 16 files changed, 97 insertions(+), 2 deletions(-) rename samples/{scripts => daemontools}/env/COIN (100%) rename samples/{scripts => daemontools}/env/DAEMON_HOST (100%) rename samples/{scripts => daemontools}/env/DAEMON_PASSWORD (100%) rename samples/{scripts => daemontools}/env/DAEMON_PORT (100%) rename samples/{scripts => daemontools}/env/DAEMON_USERNAME (100%) rename samples/{scripts => daemontools}/env/DB_DIRECTORY (100%) rename samples/{scripts => daemontools}/env/ELECTRUMX (100%) rename samples/{scripts => daemontools}/env/HIST_MB (100%) rename samples/{scripts => daemontools}/env/NETWORK (100%) rename samples/{scripts => daemontools}/env/USERNAME (100%) rename samples/{scripts => daemontools}/env/UTXO_MB (100%) rename samples/{scripts => daemontools}/log/run (100%) rename samples/{scripts => daemontools}/run (100%) create mode 100644 samples/systemd/electrumx.conf rename samples/{systemd-unit => systemd/electrumx.service} (100%) diff --git a/docs/HOWTO.rst b/docs/HOWTO.rst index 79fc35b..2775ec4 100644 --- a/docs/HOWTO.rst +++ b/docs/HOWTO.rst @@ -100,7 +100,7 @@ might do:: Then copy the all sample scripts from the ElectrumX source tree there:: - cp -R /path/to/repo/electrumx/samples/scripts ~/scripts/electrumx + cp -R /path/to/repo/electrumx/samples/daemontools ~/scripts/electrumx This copies 3 things: the top level server run script, a log/ directory with the logger run script, an env/ directory. @@ -136,7 +136,7 @@ Using systemd This repository contains a sample systemd unit file that you can use to setup ElectrumX with systemd. Simply copy it to :code:`/etc/systemd/system`:: - cp samples/systemd-unit /etc/systemd/system/electrumx.service + cp samples/systemd/electrumx.service /etc/systemd/system/ The sample unit file assumes that the repository is located at :code:`/home/electrumx/electrumx`. If that differs on your system, you need to diff --git a/samples/scripts/env/COIN b/samples/daemontools/env/COIN similarity index 100% rename from samples/scripts/env/COIN rename to samples/daemontools/env/COIN diff --git a/samples/scripts/env/DAEMON_HOST b/samples/daemontools/env/DAEMON_HOST similarity index 100% rename from samples/scripts/env/DAEMON_HOST rename to samples/daemontools/env/DAEMON_HOST diff --git a/samples/scripts/env/DAEMON_PASSWORD b/samples/daemontools/env/DAEMON_PASSWORD similarity index 100% rename from samples/scripts/env/DAEMON_PASSWORD rename to samples/daemontools/env/DAEMON_PASSWORD diff --git a/samples/scripts/env/DAEMON_PORT b/samples/daemontools/env/DAEMON_PORT similarity index 100% rename from samples/scripts/env/DAEMON_PORT rename to samples/daemontools/env/DAEMON_PORT diff --git a/samples/scripts/env/DAEMON_USERNAME b/samples/daemontools/env/DAEMON_USERNAME similarity index 100% rename from samples/scripts/env/DAEMON_USERNAME rename to samples/daemontools/env/DAEMON_USERNAME diff --git a/samples/scripts/env/DB_DIRECTORY b/samples/daemontools/env/DB_DIRECTORY similarity index 100% rename from samples/scripts/env/DB_DIRECTORY rename to samples/daemontools/env/DB_DIRECTORY diff --git a/samples/scripts/env/ELECTRUMX b/samples/daemontools/env/ELECTRUMX similarity index 100% rename from samples/scripts/env/ELECTRUMX rename to samples/daemontools/env/ELECTRUMX diff --git a/samples/scripts/env/HIST_MB b/samples/daemontools/env/HIST_MB similarity index 100% rename from samples/scripts/env/HIST_MB rename to samples/daemontools/env/HIST_MB diff --git a/samples/scripts/env/NETWORK b/samples/daemontools/env/NETWORK similarity index 100% rename from samples/scripts/env/NETWORK rename to samples/daemontools/env/NETWORK diff --git a/samples/scripts/env/USERNAME b/samples/daemontools/env/USERNAME similarity index 100% rename from samples/scripts/env/USERNAME rename to samples/daemontools/env/USERNAME diff --git a/samples/scripts/env/UTXO_MB b/samples/daemontools/env/UTXO_MB similarity index 100% rename from samples/scripts/env/UTXO_MB rename to samples/daemontools/env/UTXO_MB diff --git a/samples/scripts/log/run b/samples/daemontools/log/run similarity index 100% rename from samples/scripts/log/run rename to samples/daemontools/log/run diff --git a/samples/scripts/run b/samples/daemontools/run similarity index 100% rename from samples/scripts/run rename to samples/daemontools/run diff --git a/samples/systemd/electrumx.conf b/samples/systemd/electrumx.conf new file mode 100644 index 0000000..54d1f0a --- /dev/null +++ b/samples/systemd/electrumx.conf @@ -0,0 +1,95 @@ +#suggested /etc/electrumx.conf for systemd + +# +#REQUIRED +# + + DB_DIRECTORY = + USERNAME = electrumx + ELECTRUMX = /usr/local/bin/electrumx_server.py + + #Bitcoin Node RPC Credentials + DAEMON_URL = http://username:password@hostname:port/ + #port is optional, defaults to COIN RPC default + +# +#REQUIRED FOR PUBLIC VISIBILITY +# + + #HOST = 0.0.0.0 + #listen on interface, (0.0.0.0 is any) + #TCP_PORT = 50001 + #SSL_PORT = 50002 + #Requires + #SSL_CERTFILE = /path/to/server.crt + #SSL_KEYFILE = /path/to/server.key + +# +#OPTIONAL VISIBILITY +# + + #BANNER_FILE = /path/to/banner + #DONATION_ADDRESS = + #IRC = yes + #IRC_NICK = + #REPORT_HOST = $HOST + #REPORT_TCP_PORT = #defaults to TCP_PORT + #REPORT_SSL_PORT = #defaults to SSL_PORT + #RPC_PORT = 8000 + + +# +#MISC +# + #COIN = Bitcoin # lib/coins.py + #NETWORK = mainnet # lib/coins.py + #DB_ENGINE = leveldb + #leveldb, rocksdb, lmdb (You'll need to install appropriate python packages) + + #REORG_LIMIT = 200 + #maximum number of blocks to be able to handle in a chain + #reorganisation. ElectrumX retains some fairly compact + #undo information for this many blocks in levelDB. + + #ANON_LOGS = + #Set to anything non-empty to remove IP addresses from logs. + + +#These following environment variables are to help limit server +#resource consumption and to prevent simple DoS. Address subscriptions +#in ElectrumX are very cheap - they consume about 100 bytes of memory +#each and are processed efficiently. I feel the defaults are low and +#encourage you to raise them. + + #MAX_SUBS = 250000 + #Maximum number of address subscriptions across all sessions + #MAX_SESSION_SUBS = 50000 + #Maximum number of address subscriptions permitted to a single session. + + +#If synchronizing from the Genesis block your performance might change +#by tweaking the following cache variables. Cache size is only checked +#roughly every minute, so the caches can grow beyond the specified +#size. Also the Python process is often quite a bit fatter than the +#combined cache size, because of Python overhead and also because +#leveldb consumes a lot of memory during UTXO flushing. So I recommend +#you set the sum of these to nothing over half your available physical +#RAM: + + #HIST_MB = 300 + #amount of history cache, in MB, to retain before flushing to + #disk. Default is 300; probably no benefit being much larger + #as history is append-only and not searched. + + #UTXO_MB = 1000 + #amount of UTXO and history cache, in MB, to retain before + #flushing to disk. Default is 1000. This may be too large + #for small boxes or too small for machines with lots of RAM. + #Larger caches generally perform better as there is + #significant searching of the UTXO cache during indexing. + #However, I don't see much benefit in my tests pushing this + #too high, and in fact performance begins to fall. My + #machine has 24GB RAM; the slow down is probably because of + #leveldb caching and Python GC effects. However this may be + #very dependent on hardware and you may have different + #results. diff --git a/samples/systemd-unit b/samples/systemd/electrumx.service similarity index 100% rename from samples/systemd-unit rename to samples/systemd/electrumx.service From 11ed1c4cae0f8c788a83531cef80583f09ac44d5 Mon Sep 17 00:00:00 2001 From: Neil Booth Date: Tue, 22 Nov 2016 06:45:22 +0900 Subject: [PATCH 4/5] Don't log decoding errors any more The can be frequent. Close connections once they reach 10 errors. --- lib/jsonrpc.py | 37 ++++++++++++++++--------------------- 1 file changed, 16 insertions(+), 21 deletions(-) diff --git a/lib/jsonrpc.py b/lib/jsonrpc.py index 205beb3..eff942d 100644 --- a/lib/jsonrpc.py +++ b/lib/jsonrpc.py @@ -117,7 +117,6 @@ class JSONRPC(asyncio.Protocol, LoggedClass): message = message.decode() except UnicodeDecodeError as e: msg = 'cannot decode binary bytes: {}'.format(e) - self.logger.warning(msg) self.send_json_error(msg, self.PARSE_ERROR) return @@ -125,7 +124,6 @@ class JSONRPC(asyncio.Protocol, LoggedClass): message = json.loads(message) except json.JSONDecodeError as e: msg = 'cannot decode JSON: {}'.format(e) - self.logger.warning(msg) self.send_json_error(msg, self.PARSE_ERROR) return @@ -133,52 +131,49 @@ class JSONRPC(asyncio.Protocol, LoggedClass): def send_json_notification(self, method, params): '''Create a json notification.''' - return self.send_json(json_notification_payload(method, params)) + self.send_json(json_notification_payload(method, params)) def send_json_result(self, result, id_): '''Send a JSON result.''' - return self.send_json(json_result_payload(result, id_)) + self.send_json(json_result_payload(result, id_)) def send_json_error(self, message, code, id_=None): '''Send a JSON error.''' + self.send_json(json_error_payload(message, code, id_)) self.error_count += 1 - return self.send_json(json_error_payload(message, code, id_)) + # Close abusive clients + if self.error_count >= 10: + self.transport.close() def send_json(self, payload): '''Send a JSON payload.''' + # Confirmed this happens, sometimes a lot if self.transport.is_closing(): - # Confirmed this happens, sometimes a lot - return False + return try: data = (json.dumps(payload) + '\n').encode() except TypeError: msg = 'JSON encoding failure: {}'.format(payload) self.logger.error(msg) - return self.send_json_error(msg, self.INTERNAL_ERROR, - payload.get('id')) - - self.send_count += 1 - self.send_size += len(data) - self.transport.write(data) - return True + self.send_json_error(msg, self.INTERNAL_ERROR, payload.get('id')) + else: + self.send_count += 1 + self.send_size += len(data) + self.transport.write(data) async def handle_json_request(self, request): '''Asynchronously handle a JSON request. - Handles batch requests. Returns True if the request response - was sent (or if nothing was sent because the request was a - notification). Returns False if the send was aborted because - the connection is closing. + Handles batch requests. ''' if isinstance(request, list): payload = await self.batch_request_payload(request) else: payload = await self.single_request_payload(request) - if not payload: - return True - return self.send_json(payload) + if payload: + self.send_json(payload) async def batch_request_payload(self, batch): '''Return the JSON payload corresponding to a batch JSON request.''' From e5c4bb9743b170093ba6ecc2a006b346c1e917c0 Mon Sep 17 00:00:00 2001 From: Neil Booth Date: Tue, 22 Nov 2016 07:03:37 +0900 Subject: [PATCH 5/5] Prepare 0.7.2 release --- server/version.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server/version.py b/server/version.py index 11f0ca4..7a2a82f 100644 --- a/server/version.py +++ b/server/version.py @@ -1 +1 @@ -VERSION = "ElectrumX 0.7.1" +VERSION = "ElectrumX 0.7.2"