Skip to content

Commit

Permalink
Failover server works now. Submit hashrates.
Browse files Browse the repository at this point in the history
  • Loading branch information
Atrides committed Oct 18, 2015
1 parent cb3db4e commit 8a2e2b9
Show file tree
Hide file tree
Showing 9 changed files with 88 additions and 57 deletions.
9 changes: 4 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand All @@ -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
Expand Down
14 changes: 10 additions & 4 deletions eth-proxy.conf
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -29,12 +35,12 @@ MONITORING = False
MONITORING_EMAIL = "[email protected]"

# 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
Expand Down
49 changes: 24 additions & 25 deletions eth-proxy.py
Original file line number Diff line number Diff line change
Expand Up @@ -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)

Expand All @@ -65,51 +68,48 @@ 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()

f.on_connect.addCallback(on_connect)
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)
Expand All @@ -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()
17 changes: 8 additions & 9 deletions mining_libs/client_service.py
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -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...'''
Expand Down
7 changes: 6 additions & 1 deletion mining_libs/getwork_listener.py
Original file line number Diff line number Diff line change
Expand Up @@ -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})
Expand Down Expand Up @@ -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:
Expand Down
44 changes: 33 additions & 11 deletions mining_libs/jobs.py
Original file line number Diff line number Diff line change
Expand Up @@ -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)
2 changes: 1 addition & 1 deletion mining_libs/version.py
Original file line number Diff line number Diff line change
@@ -1 +1 @@
VERSION='0.0.3'
VERSION='0.0.4'
2 changes: 1 addition & 1 deletion stratum/config_default.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
1 change: 1 addition & 0 deletions stratum/socket_transport.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down

0 comments on commit 8a2e2b9

Please sign in to comment.