Skip to content

Commit

Permalink
Commit proxy
Browse files Browse the repository at this point in the history
  • Loading branch information
freebazaar committed Oct 12, 2015
1 parent 4a303d0 commit 2e33c11
Show file tree
Hide file tree
Showing 30 changed files with 2,566 additions and 2 deletions.
26 changes: 26 additions & 0 deletions LICENSE
Original file line number Diff line number Diff line change
@@ -1,3 +1,29 @@
Ethereum stratum proxy - for ethereum-pools using stratum protocol RPCv2

Copyright (C) 2015 Atrides <[email protected]> http://DwarfPool.com/eth

# Stratum proxy

Copyright (C) slush0
https://github.com/slush0/stratum-mining-proxy

# Stratum protocol
https://github.com/slush0/stratum

Copyright (C) 2012 Marek Palatinus <[email protected]>

This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as
published by the Free Software Foundation, either version 3 of the
License, or any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

GNU GENERAL PUBLIC LICENSE
Version 2, June 1991

Expand Down
110 changes: 108 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,2 +1,108 @@
# eth-proxy
Stratum proxy for Ethereum
#Description

This is Stratum Proxy for Ethereum-pools (RPCv2) using asynchronous networking written in Python Twisted.
Originally developed for DwarfPool http://dwarfpool.com/eth

**NOTE:** This fork is still in development. Some features may be broken. Please report any broken features or issues.


#Features

* Additional 10%~20% increase of earning compared to standard pools
* ETH stratum 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


#How it works

Pool A <---+ +-------------+ Rig1 / PC1
(Active) | |
| +-------------+ Rig2 / PC2
| |
Pool B <---+-----StratumProxy <-----+-------------+ Rig3 / PC3
(FailOver) |
+-------------+ Rig4 / PC4
|
+-------------+ Leaserigs


#ToDo

* Automatically failover via proxy
* Create for Windows users compiled .exe file
* pass submitHashrate to pool


#Configuration

* all configs in file config.py


#Command line to miner start, recommended farm-recheck to use with stratum-proxy is 200

* ./ethminer --farm-recheck 200 -G -F http://127.0.0.1:8080/rig1


#Donations

* ETH: 0xb7302f5988cd483db920069a5c88f049a3707e2f


#Requirements

eth-proxy is built in python. I have been testing it with 2.7.3, but it should work with other versions. The requirements for running the software are below.

* Python 2.7+
* python-twisted


#Installation and start

* [Linux]
1) install twisted
apt-get install python-twisted
2) start proxy with
python ./eth-proxy.py

* [Windows]
1) Download Python Version 2.7.10 for Windows
https://www.python.org/downloads/

2) Modify PATH variable (how-to http://www.java.com/en/download/help/path.xml) and add
C:\Python27;C:\Python27\Scripts;

3) Install python setuptools
https://pypi.python.org/pypi/setuptools/#windows-7-or-graphical-install

4) Install Python-Twisted
https://pypi.python.org/pypi/Twisted/15.4.0
File Twisted-15.4.0.win32-py2.7.msi (32bit) or Twisted-15.4.0.win-amd64-py2.7.msi (64bit)

5) Install zope.interface, in console run:
easy_install -U zope.interface

6) Install PyWin32 v2.7
pywin32-219.win32-py2.7.exe or pywin32-219.win-amd64-py2.7.exe
http://sourceforge.net/projects/pywin32/files/pywin32/

7) Download eth-proxy. Extract eth-proxy.zip. Change settings in config.py and start with command:
python xmr-proxy.py


#Contact

* I am available via [email protected]

#Credits

* Original version by Slush0 (original stratum code)
* More Features added by GeneralFault, Wadee Womersley and Moopless

#License

* This software is provides AS-IS without any warranties of any kind. Please use at your own risk.
45 changes: 45 additions & 0 deletions eth-proxy.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
###
# Command line for miners:
#
# ethminer.exe -G -F http://HOST:PORT/
# ethminer.exe -G -F http://HOST:PORT/rig1
#
# ethminer.exe -G -F http://127.0.0.1:8080/
# ethminer.exe -G -F http://192.168.0.33:8080/rig1
#
# You can submit shares without workername or
# You can provide workername:
# - with url like "/rig1"
# - or use automatically numbering(integer) based on IP of miner
###

# Host and port for your workers
HOST = "0.0.0.0"
PORT = 8080

# Coin address where money goes
WALLET = "0x2a65aca4d5fc5b5c859090a6c34d164135398226"

# It's useful for individually monitoring and statistic
ENABLE_WORKER_ID = True

# On DwarfPool you have option to monitor your workers via email.
# If WORKER_ID is enabled, you can monitor every worker/rig separately.
MONITORING = False
MONITORING_EMAIL = "[email protected]"

# Main pool
POOL_HOST = "eth-ru.dwarfpool.com"
POOL_PORT = 8008

# Failover pool. CURRENTLY DOESN'T WORK!
POOL_FAILOVER_ENABLE = False
POOL_HOST_FAILOVER = "eth-eu.dwarfpool.com"
POOL_PORT_FAILOVER = 8008

# Logging
LOG_TO_FILE = True

# Enable debug
DEBUG = False

146 changes: 146 additions & 0 deletions eth-proxy.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,146 @@
#!/usr/bin/env python
# -*- coding:utf-8 -*-

import time
import os
import socket

from stratum import settings
import stratum.logger
log = stratum.logger.get_logger('proxy')

if __name__ == '__main__':
if len(settings.WALLET)!=42 and len(settings.WALLET)!=40:
log.error("Wrong WALLET!")
quit()
settings.CUSTOM_EMAIL = settings.MONITORING_EMAIL if settings.MONITORING_EMAIL and settings.MONITORING else ""

from twisted.internet import reactor, defer, protocol
from twisted.internet import reactor as reactor2
from stratum.socket_transport import SocketTransportFactory, SocketTransportClientFactory
from stratum.services import ServiceEventHandler
from twisted.web.server import Site
from stratum.custom_exceptions import TransportException

from mining_libs import getwork_listener
from mining_libs import client_service
from mining_libs import jobs
from mining_libs import version
from mining_libs.jobs import Job

def on_shutdown(f):
'''Clean environment properly'''
log.info("Shutting down proxy...")
if os.path.isfile('eth-proxy.pid'):
os.remove('eth-proxy.pid')
f.is_reconnecting = False # Don't let stratum factory to reconnect again

# Support main connection
@defer.inlineCallbacks
def ping(f):
if not f.is_reconnecting:
return
try:
yield (f.rpc('eth_getWork', [], ''))
reactor.callLater(60, ping, f)
except Exception:
pass

@defer.inlineCallbacks
def on_connect(f):
'''Callback when proxy get connected to the pool'''
log.info("Connected to Stratum pool at %s:%d" % f.main_host)
#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))

reactor.callLater(0, ping, f)

defer.returnValue(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.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,
debug=settings.DEBUG, proxy=None,
event_handler=client_service.ClientMiningService)

job_registry = jobs.JobRegistry(f)
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)

# 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")
return

conn = reactor.listenTCP(settings.PORT, Site(getwork_listener.Root(job_registry, settings.ENABLE_WORKER_ID)), interface=settings.HOST)

try:
conn.socket.setsockopt(socket.SOL_SOCKET, socket.SO_KEEPALIVE, 1) # Enable keepalive packets
conn.socket.setsockopt(socket.SOL_TCP, socket.TCP_KEEPIDLE, 60) # Seconds before sending keepalive probes
conn.socket.setsockopt(socket.SOL_TCP, socket.TCP_KEEPINTVL, 1) # Interval in seconds between keepalive probes
conn.socket.setsockopt(socket.SOL_TCP, socket.TCP_KEEPCNT, 5) # Failed keepalive probles before declaring other end dead
except:
pass # Some socket features are not available on all platforms (you can guess which one)

log.warning("-----------------------------------------------------------------------")
if settings.HOST == '0.0.0.0':
log.warning("PROXY IS LISTENING ON ALL IPs ON PORT %d" % settings.PORT)
else:
log.warning("LISTENING FOR MINERS ON http://%s:%d" % (settings.HOST, settings.PORT))
log.warning("-----------------------------------------------------------------------")
log.warning("Wallet: %s" % settings.WALLET)
log.warning("Worker ID enabled: %s" % settings.ENABLE_WORKER_ID)
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("-----------------------------------------------------------------------")

if __name__ == '__main__':
fp = file("eth-proxy.pid", 'w')
fp.write(str(os.getpid()))
fp.close()
settings.failover_pool = False
main()
reactor.run()
Empty file added mining_libs/__init__.py
Empty file.
52 changes: 52 additions & 0 deletions mining_libs/client_service.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
from twisted.internet import reactor

from stratum.event_handler import GenericEventHandler
from jobs import Job
import version as _version

import stratum.logger
log = stratum.logger.get_logger('proxy')

class ClientMiningService(GenericEventHandler):
job_registry = None # Reference to JobRegistry instance
timeout = None # Reference to IReactorTime object

@classmethod
def reset_timeout(cls):
if cls.timeout != None:
if not cls.timeout.called:
cls.timeout.cancel()
cls.timeout = None

cls.timeout = reactor.callLater(960, cls.on_timeout)

@classmethod
def on_timeout(cls):
'''
Try to reconnect to the pool after 16 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()

def handle_event(self, method, params, connection_ref):
'''Handle RPC calls and notifications from the pool'''
# Yay, we received something from the pool,
# let's restart the timeout.
self.reset_timeout()

if method == 'eth_getWork':
'''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)

else:
'''Pool just asked us for something which we don't support...'''
log.error("Unhandled method %s with params %s" % (method, params))
Loading

0 comments on commit 2e33c11

Please sign in to comment.