Fixing Master (1)
This commit is contained in:
parent
905dcf68fd
commit
bf8a01a616
16
README.md
16
README.md
@ -1,7 +1,7 @@
|
||||
#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.
|
||||
This is a implementation of stratum-mining for scrypt based coins. It is compatible with *MPOS* 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.
|
||||
|
||||
@ -22,6 +22,7 @@ The goal is to make a reliable stratum mining server for scrypt based coins. Ove
|
||||
* Adjustable database commit parameters
|
||||
* Bypass password check for workers
|
||||
* Proof Of Work and Proof of Stake Coin Support
|
||||
* Transaction Messaging Support
|
||||
|
||||
#Donations
|
||||
* BTC: 18uj5SzQaYVAPX96JZt1VE4K43m5VeYekP
|
||||
@ -30,9 +31,9 @@ The goal is to make a reliable stratum mining server for scrypt based coins. Ove
|
||||
* LTC: LVDbDHPUF13YZQeJE6AtxDwiF2RyNBsmXh
|
||||
* WDC: WeVFgZQsKSKXGak7NJPp9SrcUexghzTPGJ
|
||||
* Doge: DLtBRYtNCzfiZfcpUeEr8KPvy5k1aR7jca
|
||||
|
||||
#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
|
||||
@ -60,16 +61,19 @@ Other coins have been known to work with this implementation. I have tested with
|
||||
The installation of this *stratum-mining* can be found in the Repo Wiki.
|
||||
|
||||
#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
|
||||
|
||||
I am available in the #MPOS, #crypto-expert, #digitalcoin, and #worldcoin channels on freenode.
|
||||
Although i am willing to provide support through IRC please file issues on the repo.
|
||||
issues as a direct result of stratum will be helped with as much as possible
|
||||
However issues related to a coin daemon's setup and other non stratum issues,
|
||||
Please research and attempt to debug first.
|
||||
|
||||
#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
|
||||
|
||||
* Multi Algo, Vardiff, DB and MPOS support done by Ahmed_Bodi and Obigal
|
||||
|
||||
#License
|
||||
This software is provides AS-IS without any warranties of any kind. Please use at your own risk.
|
||||
|
||||
@ -26,7 +26,7 @@ COINDAEMON_TRUSTED_PASSWORD = 'somepassword'
|
||||
# For SHA256 PoS Coins which support TX Messages please enter yes in the TX selection
|
||||
COINDAEMON_ALGO = 'scrypt'
|
||||
COINDAEMON_Reward = 'POW'
|
||||
COINDAEMON_SHA256_TX = 'no'
|
||||
COINDAEMON_TX = 'no'
|
||||
# ******************** BASIC SETTINGS ***************
|
||||
# Backup Coin Daemon address's (consider having at least 1 backup)
|
||||
# You can have up to 99
|
||||
@ -42,6 +42,8 @@ COINDAEMON_SHA256_TX = 'no'
|
||||
#COINDAEMON_TRUSTED_PASSWORD_2 = 'somepassword'
|
||||
|
||||
# ******************** GENERAL SETTINGS ***************
|
||||
# Set process name of twistd, much more comfortable if you run multiple processes on one machine
|
||||
STRATUM_MINING_PROCESS_NAME= 'twistd-stratum-mining'
|
||||
|
||||
# Enable some verbose debug (logging requests and responses).
|
||||
DEBUG = False
|
||||
@ -51,7 +53,7 @@ LOGDIR = 'log/'
|
||||
|
||||
# Main application log file.
|
||||
LOGFILE = None # eg. 'stratum.log'
|
||||
|
||||
LOGLEVEL = 'DEBUG'
|
||||
# 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
|
||||
@ -89,6 +91,7 @@ PASSWORD_SALT = 'some_crazy_string'
|
||||
# ******************** Database *********************
|
||||
|
||||
DATABASE_DRIVER = 'sqlite' # Options: none, sqlite, postgresql or mysql
|
||||
DATABASE_EXTEND = False
|
||||
|
||||
# SQLite
|
||||
DB_SQLITE_FILE = 'pooldb.sqlite'
|
||||
@ -103,7 +106,7 @@ DB_MYSQL_HOST = 'localhost'
|
||||
DB_MYSQL_DBNAME = 'pooldb'
|
||||
DB_MYSQL_USER = 'pooldb'
|
||||
DB_MYSQL_PASS = '**empty**'
|
||||
|
||||
DB_MYSQL_PORT = 3306
|
||||
|
||||
# ******************** Adv. DB Settings *********************
|
||||
# Don't change these unless you know what you are doing
|
||||
@ -151,7 +154,7 @@ 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 Liteconin's difficulty)
|
||||
USE_LITECOIN_DIFF = False # Set the maximum difficulty to the litecoin difficulty.
|
||||
USE_COINDAEMON_DIFF = False # Set the maximum difficulty to the litecoin difficulty.
|
||||
DIFF_UPDATE_FREQUENCY = 86400 # Update the litecoin difficulty once a day for the VARDIFF maximum
|
||||
VDIFF_MIN_TARGET = 16 # Minimum Target difficulty
|
||||
VDIFF_MAX_TARGET = 1024 # Maximum Target difficulty
|
||||
@ -185,7 +188,11 @@ ENABLE_WORKER_BANNING = True # enable/disable temporary worker banning
|
||||
WORKER_CACHE_TIME = 600 # How long the worker stats cache is good before we check and refresh
|
||||
WORKER_BAN_TIME = 300 # How long we temporarily ban worker
|
||||
INVALID_SHARES_PERCENT = 50 # Allow average invalid shares vary this % before we ban
|
||||
|
||||
|
||||
#Pass scrypt hash to submit block check.
|
||||
#Use if submit block is returning errors and marking submitted blocks invaild upstream, but the submitted blocks are being a accepted by the coin daemon into the block chain.
|
||||
BLOCK_CHECK_SCRYPT_HASH = False
|
||||
|
||||
# ******************** E-Mail Notification Settings *********************
|
||||
NOTIFY_EMAIL_TO = '' # Where to send Start/Found block notifications
|
||||
NOTIFY_EMAIL_TO_DEADMINER = '' # Where to send dead miner notifications
|
||||
|
||||
@ -6,6 +6,7 @@ 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
|
||||
from twisted.application.service import Application, IProcess
|
||||
|
||||
# Run listening when mining service is ready
|
||||
on_startup = defer.Deferred()
|
||||
@ -14,6 +15,7 @@ import stratum
|
||||
import lib.settings as settings
|
||||
# Bootstrap Stratum framework
|
||||
application = stratum.setup(on_startup)
|
||||
IProcess(application).processName = settings.STRATUM_MINING_PROCESS_NAME
|
||||
|
||||
# Load mining service into stratum framework
|
||||
import mining
|
||||
@ -35,6 +37,3 @@ Interfaces.set_timestamper(TimestamperInterface())
|
||||
|
||||
mining.setup(on_startup)
|
||||
|
||||
if settings.GW_ENABLE == True :
|
||||
from lib.getwork_proxy import GetworkProxy
|
||||
GetworkProxy(on_startup)
|
||||
|
||||
@ -14,6 +14,7 @@ log = lib.logger.get_logger('bitcoin_rpc')
|
||||
class BitcoinRPC(object):
|
||||
|
||||
def __init__(self, host, port, username, password):
|
||||
log.debug("Got to Bitcoin RPC")
|
||||
self.bitcoin_url = 'http://%s:%d' % (host, port)
|
||||
self.credentials = base64.b64encode("%s:%s" % (username, password))
|
||||
self.headers = {
|
||||
@ -40,11 +41,11 @@ class BitcoinRPC(object):
|
||||
}))
|
||||
|
||||
@defer.inlineCallbacks
|
||||
def submitblock(self, block_hex, block_hash_hex):
|
||||
def submitblock(self, block_hex, hash_hex):
|
||||
# Try submitblock if that fails, go to getblocktemplate
|
||||
try:
|
||||
log.info("Submitting Block with Submit Block ")
|
||||
log.info([block_hex,])
|
||||
log.debug("Submitting Block with Submit Block ")
|
||||
log.debug([block_hex,])
|
||||
resp = (yield self._call('submitblock', [block_hex,]))
|
||||
except Exception:
|
||||
try:
|
||||
@ -52,11 +53,12 @@ class BitcoinRPC(object):
|
||||
resp = (yield self._call('getblocktemplate', [{'mode': 'submit', 'data': block_hex}]))
|
||||
except Exception as e:
|
||||
log.exception("Both SubmitBlock and GetBlockTemplate failed. Problem Submitting block %s" % str(e))
|
||||
raise
|
||||
log.exception("Try Enabling TX Messages in config.py")
|
||||
raise
|
||||
|
||||
if json.loads(resp)['result'] == None:
|
||||
# make sure the block was created.
|
||||
defer.returnValue((yield self.blockexists(block_hash_hex)))
|
||||
defer.returnValue((yield self.blockexists(hash_hex)))
|
||||
else:
|
||||
defer.returnValue(False)
|
||||
|
||||
@ -90,12 +92,12 @@ class BitcoinRPC(object):
|
||||
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)
|
||||
def blockexists(self, hash_hex):
|
||||
resp = (yield self._call('getblock', [hash_hex,]))
|
||||
if "hash" in json.loads(resp)['result'] and json.loads(resp)['result']['hash'] == hash_hex:
|
||||
log.debug("Block Confirmed: %s" % hash_hex)
|
||||
defer.returnValue(True)
|
||||
else:
|
||||
log.info("Cannot find block for %s" % block_hash_hex)
|
||||
log.info("Cannot find block for %s" % hash_hex)
|
||||
defer.returnValue(False)
|
||||
|
||||
|
||||
@ -19,6 +19,7 @@ from lib.bitcoin_rpc import BitcoinRPC
|
||||
class BitcoinRPCManager(object):
|
||||
|
||||
def __init__(self):
|
||||
log.debug("Got to Bitcoin RPC Manager")
|
||||
self.conns = {}
|
||||
self.conns[0] = BitcoinRPC(settings.COINDAEMON_TRUSTED_HOST,
|
||||
settings.COINDAEMON_TRUSTED_PORT,
|
||||
@ -88,10 +89,10 @@ class BitcoinRPCManager(object):
|
||||
except:
|
||||
self.next_connection()
|
||||
|
||||
def submitblock(self, block_hex, block_hash_hex):
|
||||
def submitblock(self, block_hex, hash_hex):
|
||||
while True:
|
||||
try:
|
||||
return self.conns[self.curr_conn].submitblock(block_hex, block_hash_hex)
|
||||
return self.conns[self.curr_conn].submitblock(block_hex, hash_hex)
|
||||
except:
|
||||
self.next_connection()
|
||||
|
||||
|
||||
@ -6,6 +6,8 @@ import util
|
||||
import merkletree
|
||||
import halfnode
|
||||
from coinbasetx import CoinbaseTransaction
|
||||
import lib.logger
|
||||
log = lib.logger.get_logger('block_template')
|
||||
|
||||
# Remove dependency to settings, coinbase extras should be
|
||||
# provided from coinbaser
|
||||
@ -19,7 +21,7 @@ class BlockTemplate(halfnode.CBlock):
|
||||
coinbase_transaction_class = CoinbaseTransaction
|
||||
|
||||
def __init__(self, timestamper, coinbaser, job_id):
|
||||
print("Hit Block_template.py")
|
||||
log.debug("Got To Block_template.py")
|
||||
super(BlockTemplate, self).__init__()
|
||||
|
||||
self.job_id = job_id
|
||||
|
||||
@ -17,7 +17,8 @@ class BlockUpdater(object):
|
||||
'''
|
||||
|
||||
def __init__(self, registry, bitcoin_rpc):
|
||||
self.bitcoin_rpc = bitcoin_rpc
|
||||
log.debug("Got To Block Updater")
|
||||
self.bitcoin_rpc = bitcoin_rpc
|
||||
self.registry = registry
|
||||
self.clock = None
|
||||
self.schedule()
|
||||
|
||||
@ -13,7 +13,7 @@ class SimpleCoinbaser(object):
|
||||
for all generated blocks.'''
|
||||
|
||||
def __init__(self, bitcoin_rpc, address):
|
||||
print("hit the coinbaser")
|
||||
log.debug("Got to the coinbaser")
|
||||
# Fire Callback when the coinbaser is ready
|
||||
self.on_load = defer.Deferred()
|
||||
|
||||
@ -31,32 +31,53 @@ class SimpleCoinbaser(object):
|
||||
d.addErrback(self._failure)
|
||||
|
||||
def _POW_address_check(self, result):
|
||||
if result['isvalid'] and result['ismine']:
|
||||
if result['isvalid'] and result['ismine']:
|
||||
self.is_valid = True
|
||||
log.info("Coinbase address '%s' is valid" % self.address)
|
||||
|
||||
if not self.on_load.called:
|
||||
self.on_load.callback(True)
|
||||
log.info("Coinbase address '%s' is valid" % self.address)
|
||||
if result['isvalid'] == True:
|
||||
log.debug("Is Valid = %s" % result['isvalid'])
|
||||
log.debug("Address = %s " % result['address'])
|
||||
log.debug("PubKey = %s " % result['pubkey'])
|
||||
log.debug("Is Compressed = %s " % result['iscompressed'])
|
||||
log.debug("Account = %s " % result['account'])
|
||||
self.address = result['address']
|
||||
if not self.on_load.called:
|
||||
self.on_load.callback(True)
|
||||
|
||||
elif result['isvalid'] and settings.ALLOW_NONLOCAL_WALLET == True :
|
||||
self.is_valid = True
|
||||
log.warning("!!! Coinbase address '%s' is valid BUT it is not local" % self.address)
|
||||
|
||||
if not self.on_load.called:
|
||||
self.on_load.callback(True)
|
||||
|
||||
else:
|
||||
self.is_valid = False
|
||||
log.error("Coinbase address '%s' is NOT valid!" % self.address)
|
||||
elif result['isvalid'] and settings.ALLOW_NONLOCAL_WALLET == True :
|
||||
self.is_valid = True
|
||||
log.warning("!!! Coinbase address '%s' is valid BUT it is not local" % self.address)
|
||||
if not self.on_load.called:
|
||||
self.on_load.callback(True)
|
||||
|
||||
else:
|
||||
self.is_valid = False
|
||||
log.error("Coinbase address '%s' is NOT valid!" % self.address)
|
||||
|
||||
def _POS_address_check(self, result):
|
||||
print(result)
|
||||
print(result['pubkey'])
|
||||
self.pubkey = result['pubkey']
|
||||
print("You're PUBKEY is : ", self.pubkey)
|
||||
# Fire callback when coinbaser is ready
|
||||
self.on_load.callback(True)
|
||||
|
||||
if result['isvalid'] and result['ismine']:
|
||||
self.is_valid = True
|
||||
log.info("Coinbase address '%s' is valid" % self.address)
|
||||
if result['isvalid'] == True:
|
||||
log.debug("Is Valid = %s" % result['isvalid'])
|
||||
log.debug("Address = %s " % result['address'])
|
||||
log.debug("PubKey = %s " % result['pubkey'])
|
||||
log.debug("Is Compressed = %s " % result['iscompressed'])
|
||||
log.debug("Account = %s " % result['account'])
|
||||
self.pubkey = result['pubkey']
|
||||
if not self.on_load.called:
|
||||
self.on_load.callback(True)
|
||||
|
||||
elif result['isvalid'] and settings.ALLOW_NONLOCAL_WALLET == True :
|
||||
self.is_valid = True
|
||||
log.warning("!!! Coinbase address '%s' is valid BUT it is not local" % self.address)
|
||||
self.pubkey = result['pubkey']
|
||||
if not self.on_load.called:
|
||||
self.on_load.callback(True)
|
||||
|
||||
else:
|
||||
self.is_valid = False
|
||||
|
||||
#def on_new_block(self):
|
||||
# pass
|
||||
|
||||
|
||||
@ -3,6 +3,9 @@ import halfnode
|
||||
import struct
|
||||
import util
|
||||
import settings
|
||||
import lib.logger
|
||||
log = lib.logger.get_logger('coinbasetx')
|
||||
|
||||
if settings.COINDAEMON_Reward == 'POW':
|
||||
class CoinbaseTransaction(halfnode.CTransaction):
|
||||
'''Construct special transaction used for coinbase tx.
|
||||
@ -15,7 +18,7 @@ if settings.COINDAEMON_Reward == 'POW':
|
||||
|
||||
def __init__(self, timestamper, coinbaser, value, flags, height, data):
|
||||
super(CoinbaseTransaction, self).__init__()
|
||||
|
||||
log.debug("Got to CoinBaseTX")
|
||||
#self.extranonce = 0
|
||||
|
||||
if len(self.extranonce_placeholder) != self.extranonce_size:
|
||||
@ -36,8 +39,8 @@ if settings.COINDAEMON_Reward == 'POW':
|
||||
tx_out.nValue = value
|
||||
tx_out.scriptPubKey = coinbaser.get_script_pubkey()
|
||||
|
||||
if settings.COINDAEMON_SHA256_TX == 'yes':
|
||||
self.strTxComment = ""
|
||||
if settings.COINDAEMON_TX == 'yes':
|
||||
self.strTxComment = "http://github.com/ahmedbodi/stratum-mining"
|
||||
self.vin.append(tx_in)
|
||||
self.vout.append(tx_out)
|
||||
|
||||
@ -62,7 +65,7 @@ elif settings.COINDAEMON_Reward == 'POS':
|
||||
|
||||
def __init__(self, timestamper, coinbaser, value, flags, height, data, ntime):
|
||||
super(CoinbaseTransaction, self).__init__()
|
||||
|
||||
log.debug("Got to CoinBaseTX")
|
||||
#self.extranonce = 0
|
||||
|
||||
if len(self.extranonce_placeholder) != self.extranonce_size:
|
||||
@ -85,7 +88,7 @@ elif settings.COINDAEMON_Reward == 'POS':
|
||||
|
||||
self.nTime = ntime
|
||||
if settings.COINDAEMON_SHA256_TX == 'yes':
|
||||
self.strTxComment = ""
|
||||
self.strTxComment = "http://github.com/ahmedbodi/stratum-mining"
|
||||
self.vin.append(tx_in)
|
||||
self.vout.append(tx_out)
|
||||
|
||||
@ -110,7 +113,7 @@ else:
|
||||
|
||||
def __init__(self, timestamper, coinbaser, value, flags, height, data, ntime):
|
||||
super(CoinbaseTransaction, self).__init__()
|
||||
|
||||
log.debug("Got to CoinBaseTX")
|
||||
#self.extranonce = 0
|
||||
|
||||
if len(self.extranonce_placeholder) != self.extranonce_size:
|
||||
|
||||
@ -1,5 +1,7 @@
|
||||
import struct
|
||||
|
||||
import lib.logger
|
||||
log = lib.logger.get_logger('extronance')
|
||||
|
||||
class ExtranonceCounter(object):
|
||||
'''Implementation of a counter producing
|
||||
unique extranonce across all pool instances.
|
||||
@ -7,7 +9,8 @@ class ExtranonceCounter(object):
|
||||
but it can be changed at any time without breaking anything.'''
|
||||
|
||||
def __init__(self, instance_id):
|
||||
if instance_id < 0 or instance_id > 31:
|
||||
log.debug("Got to Extronance Counter")
|
||||
if instance_id < 0 or instance_id > 31:
|
||||
raise Exception("Current ExtranonceCounter implementation needs an instance_id in <0, 31>.")
|
||||
|
||||
# Last 5 most-significant bits represents instance_id
|
||||
@ -22,4 +25,4 @@ class ExtranonceCounter(object):
|
||||
def get_new_bin(self):
|
||||
self.counter += 1
|
||||
return struct.pack('>L', self.counter)
|
||||
|
||||
|
||||
|
||||
@ -16,32 +16,34 @@ from twisted.internet.protocol import Protocol
|
||||
from util import *
|
||||
|
||||
import settings
|
||||
import lib.logger
|
||||
log = lib.logger.get_logger('halfnode')
|
||||
log.debug("Got to Halfnode")
|
||||
|
||||
if settings.COINDAEMON_ALGO == 'scrypt':
|
||||
print("########################################### Loading LTC Scrypt Module #########################################################")
|
||||
log.debug("########################################### Loading LTC Scrypt Module #########################################################")
|
||||
import ltc_scrypt
|
||||
elif settings.COINDAEMON_ALGO == 'quark':
|
||||
print("########################################### Loading Quark Module #########################################################")
|
||||
log.debug("########################################### Loading Quark Module #########################################################")
|
||||
import quark_hash
|
||||
else:
|
||||
print("########################################### NOT Loading LTC Scrypt Module ######################################################")
|
||||
log.debug("########################################### NOT Loading LTC Scrypt Module ######################################################")
|
||||
pass
|
||||
|
||||
if settings.COINDAEMON_Reward == 'POS':
|
||||
print("########################################### Loading POS Support #########################################################")
|
||||
log.debug("########################################### Loading POS Support #########################################################")
|
||||
pass
|
||||
else:
|
||||
print("########################################### NOT Loading POS Support ######################################################")
|
||||
log.debug("########################################### NOT Loading POS Support ######################################################")
|
||||
pass
|
||||
|
||||
if settings.COINDAEMON_SHA256_TX == 'yes':
|
||||
print("########################################### Loading SHA256 Transaction Message Support #########################################################")
|
||||
if settings.COINDAEMON_TX == 'yes':
|
||||
log.debug("########################################### Loading SHA256 Transaction Message Support #########################################################")
|
||||
pass
|
||||
else:
|
||||
print("########################################### NOT Loading SHA256 Transaction Message Support ######################################################")
|
||||
log.debug("########################################### NOT Loading SHA256 Transaction Message Support ######################################################")
|
||||
pass
|
||||
|
||||
import lib.logger
|
||||
log = lib.logger.get_logger('halfnode')
|
||||
|
||||
MY_VERSION = 31402
|
||||
MY_SUBVERSION = ".4"
|
||||
@ -157,7 +159,7 @@ class CTransaction(object):
|
||||
def __init__(self):
|
||||
if settings.COINDAEMON_Reward == 'POW':
|
||||
self.nVersion = 1
|
||||
if settings.COINDAEMON_SHA256_TX == 'yes':
|
||||
if settings.COINDAEMON_TX == 'yes':
|
||||
self.nVersion = 2
|
||||
self.vin = []
|
||||
self.vout = []
|
||||
@ -165,14 +167,14 @@ class CTransaction(object):
|
||||
self.sha256 = None
|
||||
elif settings.COINDAEMON_Reward == 'POS':
|
||||
self.nVersion = 1
|
||||
if settings.COINDAEMON_SHA256_TX == 'yes':
|
||||
if settings.COINDAEMON_TX == 'yes':
|
||||
self.nVersion = 2
|
||||
self.nTime = 0
|
||||
self.vin = []
|
||||
self.vout = []
|
||||
self.nLockTime = 0
|
||||
self.sha256 = None
|
||||
if settings.COINDAEMON_SHA256_TX == 'yes':
|
||||
if settings.COINDAEMON_TX == 'yes':
|
||||
self.strTxComment = ""
|
||||
|
||||
def deserialize(self, f):
|
||||
@ -189,7 +191,7 @@ class CTransaction(object):
|
||||
self.vout = deser_vector(f, CTxOut)
|
||||
self.nLockTime = struct.unpack("<I", f.read(4))[0]
|
||||
self.sha256 = None
|
||||
if settings.COINDAEMON_SHA256_TX == 'yes':
|
||||
if settings.COINDAEMON_TX == 'yes':
|
||||
self.strTxComment = deser_string(f)
|
||||
|
||||
def serialize(self):
|
||||
@ -206,7 +208,7 @@ class CTransaction(object):
|
||||
r += ser_vector(self.vin)
|
||||
r += ser_vector(self.vout)
|
||||
r += struct.pack("<I", self.nLockTime)
|
||||
if settings.COINDAEMON_SHA256_TX == 'yes':
|
||||
if settings.COINDAEMON_TX == 'yes':
|
||||
r += ser_string(self.strTxComment)
|
||||
return r
|
||||
|
||||
|
||||
@ -15,7 +15,7 @@ from lib.exceptions import SubmitException
|
||||
|
||||
import lib.logger
|
||||
log = lib.logger.get_logger('template_registry')
|
||||
|
||||
log.debug("Got to Template Registry")
|
||||
from mining.interfaces import Interfaces
|
||||
from extranonce_counter import ExtranonceCounter
|
||||
import lib.settings as settings
|
||||
@ -63,11 +63,13 @@ class TemplateRegistry(object):
|
||||
def get_new_extranonce1(self):
|
||||
'''Generates unique extranonce1 (e.g. for newly
|
||||
subscribed connection.'''
|
||||
log.debug("Getting New Extronance")
|
||||
return self.extranonce_counter.get_new_bin()
|
||||
|
||||
def get_last_broadcast_args(self):
|
||||
'''Returns arguments for mining.notify
|
||||
from last known template.'''
|
||||
log.debug("Getting Laat Template")
|
||||
return self.last_block.broadcast_args
|
||||
|
||||
def add_template(self, block,block_height):
|
||||
@ -135,7 +137,6 @@ class TemplateRegistry(object):
|
||||
start = Interfaces.timestamper.time()
|
||||
|
||||
template = self.block_template_class(Interfaces.timestamper, self.coinbaser, JobIdGenerator.get_new_id())
|
||||
print("hit template registry")
|
||||
log.info(template.fill_from_rpc(data))
|
||||
self.add_template(template,data['height'])
|
||||
|
||||
@ -275,11 +276,16 @@ class TemplateRegistry(object):
|
||||
|
||||
if not job.is_valid():
|
||||
# Should not happen
|
||||
log.error("Final job validation failed!")
|
||||
log.exception("Final job validation failed!")
|
||||
|
||||
# 7. Submit block to the network
|
||||
serialized = binascii.hexlify(job.serialize())
|
||||
on_submit = self.bitcoin_rpc.submitblock(serialized, block_hash_hex)
|
||||
on_submit = self.bitcoin_rpc.
|
||||
if settings.BLOCK_CHECK_SCRYPT_HASH:
|
||||
on_submit = self.bitcoin_rpc.submitblock(serialized, scrypt_hash_hex)
|
||||
else:
|
||||
on_submit = self.bitcoin_rpc.submitblock(serialized, block_hash_hex)
|
||||
|
||||
if on_submit:
|
||||
self.update_block()
|
||||
|
||||
|
||||
@ -221,5 +221,5 @@ if settings.COINDAEMON_Reward == 'POW':
|
||||
else:
|
||||
def script_to_pubkey(key):
|
||||
if len(key) == 66: key = binascii.unhexlify(key)
|
||||
if len(key) != 33: raise Exception('invalid pubkey passed to script_to_pubkey')
|
||||
if len(key) != 33: raise Exception('Invalid Address')
|
||||
return b'\x21' + key + b'\xac'
|
||||
|
||||
@ -31,7 +31,7 @@ class DBInterface():
|
||||
signal.signal(signal.SIGINT, self.signal_handler)
|
||||
|
||||
def signal_handler(self, signal, frame):
|
||||
print "SIGINT Detected, shutting down"
|
||||
log.warning("SIGINT Detected, shutting down")
|
||||
self.do_import(self.dbi, True)
|
||||
reactor.stop()
|
||||
|
||||
|
||||
@ -12,7 +12,7 @@ class DB_Mysql():
|
||||
|
||||
required_settings = ['PASSWORD_SALT', 'DB_MYSQL_HOST',
|
||||
'DB_MYSQL_USER', 'DB_MYSQL_PASS',
|
||||
'DB_MYSQL_DBNAME']
|
||||
'DB_MYSQL_DBNAME', 'DB_MYSQL_PORT']
|
||||
|
||||
for setting_name in required_settings:
|
||||
if not hasattr(settings, setting_name):
|
||||
@ -26,7 +26,8 @@ class DB_Mysql():
|
||||
getattr(settings, 'DB_MYSQL_HOST'),
|
||||
getattr(settings, 'DB_MYSQL_USER'),
|
||||
getattr(settings, 'DB_MYSQL_PASS'),
|
||||
getattr(settings, 'DB_MYSQL_DBNAME')
|
||||
getattr(settings, 'DB_MYSQL_DBNAME'),
|
||||
getattr(settings, 'DB_MYSQL_PORT')
|
||||
)
|
||||
self.dbc = self.dbh.cursor()
|
||||
self.dbh.autocommit(True)
|
||||
@ -69,8 +70,10 @@ class DB_Mysql():
|
||||
checkin_times = {}
|
||||
total_shares = 0
|
||||
best_diff = 0
|
||||
lof.debug(data)
|
||||
|
||||
for k, v in enumerate(data):
|
||||
log.debug(v)
|
||||
# for database compatibility we are converting our_worker to Y/N format
|
||||
if v[5]:
|
||||
v[5] = 'Y'
|
||||
@ -81,19 +84,21 @@ class DB_Mysql():
|
||||
"""
|
||||
INSERT INTO `shares`
|
||||
(time, rem_host, username, our_result,
|
||||
upstream_result, reason, solution)
|
||||
upstream_result, reason, solution, difficulty)
|
||||
VALUES
|
||||
(FROM_UNIXTIME(%(time)s), %(host)s,
|
||||
%(uname)s,
|
||||
%(lres)s, 'N', %(reason)s, %(solution)s)
|
||||
%(lres)s, %(result)s, %(reason)s, %(solution)s, %(difficulty)s )
|
||||
""",
|
||||
{
|
||||
"time": v[4],
|
||||
"host": v[6],
|
||||
"uname": v[0],
|
||||
"lres": v[5],
|
||||
"reason": v[9],
|
||||
"solution": v[2]
|
||||
"time": data[4],
|
||||
"host": data[6],
|
||||
"uname": data[0],
|
||||
"lres": data[5],
|
||||
"result": data[5],
|
||||
"reason": data[9],
|
||||
"solution": data[2],
|
||||
"difficulty": data[3]
|
||||
}
|
||||
)
|
||||
|
||||
@ -343,5 +348,5 @@ class DB_Mysql():
|
||||
data = self.dbc.fetchone()
|
||||
|
||||
if data[0] <= 0:
|
||||
raise Exception("There is no shares table. Have you imported the schema?")
|
||||
raise Exception("There is no shares table. Have you imported the MPOS schema?")
|
||||
|
||||
|
||||
@ -45,13 +45,14 @@ class DB_Mysql_Vardiff(DB_Mysql.DB_Mysql):
|
||||
VALUES
|
||||
(FROM_UNIXTIME(%(time)s), %(host)s,
|
||||
%(uname)s,
|
||||
%(lres)s, 'N', %(reason)s, %(solution)s, %(difficulty)s)
|
||||
%(lres)s, %(result)s, %(reason)s, %(solution)s, %(difficulty)s)
|
||||
""",
|
||||
{
|
||||
"time": v[4],
|
||||
"host": v[6],
|
||||
"uname": v[0],
|
||||
"lres": v[5],
|
||||
"result": data[5],
|
||||
"reason": v[9],
|
||||
"solution": v[2],
|
||||
"difficulty": v[3]
|
||||
|
||||
@ -42,36 +42,47 @@ def setup(on_startup):
|
||||
try:
|
||||
result = (yield bitcoin_rpc.getblocktemplate())
|
||||
if isinstance(result, dict):
|
||||
print(result)
|
||||
# litecoind implements version 1 of getblocktemplate
|
||||
if result['version'] >= 1:
|
||||
break
|
||||
result = (yield bitcoin_rpc.getinfo())
|
||||
if isinstance(result,dict):
|
||||
if 'stake' in result and settings.COINDAEMON_Reward == 'POS':
|
||||
log.info("CoinD looks to be a POS Coin, Config for POS looks correct")
|
||||
break
|
||||
elif 'stake' not in result and settings.COINDAEMON_Reward == 'POW':
|
||||
log.info("CoinD looks to be a POW Coin, Config looks to be correct")
|
||||
break
|
||||
else:
|
||||
log.error("Wrong Algo Selected, Switch to appropriate POS/POW in config.py!")
|
||||
reactor.stop()
|
||||
else:
|
||||
log.error("Block Version mismatch: %s" % result['version'])
|
||||
|
||||
|
||||
except ConnectionRefusedError, e:
|
||||
log.error("Connection refused while trying to connect to litecoin (are your COIND_* settings correct?)")
|
||||
log.error("Connection refused while trying to connect to the coind (are your COIND_* settings correct?)")
|
||||
reactor.stop()
|
||||
break
|
||||
|
||||
except Exception, e:
|
||||
print(e)
|
||||
if isinstance(e[2], str):
|
||||
print(e[2])
|
||||
if isinstance(json.loads(e[2])['error']['message'], str):
|
||||
error = json.loads(e[2])['error']['message']
|
||||
if error == "Method not found":
|
||||
log.error("Litecoind does not support getblocktemplate!!! (time to upgrade.)")
|
||||
reactor.stop()
|
||||
elif error == "Litecoind is downloading blocks...":
|
||||
log.error("Litecoind downloading blockchain... will check back in 30 sec")
|
||||
time.sleep(29)
|
||||
else:
|
||||
log.error("Litecoind Error: %s", error)
|
||||
try:
|
||||
if isinstance(json.loads(e[2])['error']['message'], str):
|
||||
error = json.loads(e[2])['error']['message']
|
||||
if error == "Method not found":
|
||||
log.error("CoinD does not support getblocktemplate!!! (time to upgrade.)")
|
||||
reactor.stop()
|
||||
elif "downloading blocks" in error:
|
||||
log.error("CoinD downloading blockchain... will check back in 30 sec")
|
||||
time.sleep(29)
|
||||
else:
|
||||
log.error("Coind Error: %s", error)
|
||||
except ValueError:
|
||||
log.error("Failed Connect(HTTP 500 or Invalid JSON), Check Username and Password!")
|
||||
reactor.stop()
|
||||
time.sleep(1) # If we didn't get a result or the connect failed
|
||||
|
||||
log.info('Connected to litecoind - Ready to GO!')
|
||||
log.info('Connected to the coind - Begining to load Address and Module Checks!')
|
||||
|
||||
# Start the coinbaser
|
||||
coinbaser = SimpleCoinbaser(bitcoin_rpc, getattr(settings, 'CENTRAL_WALLET'))
|
||||
|
||||
@ -134,7 +134,7 @@ class BasicShareLimiter(object):
|
||||
if settings.VDIFF_X2_TYPE:
|
||||
ddiff = 2
|
||||
# Don't go above LITECOIN or VDIFF_MAX_TARGET
|
||||
if settings.USE_LITECOIN_DIFF:
|
||||
if settings.USE_COINDAEMON_DIFF:
|
||||
self.update_litecoin_difficulty()
|
||||
diff_max = min([settings.VDIFF_MAX_TARGET, self.litecoin_diff])
|
||||
else:
|
||||
@ -146,7 +146,7 @@ class BasicShareLimiter(object):
|
||||
if ddiff < 1:
|
||||
ddiff = 1
|
||||
# Don't go above LITECOIN or VDIFF_MAX_TARGET
|
||||
if settings.USE_LITECOIN_DIFF:
|
||||
if settings.USE_COINDAEMON_DIFF:
|
||||
self.update_litecoin_difficulty()
|
||||
diff_max = min([settings.VDIFF_MAX_TARGET, self.litecoin_diff])
|
||||
else:
|
||||
|
||||
@ -30,10 +30,10 @@ class WorkerManagerInterface(object):
|
||||
def get_user_difficulty(self, worker_name):
|
||||
wd = dbi.get_user(worker_name)
|
||||
if len(wd) > 6:
|
||||
#dbi.update_worker_diff(worker_name, wd[6])
|
||||
return (True, wd[6])
|
||||
else:
|
||||
return (False, settings.POOL_TARGET)
|
||||
if wd[6] != 0:
|
||||
return (True, wd[6])
|
||||
#dbi.update_worker_diff(worker_name, wd[6])
|
||||
return (False, settings.POOL_TARGET)
|
||||
|
||||
def register_work(self, worker_name, job_id, difficulty):
|
||||
now = Interfaces.timestamper.time()
|
||||
@ -105,7 +105,13 @@ class Interfaces(object):
|
||||
share_limiter = None
|
||||
timestamper = None
|
||||
template_registry = None
|
||||
|
||||
lib.settings = None
|
||||
|
||||
@classmethod
|
||||
def set_settings(cls, settings):
|
||||
lib.settings.setup()
|
||||
cls.settings = lib.settings
|
||||
|
||||
@classmethod
|
||||
def set_worker_manager(cls, manager):
|
||||
cls.worker_manager = manager
|
||||
|
||||
@ -7,7 +7,7 @@ from stratum.pubsub import Pubsub
|
||||
from interfaces import Interfaces
|
||||
from subscription import MiningSubscription
|
||||
from lib.exceptions import SubmitException
|
||||
|
||||
import json
|
||||
import lib.logger
|
||||
log = lib.logger.get_logger('mining')
|
||||
|
||||
@ -21,7 +21,37 @@ class MiningService(GenericService):
|
||||
service_type = 'mining'
|
||||
service_vendor = 'stratum'
|
||||
is_default = True
|
||||
|
||||
event = 'mining.notify'
|
||||
|
||||
@admin
|
||||
def get_server_stats(self):
|
||||
serialized = ''
|
||||
for subscription in Pubsub.iterate_subscribers(self.event):
|
||||
try:
|
||||
if subscription != None:
|
||||
session = subscription.connection_ref().get_session()
|
||||
session.setdefault('authorized', {})
|
||||
if session['authorized'].keys():
|
||||
worker_name = session['authorized'].keys()[0]
|
||||
difficulty = session['difficulty']
|
||||
ip = subscription.connection_ref()._get_ip()
|
||||
serialized += json.dumps({'worker_name': worker_name, 'ip': ip, 'difficulty': difficulty})
|
||||
else:
|
||||
pass
|
||||
except Exception as e:
|
||||
log.exception("Error getting subscriptions %s" % str(e))
|
||||
pass
|
||||
|
||||
log.debug("Server stats request: %s" % serialized)
|
||||
return '%s' % serialized
|
||||
|
||||
@admin
|
||||
def refresh_config(self):
|
||||
settings.setup()
|
||||
log.info("Updated Config")
|
||||
return True
|
||||
|
||||
|
||||
@admin
|
||||
def update_block(self):
|
||||
'''Connect this RPC call to 'litecoind -blocknotify' for
|
||||
|
||||
Loading…
Reference in New Issue
Block a user