Skip to content

Commit 2e33c11

Browse files
committed
Commit proxy
1 parent 4a303d0 commit 2e33c11

30 files changed

+2566
-2
lines changed

LICENSE

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,29 @@
1+
Ethereum stratum proxy - for ethereum-pools using stratum protocol RPCv2
2+
3+
Copyright (C) 2015 Atrides <mail@dwarfpool.com> http://DwarfPool.com/eth
4+
5+
# Stratum proxy
6+
7+
Copyright (C) slush0
8+
https://github.com/slush0/stratum-mining-proxy
9+
10+
# Stratum protocol
11+
https://github.com/slush0/stratum
12+
13+
Copyright (C) 2012 Marek Palatinus <info@bitcoin.cz>
14+
15+
This program is free software: you can redistribute it and/or modify
16+
it under the terms of the GNU Affero General Public License as
17+
published by the Free Software Foundation, either version 3 of the
18+
License, or any later version.
19+
20+
This program is distributed in the hope that it will be useful,
21+
but WITHOUT ANY WARRANTY; without even the implied warranty of
22+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
23+
GNU Affero General Public License for more details.
24+
25+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
26+
127
GNU GENERAL PUBLIC LICENSE
228
Version 2, June 1991
329

README.md

Lines changed: 108 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,108 @@
1-
# eth-proxy
2-
Stratum proxy for Ethereum
1+
#Description
2+
3+
This is Stratum Proxy for Ethereum-pools (RPCv2) using asynchronous networking written in Python Twisted.
4+
Originally developed for DwarfPool http://dwarfpool.com/eth
5+
6+
**NOTE:** This fork is still in development. Some features may be broken. Please report any broken features or issues.
7+
8+
9+
#Features
10+
11+
* Additional 10%~20% increase of earning compared to standard pools
12+
* ETH stratum proxy
13+
* Only one connection to the pool
14+
* Workers get new jobs immediately
15+
* Submit of shares without network delay, it's like solo-mining but with benefits of professional pool
16+
* Central Wallet configuration, miners doesn't need wallet as username
17+
* Support monitoring via email
18+
* Bypass worker_id for detailed statistic and per rig monitoring
19+
20+
21+
#How it works
22+
23+
Pool A <---+ +-------------+ Rig1 / PC1
24+
(Active) | |
25+
| +-------------+ Rig2 / PC2
26+
| |
27+
Pool B <---+-----StratumProxy <-----+-------------+ Rig3 / PC3
28+
(FailOver) |
29+
+-------------+ Rig4 / PC4
30+
|
31+
+-------------+ Leaserigs
32+
33+
34+
#ToDo
35+
36+
* Automatically failover via proxy
37+
* Create for Windows users compiled .exe file
38+
* pass submitHashrate to pool
39+
40+
41+
#Configuration
42+
43+
* all configs in file config.py
44+
45+
46+
#Command line to miner start, recommended farm-recheck to use with stratum-proxy is 200
47+
48+
* ./ethminer --farm-recheck 200 -G -F http://127.0.0.1:8080/rig1
49+
50+
51+
#Donations
52+
53+
* ETH: 0xb7302f5988cd483db920069a5c88f049a3707e2f
54+
55+
56+
#Requirements
57+
58+
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.
59+
60+
* Python 2.7+
61+
* python-twisted
62+
63+
64+
#Installation and start
65+
66+
* [Linux]
67+
1) install twisted
68+
apt-get install python-twisted
69+
2) start proxy with
70+
python ./eth-proxy.py
71+
72+
* [Windows]
73+
1) Download Python Version 2.7.10 for Windows
74+
https://www.python.org/downloads/
75+
76+
2) Modify PATH variable (how-to http://www.java.com/en/download/help/path.xml) and add
77+
C:\Python27;C:\Python27\Scripts;
78+
79+
3) Install python setuptools
80+
https://pypi.python.org/pypi/setuptools/#windows-7-or-graphical-install
81+
82+
4) Install Python-Twisted
83+
https://pypi.python.org/pypi/Twisted/15.4.0
84+
File Twisted-15.4.0.win32-py2.7.msi (32bit) or Twisted-15.4.0.win-amd64-py2.7.msi (64bit)
85+
86+
5) Install zope.interface, in console run:
87+
easy_install -U zope.interface
88+
89+
6) Install PyWin32 v2.7
90+
pywin32-219.win32-py2.7.exe or pywin32-219.win-amd64-py2.7.exe
91+
http://sourceforge.net/projects/pywin32/files/pywin32/
92+
93+
7) Download eth-proxy. Extract eth-proxy.zip. Change settings in config.py and start with command:
94+
python xmr-proxy.py
95+
96+
97+
#Contact
98+
99+
* I am available via admin@dwarfpool.com
100+
101+
#Credits
102+
103+
* Original version by Slush0 (original stratum code)
104+
* More Features added by GeneralFault, Wadee Womersley and Moopless
105+
106+
#License
107+
108+
* This software is provides AS-IS without any warranties of any kind. Please use at your own risk.

eth-proxy.conf

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
###
2+
# Command line for miners:
3+
#
4+
# ethminer.exe -G -F http://HOST:PORT/
5+
# ethminer.exe -G -F http://HOST:PORT/rig1
6+
#
7+
# ethminer.exe -G -F http://127.0.0.1:8080/
8+
# ethminer.exe -G -F http://192.168.0.33:8080/rig1
9+
#
10+
# You can submit shares without workername or
11+
# You can provide workername:
12+
# - with url like "/rig1"
13+
# - or use automatically numbering(integer) based on IP of miner
14+
###
15+
16+
# Host and port for your workers
17+
HOST = "0.0.0.0"
18+
PORT = 8080
19+
20+
# Coin address where money goes
21+
WALLET = "0x2a65aca4d5fc5b5c859090a6c34d164135398226"
22+
23+
# It's useful for individually monitoring and statistic
24+
ENABLE_WORKER_ID = True
25+
26+
# On DwarfPool you have option to monitor your workers via email.
27+
# If WORKER_ID is enabled, you can monitor every worker/rig separately.
28+
MONITORING = False
29+
MONITORING_EMAIL = "mail@example.com"
30+
31+
# Main pool
32+
POOL_HOST = "eth-ru.dwarfpool.com"
33+
POOL_PORT = 8008
34+
35+
# Failover pool. CURRENTLY DOESN'T WORK!
36+
POOL_FAILOVER_ENABLE = False
37+
POOL_HOST_FAILOVER = "eth-eu.dwarfpool.com"
38+
POOL_PORT_FAILOVER = 8008
39+
40+
# Logging
41+
LOG_TO_FILE = True
42+
43+
# Enable debug
44+
DEBUG = False
45+

eth-proxy.py

Lines changed: 146 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,146 @@
1+
#!/usr/bin/env python
2+
# -*- coding:utf-8 -*-
3+
4+
import time
5+
import os
6+
import socket
7+
8+
from stratum import settings
9+
import stratum.logger
10+
log = stratum.logger.get_logger('proxy')
11+
12+
if __name__ == '__main__':
13+
if len(settings.WALLET)!=42 and len(settings.WALLET)!=40:
14+
log.error("Wrong WALLET!")
15+
quit()
16+
settings.CUSTOM_EMAIL = settings.MONITORING_EMAIL if settings.MONITORING_EMAIL and settings.MONITORING else ""
17+
18+
from twisted.internet import reactor, defer, protocol
19+
from twisted.internet import reactor as reactor2
20+
from stratum.socket_transport import SocketTransportFactory, SocketTransportClientFactory
21+
from stratum.services import ServiceEventHandler
22+
from twisted.web.server import Site
23+
from stratum.custom_exceptions import TransportException
24+
25+
from mining_libs import getwork_listener
26+
from mining_libs import client_service
27+
from mining_libs import jobs
28+
from mining_libs import version
29+
from mining_libs.jobs import Job
30+
31+
def on_shutdown(f):
32+
'''Clean environment properly'''
33+
log.info("Shutting down proxy...")
34+
if os.path.isfile('eth-proxy.pid'):
35+
os.remove('eth-proxy.pid')
36+
f.is_reconnecting = False # Don't let stratum factory to reconnect again
37+
38+
# Support main connection
39+
@defer.inlineCallbacks
40+
def ping(f):
41+
if not f.is_reconnecting:
42+
return
43+
try:
44+
yield (f.rpc('eth_getWork', [], ''))
45+
reactor.callLater(60, ping, f)
46+
except Exception:
47+
pass
48+
49+
@defer.inlineCallbacks
50+
def on_connect(f):
51+
'''Callback when proxy get connected to the pool'''
52+
log.info("Connected to Stratum pool at %s:%d" % f.main_host)
53+
#reactor.callLater(30, f.client.transport.loseConnection)
54+
55+
# Hook to on_connect again
56+
f.on_connect.addCallback(on_connect)
57+
58+
# Get first job and user_id
59+
initial_job = (yield f.rpc('eth_submitLogin', [settings.WALLET, settings.CUSTOM_EMAIL], 'Proxy_'+version.VERSION))
60+
61+
reactor.callLater(0, ping, f)
62+
63+
defer.returnValue(f)
64+
65+
def on_disconnect(f):
66+
'''Callback when proxy get disconnected from the pool'''
67+
log.info("Disconnected from Stratum pool at %s:%d" % f.main_host)
68+
f.on_disconnect.addCallback(on_disconnect)
69+
70+
# Prepare to failover, currently works very bad
71+
#if f.main_host==(settings.POOL_HOST, settings.POOL_PORT):
72+
# main()
73+
#else:
74+
# f.is_reconnecting = False
75+
#return f
76+
77+
@defer.inlineCallbacks
78+
def main():
79+
reactor.disconnectAll()
80+
failover = False
81+
if settings.POOL_FAILOVER_ENABLE:
82+
failover = settings.failover_pool
83+
settings.failover_pool = not settings.failover_pool
84+
85+
pool_host = settings.POOL_HOST
86+
pool_port = settings.POOL_PORT
87+
if failover and settings.POOL_FAILOVER_ENABLE:
88+
pool_host = settings.POOL_HOST_FAILOVER
89+
pool_port = settings.POOL_PORT_FAILOVER
90+
91+
log.warning("Ethereum Stratum proxy version: %s" % version.VERSION)
92+
log.warning("Trying to connect to Stratum pool at %s:%d" % (pool_host, pool_port))
93+
94+
# Connect to Stratum pool, main monitoring connection
95+
f = SocketTransportClientFactory(pool_host, pool_port,
96+
debug=settings.DEBUG, proxy=None,
97+
event_handler=client_service.ClientMiningService)
98+
99+
job_registry = jobs.JobRegistry(f)
100+
client_service.ClientMiningService.job_registry = job_registry
101+
client_service.ClientMiningService.reset_timeout()
102+
103+
f.on_connect.addCallback(on_connect)
104+
f.on_disconnect.addCallback(on_disconnect)
105+
# Cleanup properly on shutdown
106+
reactor.addSystemEventTrigger('before', 'shutdown', on_shutdown, f)
107+
108+
# Block until proxy connect to the pool
109+
try:
110+
yield f.on_connect
111+
except TransportException:
112+
log.warning("First pool server must be online first time to start failover")
113+
return
114+
115+
conn = reactor.listenTCP(settings.PORT, Site(getwork_listener.Root(job_registry, settings.ENABLE_WORKER_ID)), interface=settings.HOST)
116+
117+
try:
118+
conn.socket.setsockopt(socket.SOL_SOCKET, socket.SO_KEEPALIVE, 1) # Enable keepalive packets
119+
conn.socket.setsockopt(socket.SOL_TCP, socket.TCP_KEEPIDLE, 60) # Seconds before sending keepalive probes
120+
conn.socket.setsockopt(socket.SOL_TCP, socket.TCP_KEEPINTVL, 1) # Interval in seconds between keepalive probes
121+
conn.socket.setsockopt(socket.SOL_TCP, socket.TCP_KEEPCNT, 5) # Failed keepalive probles before declaring other end dead
122+
except:
123+
pass # Some socket features are not available on all platforms (you can guess which one)
124+
125+
log.warning("-----------------------------------------------------------------------")
126+
if settings.HOST == '0.0.0.0':
127+
log.warning("PROXY IS LISTENING ON ALL IPs ON PORT %d" % settings.PORT)
128+
else:
129+
log.warning("LISTENING FOR MINERS ON http://%s:%d" % (settings.HOST, settings.PORT))
130+
log.warning("-----------------------------------------------------------------------")
131+
log.warning("Wallet: %s" % settings.WALLET)
132+
log.warning("Worker ID enabled: %s" % settings.ENABLE_WORKER_ID)
133+
if settings.MONITORING:
134+
log.warning("Email monitoring on %s" % settings.MONITORING_EMAIL)
135+
else:
136+
log.warning("Email monitoring diasbled")
137+
#log.warning("Failover enabled: %" % settings.POOL_FAILOVER_ENABLE)
138+
log.warning("-----------------------------------------------------------------------")
139+
140+
if __name__ == '__main__':
141+
fp = file("eth-proxy.pid", 'w')
142+
fp.write(str(os.getpid()))
143+
fp.close()
144+
settings.failover_pool = False
145+
main()
146+
reactor.run()

mining_libs/__init__.py

Whitespace-only changes.

mining_libs/client_service.py

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
from twisted.internet import reactor
2+
3+
from stratum.event_handler import GenericEventHandler
4+
from jobs import Job
5+
import version as _version
6+
7+
import stratum.logger
8+
log = stratum.logger.get_logger('proxy')
9+
10+
class ClientMiningService(GenericEventHandler):
11+
job_registry = None # Reference to JobRegistry instance
12+
timeout = None # Reference to IReactorTime object
13+
14+
@classmethod
15+
def reset_timeout(cls):
16+
if cls.timeout != None:
17+
if not cls.timeout.called:
18+
cls.timeout.cancel()
19+
cls.timeout = None
20+
21+
cls.timeout = reactor.callLater(960, cls.on_timeout)
22+
23+
@classmethod
24+
def on_timeout(cls):
25+
'''
26+
Try to reconnect to the pool after 16 minutes of no activity on the connection.
27+
It will also drop all Stratum connections to sub-miners
28+
to indicate connection issues.
29+
'''
30+
log.error("Connection to upstream pool timed out")
31+
cls.reset_timeout()
32+
cls.job_registry.f.reconnect()
33+
34+
def handle_event(self, method, params, connection_ref):
35+
'''Handle RPC calls and notifications from the pool'''
36+
# Yay, we received something from the pool,
37+
# let's restart the timeout.
38+
self.reset_timeout()
39+
40+
if method == 'eth_getWork':
41+
'''Proxy just received information about new mining job'''
42+
# Broadcast to getwork clients
43+
job = Job.build_from_pool(params)
44+
if stratum.logger.settings.DEBUG:
45+
log.debug("NEW_JOB %s" % params)
46+
else:
47+
log.info("NEW_JOB")
48+
self.job_registry.replace_job(job)
49+
50+
else:
51+
'''Pool just asked us for something which we don't support...'''
52+
log.error("Unhandled method %s with params %s" % (method, params))

0 commit comments

Comments
 (0)