From de4930b96d2501da9ed93b46e8557b06a7108bf8 Mon Sep 17 00:00:00 2001 From: Neil Booth Date: Thu, 24 Nov 2016 23:30:40 +0900 Subject: [PATCH] Introduce MAX_HIST environment variable. --- docs/ENV-NOTES | 8 ++++++++ server/env.py | 3 ++- server/protocol.py | 4 +++- 3 files changed, 13 insertions(+), 2 deletions(-) diff --git a/docs/ENV-NOTES b/docs/ENV-NOTES index f76af1c..85243b1 100644 --- a/docs/ENV-NOTES +++ b/docs/ENV-NOTES @@ -44,6 +44,14 @@ 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_HIST - maximum number of historical transactions to serve for an + address. The current Electrum protocol requires + address histories be served en-masse or not at all, + an obvious avenue for abuse. This limit is a stop-gap + until the protocol is improved to admit incremental + history requests. The default value is 2,000 which is + I feel is low. Increasing to around 10,000 is probably + fine but beyond that experimental. MAX_SUBS - maximum number of address subscriptions across all sessions. Defaults to 250,000. MAX_SESSION_SUBS - maximum number of address subscriptions permitted to a diff --git a/server/env.py b/server/env.py index bfddcf6..b62b8fa 100644 --- a/server/env.py +++ b/server/env.py @@ -44,7 +44,8 @@ class Env(LoggedClass): # The electrum client takes the empty string as unspecified self.donation_address = self.default('DONATION_ADDRESS', '') self.db_engine = self.default('DB_ENGINE', 'leveldb') - # Subscription limits + # Server limits to help prevent DoS + self.max_hist = self.integer('MAX_HIST', 2000) self.max_subs = self.integer('MAX_SUBS', 250000) self.max_session_subs = self.integer('MAX_SESSION_SUBS', 50000) # IRC diff --git a/server/protocol.py b/server/protocol.py index c14e745..dcb9e63 100644 --- a/server/protocol.py +++ b/server/protocol.py @@ -674,9 +674,11 @@ class ElectrumX(Session): return self.bp.read_headers(start_height, count).hex() async def async_get_history(self, hash168): + # Apply DoS limit + limit = self.env.max_hist # Python 3.6: use async generators; update callers history = [] - for item in self.bp.get_history(hash168, limit=None): + for item in self.bp.get_history(hash168, limit=limit): history.append(item) if len(history) % 100 == 0: await asyncio.sleep(0)