From 8a2e2b9e9750aaea13ff1e08bf894663374bf371 Mon Sep 17 00:00:00 2001 From: Atrides Date: Sun, 18 Oct 2015 18:07:56 +0200 Subject: [PATCH] Failover server works now. Submit hashrates. --- README.md | 9 +++--- eth-proxy.conf | 14 +++++++--- eth-proxy.py | 49 ++++++++++++++++----------------- mining_libs/client_service.py | 17 ++++++------ mining_libs/getwork_listener.py | 7 ++++- mining_libs/jobs.py | 44 +++++++++++++++++++++-------- mining_libs/version.py | 2 +- stratum/config_default.py | 2 +- stratum/socket_transport.py | 1 + 9 files changed, 88 insertions(+), 57 deletions(-) diff --git a/README.md b/README.md index d3752ed..a18742b 100644 --- a/README.md +++ b/README.md @@ -8,15 +8,16 @@ Originally developed for DwarfPool http://dwarfpool.com/eth #Features -* Additional 10%~20% increase of earning compared to standard pools +* Additional up to 20% increase of earning compared to standard pools * ETH stratum proxy +* Automatically failover via proxy * Only one connection to the pool * Workers get new jobs immediately * Submit of shares without network delay, it's like solo-mining but with benefits of professional pool * Central Wallet configuration, miners doesn't need wallet as username * Support monitoring via email * Bypass worker_id for detailed statistic and per rig monitoring - +* pass submitHashrate to pool #How it works @@ -33,9 +34,7 @@ Originally developed for DwarfPool http://dwarfpool.com/eth #ToDo -* Automatically failover via proxy -* Create for Windows users compiled .exe file -* pass submitHashrate to pool +* --- #Configuration diff --git a/eth-proxy.conf b/eth-proxy.conf index 0e7af06..dcb158f 100644 --- a/eth-proxy.conf +++ b/eth-proxy.conf @@ -11,6 +11,12 @@ # You can provide workername: # - with url like "/rig1" # - or use automatically numbering(integer) based on IP of miner +# +# Servers: +# EU-Server: eth-eu.dwarfpool.com (France) +# US-Server: eth-us.dwarfpool.com (Montreal,Canada) +# RU-Server: eth-ru.dwarfpool.com (Moscow) +# ### # Host and port for your workers @@ -29,12 +35,12 @@ MONITORING = False MONITORING_EMAIL = "mail@example.com" # Main pool -POOL_HOST = "eth-ru.dwarfpool.com" +POOL_HOST = "eth-eu.dwarfpool.com" POOL_PORT = 8008 -# Failover pool. CURRENTLY DOESN'T WORK! -POOL_FAILOVER_ENABLE = False -POOL_HOST_FAILOVER = "eth-eu.dwarfpool.com" +# Failover pool +POOL_FAILOVER_ENABLE = True +POOL_HOST_FAILOVER = "eth-us.dwarfpool.com" POOL_PORT_FAILOVER = 8008 # Logging diff --git a/eth-proxy.py b/eth-proxy.py index 0010696..dbfaf58 100644 --- a/eth-proxy.py +++ b/eth-proxy.py @@ -50,13 +50,16 @@ def ping(f): def on_connect(f): '''Callback when proxy get connected to the pool''' log.info("Connected to Stratum pool at %s:%d" % f.main_host) + f.is_connected = True + f.remote_ip = f.client._get_ip() #reactor.callLater(30, f.client.transport.loseConnection) # Hook to on_connect again f.on_connect.addCallback(on_connect) # Get first job and user_id - initial_job = (yield f.rpc('eth_submitLogin', [settings.WALLET, settings.CUSTOM_EMAIL], 'Proxy_'+version.VERSION)) + debug = "_debug" if settings.DEBUG else "" + initial_job = (yield f.rpc('eth_submitLogin', [settings.WALLET, settings.CUSTOM_EMAIL], 'Proxy_'+version.VERSION+debug)) reactor.callLater(0, ping, f) @@ -65,38 +68,31 @@ def on_connect(f): def on_disconnect(f): '''Callback when proxy get disconnected from the pool''' log.info("Disconnected from Stratum pool at %s:%d" % f.main_host) + f.is_connected = False f.on_disconnect.addCallback(on_disconnect) - # Prepare to failover, currently works very bad - #if f.main_host==(settings.POOL_HOST, settings.POOL_PORT): - # main() - #else: - # f.is_reconnecting = False - #return f - @defer.inlineCallbacks def main(): reactor.disconnectAll() - failover = False - if settings.POOL_FAILOVER_ENABLE: - failover = settings.failover_pool - settings.failover_pool = not settings.failover_pool - - pool_host = settings.POOL_HOST - pool_port = settings.POOL_PORT - if failover and settings.POOL_FAILOVER_ENABLE: - pool_host = settings.POOL_HOST_FAILOVER - pool_port = settings.POOL_PORT_FAILOVER log.warning("Ethereum Stratum proxy version: %s" % version.VERSION) - log.warning("Trying to connect to Stratum pool at %s:%d" % (pool_host, pool_port)) # Connect to Stratum pool, main monitoring connection - f = SocketTransportClientFactory(pool_host, pool_port, + log.warning("Trying to connect to Stratum pool at %s:%d" % (settings.POOL_HOST, settings.POOL_PORT)) + f = SocketTransportClientFactory(settings.POOL_HOST, settings.POOL_PORT, + debug=settings.DEBUG, proxy=None, + event_handler=client_service.ClientMiningService) + f.is_failover = False + + ff = None + if settings.POOL_FAILOVER_ENABLE: + log.warning("Trying to connect to failover Stratum pool at %s:%d" % (settings.POOL_HOST_FAILOVER, settings.POOL_PORT_FAILOVER)) + ff = SocketTransportClientFactory(settings.POOL_HOST_FAILOVER, settings.POOL_PORT_FAILOVER, debug=settings.DEBUG, proxy=None, event_handler=client_service.ClientMiningService) + ff.is_failover = True - job_registry = jobs.JobRegistry(f) + job_registry = jobs.JobRegistry(f,ff) client_service.ClientMiningService.job_registry = job_registry client_service.ClientMiningService.reset_timeout() @@ -104,12 +100,16 @@ def main(): f.on_disconnect.addCallback(on_disconnect) # Cleanup properly on shutdown reactor.addSystemEventTrigger('before', 'shutdown', on_shutdown, f) + if ff: + ff.on_connect.addCallback(on_connect) + ff.on_disconnect.addCallback(on_disconnect) + reactor.addSystemEventTrigger('before', 'shutdown', on_shutdown, ff) # Block until proxy connect to the pool try: yield f.on_connect except TransportException: - log.warning("First pool server must be online first time to start failover") + log.warning("First pool server must be online first time during start") return conn = reactor.listenTCP(settings.PORT, Site(getwork_listener.Root(job_registry, settings.ENABLE_WORKER_ID)), interface=settings.HOST) @@ -133,14 +133,13 @@ def main(): if settings.MONITORING: log.warning("Email monitoring on %s" % settings.MONITORING_EMAIL) else: - log.warning("Email monitoring diasbled") - #log.warning("Failover enabled: %" % settings.POOL_FAILOVER_ENABLE) + log.warning("Email monitoring disabled") + log.warning("Failover enabled: %s" % settings.POOL_FAILOVER_ENABLE) log.warning("-----------------------------------------------------------------------") if __name__ == '__main__': fp = file("eth-proxy.pid", 'w') fp.write(str(os.getpid())) fp.close() - settings.failover_pool = False main() reactor.run() diff --git a/mining_libs/client_service.py b/mining_libs/client_service.py index 8d08036..ed4d35d 100644 --- a/mining_libs/client_service.py +++ b/mining_libs/client_service.py @@ -18,19 +18,22 @@ def reset_timeout(cls): cls.timeout.cancel() cls.timeout = None - cls.timeout = reactor.callLater(960, cls.on_timeout) + cls.timeout = reactor.callLater(180, cls.on_timeout) @classmethod def on_timeout(cls): ''' - Try to reconnect to the pool after 16 minutes of no activity on the connection. + Try to reconnect to the pool after 3 minutes of no activity on the connection. It will also drop all Stratum connections to sub-miners to indicate connection issues. ''' log.error("Connection to upstream pool timed out") cls.reset_timeout() - cls.job_registry.f.reconnect() - + if not cls.job_registry.f.is_connected: + cls.job_registry.f.reconnect() + if cls.job_registry.ff and not cls.job_registry.ff.is_connected: + cls.job_registry.ff.reconnect() + def handle_event(self, method, params, connection_ref): '''Handle RPC calls and notifications from the pool''' # Yay, we received something from the pool, @@ -41,11 +44,7 @@ def handle_event(self, method, params, connection_ref): '''Proxy just received information about new mining job''' # Broadcast to getwork clients job = Job.build_from_pool(params) - if stratum.logger.settings.DEBUG: - log.debug("NEW_JOB %s" % params) - else: - log.info("NEW_JOB") - self.job_registry.replace_job(job) + self.job_registry.replace_job(job, connection_ref) else: '''Pool just asked us for something which we don't support...''' diff --git a/mining_libs/getwork_listener.py b/mining_libs/getwork_listener.py index 756f952..e0e8b1e 100644 --- a/mining_libs/getwork_listener.py +++ b/mining_libs/getwork_listener.py @@ -15,6 +15,7 @@ def __init__(self, job_registry, enable_worker_id): Resource.__init__(self) self.job_registry = job_registry self.isWorkerID = enable_worker_id + self.submitHashrates = {} def json_response(self, msg_id, result): resp = json.dumps({'id': msg_id, 'jsonrpc': '2.0', 'result': result}) @@ -47,7 +48,11 @@ def render_POST(self, request): else: worker_name = '' - if data['method'] == 'eth_submitWork': # ToFix!!!! + if data['method'] == 'eth_submitHashrate': + if worker_name and (not self.submitHashrates.has_key(worker_name) or int(time.time())-self.submitHashrates[worker_name]>=60): + self.submitHashrates[worker_name] = int(time.time()) + threads.deferToThread(self.job_registry.submit, data['method'], data['params'], worker_name) + elif data['method'] == 'eth_submitWork': threads.deferToThread(self.job_registry.submit, data['method'], data['params'], worker_name) response = self.json_response(data.get('id', 0), True) else: diff --git a/mining_libs/jobs.py b/mining_libs/jobs.py index 9ab7ef8..1624b19 100644 --- a/mining_libs/jobs.py +++ b/mining_libs/jobs.py @@ -16,22 +16,44 @@ def build_from_pool(cls, getWorkParams): return job class JobRegistry(object): - def __init__(self, f): + def __init__(self, f, ff): self.f = f + self.ff = ff self.jobs = None # Hook for LP broadcasts self.on_block = defer.Deferred() - def replace_job(self, newjob): - self.jobs = newjob - # Force miners to reload jobs - on_block = self.on_block - self.on_block = defer.Deferred() - on_block.callback(True) + def replace_job(self, newjob, connection_ref): + is_main_pool = connection_ref._get_ip() == self.f.remote_ip + if is_main_pool: + log_text = "MAIN NEW_JOB" + else: + log_text = "FAILOVER NEW_JOB" + + if (self.f.is_connected and is_main_pool) or (not self.f.is_connected and self.ff and self.ff.is_connected and not is_main_pool): + if stratum.logger.settings.DEBUG: + log.debug("%s %s" % (log_text, newjob.params)) + else: + log.info(log_text) + self.jobs = newjob + # Force miners to reload jobs + on_block = self.on_block + self.on_block = defer.Deferred() + on_block.callback(True) + elif stratum.logger.settings.DEBUG: + log.debug("%s NOT_USED %s" % (log_text, newjob.params)) def submit(self, method, params, worker_name): + log_text = "" if settings.DEBUG: - log.info("%s by %s %s" % (method, worker_name, params)) - else: - log.info("%s by %s" % (method, worker_name) ) - self.f.rpc(method, params, worker_name) + log_text = "%s by %s %s" % (method, worker_name, params) + elif method=="eth_submitWork": + log_text = "%s by %s" % (method, worker_name) + if self.f.is_connected: + if log_text: + log.info( "MAIN %s" % log_text ) + self.f.rpc(method, params, worker_name) + elif self.ff and self.ff.is_connected: + if log_text: + log.info( "FAILOVER %s" % log_text ) + self.ff.rpc(method, params, worker_name) diff --git a/mining_libs/version.py b/mining_libs/version.py index d814d9d..4c02f0f 100644 --- a/mining_libs/version.py +++ b/mining_libs/version.py @@ -1 +1 @@ -VERSION='0.0.3' +VERSION='0.0.4' diff --git a/stratum/config_default.py b/stratum/config_default.py index a3114d5..49d0881 100644 --- a/stratum/config_default.py +++ b/stratum/config_default.py @@ -156,7 +156,7 @@ POOL_HOST = 'eth-ru.dwarfpool.com' POOL_PORT = 8008 -# Failover pool. CURRENTLY DOESN'T WORK! +# Failover pool. POOL_FAILOVER_ENABLE = False POOL_HOST_FAILOVER = 'eth-eu.dwarfpool.com' POOL_PORT_FAILOVER = 8008 diff --git a/stratum/socket_transport.py b/stratum/socket_transport.py index 5dc6f40..c803631 100644 --- a/stratum/socket_transport.py +++ b/stratum/socket_transport.py @@ -32,6 +32,7 @@ def __init__(self, host, port, allow_trusted=True, allow_untrusted=False, is_reconnecting=True, proxy=None, event_handler=GenericEventHandler): self.debug = debug + self.maxDelay = 60 self.is_reconnecting = is_reconnecting self.signing_key = signing_key self.signing_id = signing_id