-
Notifications
You must be signed in to change notification settings - Fork 347
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Initial Commit of Stratum + Getwork Proxy
- Loading branch information
0 parents
commit 429baa7
Showing
33 changed files
with
3,605 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
Stratum mining - *coin pool using Stratum protocol | ||
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. | ||
|
||
You should have received a copy of the GNU Affero General Public License | ||
along with this program. If not, see <http://www.gnu.org/licenses/>. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,58 @@ | ||
#Description | ||
Stratum-mining is a pooled mining protocol. It is a replacement for *getwork* based pooling servers by allowing clients to generate work. The stratum protocol is described [here](http://mining.bitcoin.cz/stratum-mining) in full detail. | ||
|
||
This is a implementation of stratum-mining for scrypt based coins. It is compatible with *MPOS* as well as *mmcfe*, as it complies with the standards of *pushpool*. The end goal is to build on these standards to come up with a more stable solution. | ||
|
||
The goal is to make a reliable stratum mining server for scrypt based coins. Over time I will develop this to be more feature rich and very stable. If you would like to see a feature please file a feature request. | ||
|
||
**NOTE:** This fork is still in development. Many features may be broken. Please report any broken features or issues. | ||
|
||
#Features | ||
|
||
* Stratum Mining Pool | ||
* Solved Block Confirmation | ||
* Vardiff support | ||
* Solution Block Hash Support | ||
* *NEW* SHA256 and Scrypt Algo Support | ||
* Log Rotation | ||
* Initial low difficulty share confirmation | ||
* Multiple *coind* wallets | ||
* On the fly addition of new *coind* wallets | ||
* MySQL database support | ||
* Adjustable database commit parameters | ||
* Bypass password check for workers | ||
|
||
|
||
#Requirements | ||
*stratum-mining* 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 | ||
* stratum | ||
* MySQL Server | ||
* SHA256 or Scrypt CoinDaemon | ||
|
||
Other coins have been known to work with this implementation. I have tested with the following coins, but there may be many others that work. | ||
|
||
*Orbitcoin | ||
*FireFlyCoin | ||
|
||
#Installation | ||
|
||
The installation of this *stratum-mining* can be found in the INSTALL.md file. | ||
|
||
#Contact | ||
I am available in the #MPOS, #crypto-expert, #digitalcoin, #bytecoin and #worldcoin channels on freenode. Although i am willing to provide support through IRC please file issues on the repo | ||
|
||
#Credits | ||
|
||
* Original version by Slush0 (original stratum code) | ||
* More Features added by GeneralFault, Wadee Womersley and Moopless | ||
* Scrypt conversion from work done by viperaus | ||
* PoS conversion done by TheSeven | ||
* Modifications to make it more user friendly and easier to setup for multiple coins done by Ahmed_Bodi | ||
|
||
|
||
#License | ||
This software is provides AS-IS without any warranties of any kind. Please use at your own risk. | ||
|
Empty file.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,147 @@ | ||
''' | ||
This is example configuration for Stratum server. | ||
Please rename it to config.py and fill correct values. | ||
This is already setup with sane values for solomining. | ||
You NEED to set the parameters in BASIC SETTINGS | ||
''' | ||
|
||
# ******************** BASIC SETTINGS *************** | ||
# These are the MUST BE SET parameters! | ||
|
||
CENTRAL_WALLET = 'set_valid_addresss_in_config!' # local coin address where money goes | ||
|
||
COINDAEMON_TRUSTED_HOST = 'localhost' | ||
COINDAEMON_TRUSTED_PORT = 8332 | ||
COINDAEMON_TRUSTED_USER = 'user' | ||
COINDAEMON_TRUSTED_PASSWORD = 'somepassword' | ||
|
||
# ******************** BASIC SETTINGS *************** | ||
# Backup Coin Daemon address's (consider having at least 1 backup) | ||
# You can have up to 99 | ||
|
||
#COINDAEMON_TRUSTED_HOST_1 = 'localhost' | ||
#COINDAEMON_TRUSTED_PORT_1 = 8332 | ||
#COINDAEMON_TRUSTED_USER_1 = 'user' | ||
#COINDAEMON_TRUSTED_PASSWORD_1 = 'somepassword' | ||
|
||
#COINDAEMON_TRUSTED_HOST_2 = 'localhost' | ||
#COINDAEMON_TRUSTED_PORT_2 = 8332 | ||
#COINDAEMON_TRUSTED_USER_2 = 'user' | ||
#COINDAEMON_TRUSTED_PASSWORD_2 = 'somepassword' | ||
|
||
# ******************** GENERAL SETTINGS *************** | ||
|
||
# Enable some verbose debug (logging requests and responses). | ||
DEBUG = False | ||
|
||
# Destination for application logs, files rotated once per day. | ||
LOGDIR = 'log/' | ||
|
||
# Main application log file. | ||
LOGFILE = None # eg. 'stratum.log' | ||
|
||
# Logging Rotation can be enabled with the following settings | ||
# It if not enabled here, you can set up logrotate to rotate the files. | ||
# For built in log rotation set LOG_ROTATION = True and configrue the variables | ||
LOG_ROTATION = True | ||
LOG_SIZE = 10485760 # Rotate every 10M | ||
LOG_RETENTION = 10 # Keep 10 Logs | ||
# How many threads use for synchronous methods (services). | ||
# 30 is enough for small installation, for real usage | ||
# it should be slightly more, say 100-300. | ||
THREAD_POOL_SIZE = 300 | ||
|
||
# Disable the example service | ||
ENABLE_EXAMPLE_SERVICE = False | ||
|
||
# ******************** TRANSPORTS ********************* | ||
|
||
# Hostname or external IP to expose | ||
HOSTNAME = 'localhost' | ||
|
||
# Port used for Socket transport. Use 'None' for disabling the transport. | ||
LISTEN_SOCKET_TRANSPORT = 3333 | ||
# Port used for HTTP Poll transport. Use 'None' for disabling the transport | ||
LISTEN_HTTP_TRANSPORT = None | ||
# Port used for HTTPS Poll transport | ||
LISTEN_HTTPS_TRANSPORT = None | ||
# Port used for WebSocket transport, 'None' for disabling WS | ||
LISTEN_WS_TRANSPORT = None | ||
# Port used for secure WebSocket, 'None' for disabling WSS | ||
LISTEN_WSS_TRANSPORT = None | ||
|
||
|
||
# Salt used when hashing passwords | ||
PASSWORD_SALT = 'some_crazy_string' | ||
|
||
# ******************** Database ********************* | ||
|
||
# MySQL | ||
DB_MYSQL_HOST = 'localhost' | ||
DB_MYSQL_DBNAME = 'pooldb' | ||
DB_MYSQL_USER = 'pooldb' | ||
DB_MYSQL_PASS = '**empty**' | ||
|
||
# ******************** Adv. DB Settings ********************* | ||
# Don't change these unless you know what you are doing | ||
|
||
DB_LOADER_CHECKTIME = 15 # How often we check to see if we should run the loader | ||
DB_LOADER_REC_MIN = 10 # Min Records before the bulk loader fires | ||
DB_LOADER_REC_MAX = 50 # Max Records the bulk loader will commit at a time | ||
|
||
DB_LOADER_FORCE_TIME = 300 # How often the cache should be flushed into the DB regardless of size. | ||
|
||
DB_STATS_AVG_TIME = 300 # When using the DATABASE_EXTEND option, average speed over X sec | ||
# Note: this is also how often it updates | ||
DB_USERCACHE_TIME = 600 # How long the usercache is good for before we refresh | ||
|
||
# ******************** Pool Settings ********************* | ||
|
||
# User Auth Options | ||
USERS_AUTOADD = False # Automatically add users to db when they connect. | ||
# This basically disables User Auth for the pool. | ||
USERS_CHECK_PASSWORD = False # Check the workers password? (Many pools don't) | ||
|
||
# Transaction Settings | ||
COINBASE_EXTRAS = '/stratumPool/' # Extra Descriptive String to incorporate in solved blocks | ||
ALLOW_NONLOCAL_WALLET = False # Allow valid, but NON-Local wallet's | ||
|
||
# Coin Daemon communication polling settings (In Seconds) | ||
PREVHASH_REFRESH_INTERVAL = 5 # How often to check for new Blocks | ||
# If using the blocknotify script (recommended) set = to MERKLE_REFRESH_INTERVAL | ||
# (No reason to poll if we're getting pushed notifications) | ||
MERKLE_REFRESH_INTERVAL = 60 # How often check memorypool | ||
# This effectively resets the template and incorporates new transactions. | ||
# This should be "slow" | ||
|
||
INSTANCE_ID = 31 # Used for extranonce and needs to be 0-31 | ||
|
||
# ******************** Pool Difficulty Settings ********************* | ||
# Again, Don't change unless you know what this is for. | ||
|
||
# Pool Target (Base Difficulty) | ||
# In order to match the Pool Target with a frontend like MPOS the following formula is used: (stratum diff) ~= 2^((target bits in pushpool) - 16) | ||
# E.G. a Pool Target of 16 would = a MPOS and PushPool Target bit's of 20 | ||
POOL_TARGET = 16 # Pool-wide difficulty target int >= 1 | ||
|
||
# Variable Difficulty Enable | ||
VARIABLE_DIFF = True # Master variable difficulty enable | ||
|
||
# Variable diff tuning variables | ||
#VARDIFF will start at the POOL_TARGET. It can go as low as the VDIFF_MIN and as high as min(VDIFF_MAX or the coin daemon's difficulty) | ||
USE_COINDAEMON_DIFF = False # Set the maximum difficulty to the coin daemon's difficulty. | ||
DIFF_UPDATE_FREQUENCY = 86400 # Update the COINDAEMON difficulty once a day for the VARDIFF maximum | ||
VDIFF_MIN_TARGET = 15 # Minimum Target difficulty | ||
VDIFF_MAX_TARGET = 1000 # Maximum Target difficulty | ||
VDIFF_TARGET_TIME = 30 # Target time per share (i.e. try to get 1 share per this many seconds) | ||
VDIFF_RETARGET_TIME = 120 # Check to see if we should retarget this often | ||
VDIFF_VARIANCE_PERCENT = 20 # Allow average time to very this % from target without retarget | ||
#### Advanced Option ##### | ||
# For backwards compatibility, we send the scrypt hash to the solutions column in the shares table | ||
# For block confirmation, we have an option to send the block hash in | ||
# Please make sure your front end is compatible with the block hash in the solutions table. | ||
# For People using the MPOS frontend enabling this is recommended. It allows the frontend to compare the block hash to the coin daemon reducing the liklihood of missing share error's for blocks | ||
SOLUTION_BLOCK_HASH = False # If enabled, enter the block hash. If false enter the scrypt/sha hash into the shares table | ||
|
||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
# Run me with "twistd -ny launcher.tac -l -" | ||
|
||
# Add conf directory to python path. | ||
# Configuration file is standard python module. | ||
import os, sys | ||
sys.path = [os.path.join(os.getcwd(), 'conf'),os.path.join(os.getcwd(), 'externals', 'stratum-mining-proxy'),] + sys.path | ||
|
||
from twisted.internet import defer | ||
|
||
# Run listening when mining service is ready | ||
on_startup = defer.Deferred() | ||
|
||
import stratum | ||
import lib.settings as settings | ||
# Bootstrap Stratum framework | ||
application = stratum.setup(on_startup) | ||
|
||
# Load mining service into stratum framework | ||
import mining | ||
|
||
from mining.interfaces import Interfaces | ||
from mining.interfaces import WorkerManagerInterface, TimestamperInterface, \ | ||
ShareManagerInterface, ShareLimiterInterface | ||
|
||
if settings.VARIABLE_DIFF == True: | ||
from mining.basic_share_limiter import BasicShareLimiter | ||
Interfaces.set_share_limiter(BasicShareLimiter()) | ||
else: | ||
from mining.interfaces import ShareLimiterInterface | ||
Interfaces.set_share_limiter(ShareLimiterInterface()) | ||
|
||
Interfaces.set_share_manager(ShareManagerInterface()) | ||
Interfaces.set_worker_manager(WorkerManagerInterface()) | ||
Interfaces.set_timestamper(TimestamperInterface()) | ||
|
||
mining.setup(on_startup) |
Empty file.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,98 @@ | ||
''' | ||
Implements simple interface to a coin daemon's RPC. | ||
''' | ||
|
||
import simplejson as json | ||
import base64 | ||
from twisted.internet import defer | ||
from twisted.web import client | ||
import time | ||
|
||
import lib.logger | ||
log = lib.logger.get_logger('bitcoin_rpc') | ||
|
||
class BitcoinRPC(object): | ||
|
||
def __init__(self, host, port, username, password): | ||
self.bitcoin_url = 'http://%s:%d' % (host, port) | ||
self.credentials = base64.b64encode("%s:%s" % (username, password)) | ||
self.headers = { | ||
'Content-Type': 'text/json', | ||
'Authorization': 'Basic %s' % self.credentials, | ||
} | ||
client.HTTPClientFactory.noisy = False | ||
|
||
def _call_raw(self, data): | ||
client.Headers | ||
return client.getPage( | ||
url=self.bitcoin_url, | ||
method='POST', | ||
headers=self.headers, | ||
postdata=data, | ||
) | ||
|
||
def _call(self, method, params): | ||
return self._call_raw(json.dumps({ | ||
'jsonrpc': '2.0', | ||
'method': method, | ||
'params': params, | ||
'id': '1', | ||
})) | ||
|
||
@defer.inlineCallbacks | ||
def submitblock(self, block_hex, block_hash_hex): | ||
# Try submitblock if that fails, go to getblocktemplate | ||
try: | ||
resp = (yield self._call('submitblock', [block_hex,])) | ||
except Exception: | ||
try: | ||
resp = (yield self._call('getblocktemplate', [{'mode': 'submit', 'data': block_hex}])) | ||
except Exception as e: | ||
log.exception("Problem Submitting block %s" % str(e)) | ||
raise | ||
|
||
if json.loads(resp)['result'] == None: | ||
# make sure the block was created. | ||
defer.returnValue((yield self.blockexists(block_hash_hex))) | ||
else: | ||
defer.returnValue(False) | ||
|
||
@defer.inlineCallbacks | ||
def getinfo(self): | ||
resp = (yield self._call('getinfo', [])) | ||
defer.returnValue(json.loads(resp)['result']) | ||
|
||
@defer.inlineCallbacks | ||
def getblocktemplate(self): | ||
resp = (yield self._call('getblocktemplate', [{}])) | ||
defer.returnValue(json.loads(resp)['result']) | ||
|
||
@defer.inlineCallbacks | ||
def prevhash(self): | ||
resp = (yield self._call('getwork', [])) | ||
try: | ||
defer.returnValue(json.loads(resp)['result']['data'][8:72]) | ||
except Exception as e: | ||
log.exception("Cannot decode prevhash %s" % str(e)) | ||
raise | ||
|
||
@defer.inlineCallbacks | ||
def validateaddress(self, address): | ||
resp = (yield self._call('validateaddress', [address,])) | ||
defer.returnValue(json.loads(resp)['result']) | ||
|
||
@defer.inlineCallbacks | ||
def getdifficulty(self): | ||
resp = (yield self._call('getdifficulty', [])) | ||
defer.returnValue(json.loads(resp)['result']) | ||
|
||
@defer.inlineCallbacks | ||
def blockexists(self, block_hash_hex): | ||
resp = (yield self._call('getblock', [block_hash_hex,])) | ||
if "hash" in json.loads(resp)['result'] and json.loads(resp)['result']['hash'] == block_hash_hex: | ||
log.debug("Block Confirmed: %s" % block_hash_hex) | ||
defer.returnValue(True) | ||
else: | ||
log.info("Cannot find block for %s" % block_hash_hex) | ||
defer.returnValue(False) | ||
|
Oops, something went wrong.