Fixing Master (1)

This commit is contained in:
Ahmed Bodiwala 2014-01-05 20:55:21 +00:00
parent 905dcf68fd
commit bf8a01a616
20 changed files with 222 additions and 118 deletions

View File

@ -1,7 +1,7 @@
#Description #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. 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. 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 * Adjustable database commit parameters
* Bypass password check for workers * Bypass password check for workers
* Proof Of Work and Proof of Stake Coin Support * Proof Of Work and Proof of Stake Coin Support
* Transaction Messaging Support
#Donations #Donations
* BTC: 18uj5SzQaYVAPX96JZt1VE4K43m5VeYekP * BTC: 18uj5SzQaYVAPX96JZt1VE4K43m5VeYekP
@ -30,9 +31,9 @@ The goal is to make a reliable stratum mining server for scrypt based coins. Ove
* LTC: LVDbDHPUF13YZQeJE6AtxDwiF2RyNBsmXh * LTC: LVDbDHPUF13YZQeJE6AtxDwiF2RyNBsmXh
* WDC: WeVFgZQsKSKXGak7NJPp9SrcUexghzTPGJ * WDC: WeVFgZQsKSKXGak7NJPp9SrcUexghzTPGJ
* Doge: DLtBRYtNCzfiZfcpUeEr8KPvy5k1aR7jca * Doge: DLtBRYtNCzfiZfcpUeEr8KPvy5k1aR7jca
#Requirements #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. *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 2.7+
* python-twisted * python-twisted
* stratum * 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. The installation of this *stratum-mining* can be found in the Repo Wiki.
#Contact #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 #Credits
* Original version by Slush0 (original stratum code) * Original version by Slush0 (original stratum code)
* More Features added by GeneralFault, Wadee Womersley and Moopless * More Features added by GeneralFault, Wadee Womersley and Moopless
* Scrypt conversion from work done by viperaus * Scrypt conversion from work done by viperaus
* PoS conversion done by TheSeven * 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 #License
This software is provides AS-IS without any warranties of any kind. Please use at your own risk. This software is provides AS-IS without any warranties of any kind. Please use at your own risk.

View File

@ -26,7 +26,7 @@ COINDAEMON_TRUSTED_PASSWORD = 'somepassword'
# For SHA256 PoS Coins which support TX Messages please enter yes in the TX selection # For SHA256 PoS Coins which support TX Messages please enter yes in the TX selection
COINDAEMON_ALGO = 'scrypt' COINDAEMON_ALGO = 'scrypt'
COINDAEMON_Reward = 'POW' COINDAEMON_Reward = 'POW'
COINDAEMON_SHA256_TX = 'no' COINDAEMON_TX = 'no'
# ******************** BASIC SETTINGS *************** # ******************** BASIC SETTINGS ***************
# Backup Coin Daemon address's (consider having at least 1 backup) # Backup Coin Daemon address's (consider having at least 1 backup)
# You can have up to 99 # You can have up to 99
@ -42,6 +42,8 @@ COINDAEMON_SHA256_TX = 'no'
#COINDAEMON_TRUSTED_PASSWORD_2 = 'somepassword' #COINDAEMON_TRUSTED_PASSWORD_2 = 'somepassword'
# ******************** GENERAL SETTINGS *************** # ******************** 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). # Enable some verbose debug (logging requests and responses).
DEBUG = False DEBUG = False
@ -51,7 +53,7 @@ LOGDIR = 'log/'
# Main application log file. # Main application log file.
LOGFILE = None # eg. 'stratum.log' LOGFILE = None # eg. 'stratum.log'
LOGLEVEL = 'DEBUG'
# Logging Rotation can be enabled with the following settings # Logging Rotation can be enabled with the following settings
# It if not enabled here, you can set up logrotate to rotate the files. # 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 # For built in log rotation set LOG_ROTATION = True and configrue the variables
@ -89,6 +91,7 @@ PASSWORD_SALT = 'some_crazy_string'
# ******************** Database ********************* # ******************** Database *********************
DATABASE_DRIVER = 'sqlite' # Options: none, sqlite, postgresql or mysql DATABASE_DRIVER = 'sqlite' # Options: none, sqlite, postgresql or mysql
DATABASE_EXTEND = False
# SQLite # SQLite
DB_SQLITE_FILE = 'pooldb.sqlite' DB_SQLITE_FILE = 'pooldb.sqlite'
@ -103,7 +106,7 @@ DB_MYSQL_HOST = 'localhost'
DB_MYSQL_DBNAME = 'pooldb' DB_MYSQL_DBNAME = 'pooldb'
DB_MYSQL_USER = 'pooldb' DB_MYSQL_USER = 'pooldb'
DB_MYSQL_PASS = '**empty**' DB_MYSQL_PASS = '**empty**'
DB_MYSQL_PORT = 3306
# ******************** Adv. DB Settings ********************* # ******************** Adv. DB Settings *********************
# Don't change these unless you know what you are doing # 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 # 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) #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 DIFF_UPDATE_FREQUENCY = 86400 # Update the litecoin difficulty once a day for the VARDIFF maximum
VDIFF_MIN_TARGET = 16 # Minimum Target difficulty VDIFF_MIN_TARGET = 16 # Minimum Target difficulty
VDIFF_MAX_TARGET = 1024 # Maximum 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_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 WORKER_BAN_TIME = 300 # How long we temporarily ban worker
INVALID_SHARES_PERCENT = 50 # Allow average invalid shares vary this % before we ban 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 ********************* # ******************** E-Mail Notification Settings *********************
NOTIFY_EMAIL_TO = '' # Where to send Start/Found block notifications NOTIFY_EMAIL_TO = '' # Where to send Start/Found block notifications
NOTIFY_EMAIL_TO_DEADMINER = '' # Where to send dead miner notifications NOTIFY_EMAIL_TO_DEADMINER = '' # Where to send dead miner notifications

View File

@ -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 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.internet import defer
from twisted.application.service import Application, IProcess
# Run listening when mining service is ready # Run listening when mining service is ready
on_startup = defer.Deferred() on_startup = defer.Deferred()
@ -14,6 +15,7 @@ import stratum
import lib.settings as settings import lib.settings as settings
# Bootstrap Stratum framework # Bootstrap Stratum framework
application = stratum.setup(on_startup) application = stratum.setup(on_startup)
IProcess(application).processName = settings.STRATUM_MINING_PROCESS_NAME
# Load mining service into stratum framework # Load mining service into stratum framework
import mining import mining
@ -35,6 +37,3 @@ Interfaces.set_timestamper(TimestamperInterface())
mining.setup(on_startup) mining.setup(on_startup)
if settings.GW_ENABLE == True :
from lib.getwork_proxy import GetworkProxy
GetworkProxy(on_startup)

View File

@ -14,6 +14,7 @@ log = lib.logger.get_logger('bitcoin_rpc')
class BitcoinRPC(object): class BitcoinRPC(object):
def __init__(self, host, port, username, password): def __init__(self, host, port, username, password):
log.debug("Got to Bitcoin RPC")
self.bitcoin_url = 'http://%s:%d' % (host, port) self.bitcoin_url = 'http://%s:%d' % (host, port)
self.credentials = base64.b64encode("%s:%s" % (username, password)) self.credentials = base64.b64encode("%s:%s" % (username, password))
self.headers = { self.headers = {
@ -40,11 +41,11 @@ class BitcoinRPC(object):
})) }))
@defer.inlineCallbacks @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 submitblock if that fails, go to getblocktemplate
try: try:
log.info("Submitting Block with Submit Block ") log.debug("Submitting Block with Submit Block ")
log.info([block_hex,]) log.debug([block_hex,])
resp = (yield self._call('submitblock', [block_hex,])) resp = (yield self._call('submitblock', [block_hex,]))
except Exception: except Exception:
try: try:
@ -52,11 +53,12 @@ class BitcoinRPC(object):
resp = (yield self._call('getblocktemplate', [{'mode': 'submit', 'data': block_hex}])) resp = (yield self._call('getblocktemplate', [{'mode': 'submit', 'data': block_hex}]))
except Exception as e: except Exception as e:
log.exception("Both SubmitBlock and GetBlockTemplate failed. Problem Submitting block %s" % str(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: if json.loads(resp)['result'] == None:
# make sure the block was created. # make sure the block was created.
defer.returnValue((yield self.blockexists(block_hash_hex))) defer.returnValue((yield self.blockexists(hash_hex)))
else: else:
defer.returnValue(False) defer.returnValue(False)
@ -90,12 +92,12 @@ class BitcoinRPC(object):
defer.returnValue(json.loads(resp)['result']) defer.returnValue(json.loads(resp)['result'])
@defer.inlineCallbacks @defer.inlineCallbacks
def blockexists(self, block_hash_hex): def blockexists(self, hash_hex):
resp = (yield self._call('getblock', [block_hash_hex,])) resp = (yield self._call('getblock', [hash_hex,]))
if "hash" in json.loads(resp)['result'] and json.loads(resp)['result']['hash'] == block_hash_hex: if "hash" in json.loads(resp)['result'] and json.loads(resp)['result']['hash'] == hash_hex:
log.debug("Block Confirmed: %s" % block_hash_hex) log.debug("Block Confirmed: %s" % hash_hex)
defer.returnValue(True) defer.returnValue(True)
else: else:
log.info("Cannot find block for %s" % block_hash_hex) log.info("Cannot find block for %s" % hash_hex)
defer.returnValue(False) defer.returnValue(False)

View File

@ -19,6 +19,7 @@ from lib.bitcoin_rpc import BitcoinRPC
class BitcoinRPCManager(object): class BitcoinRPCManager(object):
def __init__(self): def __init__(self):
log.debug("Got to Bitcoin RPC Manager")
self.conns = {} self.conns = {}
self.conns[0] = BitcoinRPC(settings.COINDAEMON_TRUSTED_HOST, self.conns[0] = BitcoinRPC(settings.COINDAEMON_TRUSTED_HOST,
settings.COINDAEMON_TRUSTED_PORT, settings.COINDAEMON_TRUSTED_PORT,
@ -88,10 +89,10 @@ class BitcoinRPCManager(object):
except: except:
self.next_connection() self.next_connection()
def submitblock(self, block_hex, block_hash_hex): def submitblock(self, block_hex, hash_hex):
while True: while True:
try: 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: except:
self.next_connection() self.next_connection()

View File

@ -6,6 +6,8 @@ import util
import merkletree import merkletree
import halfnode import halfnode
from coinbasetx import CoinbaseTransaction from coinbasetx import CoinbaseTransaction
import lib.logger
log = lib.logger.get_logger('block_template')
# Remove dependency to settings, coinbase extras should be # Remove dependency to settings, coinbase extras should be
# provided from coinbaser # provided from coinbaser
@ -19,7 +21,7 @@ class BlockTemplate(halfnode.CBlock):
coinbase_transaction_class = CoinbaseTransaction coinbase_transaction_class = CoinbaseTransaction
def __init__(self, timestamper, coinbaser, job_id): def __init__(self, timestamper, coinbaser, job_id):
print("Hit Block_template.py") log.debug("Got To Block_template.py")
super(BlockTemplate, self).__init__() super(BlockTemplate, self).__init__()
self.job_id = job_id self.job_id = job_id

View File

@ -17,7 +17,8 @@ class BlockUpdater(object):
''' '''
def __init__(self, registry, bitcoin_rpc): 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.registry = registry
self.clock = None self.clock = None
self.schedule() self.schedule()

View File

@ -13,7 +13,7 @@ class SimpleCoinbaser(object):
for all generated blocks.''' for all generated blocks.'''
def __init__(self, bitcoin_rpc, address): def __init__(self, bitcoin_rpc, address):
print("hit the coinbaser") log.debug("Got to the coinbaser")
# Fire Callback when the coinbaser is ready # Fire Callback when the coinbaser is ready
self.on_load = defer.Deferred() self.on_load = defer.Deferred()
@ -31,32 +31,53 @@ class SimpleCoinbaser(object):
d.addErrback(self._failure) d.addErrback(self._failure)
def _POW_address_check(self, result): def _POW_address_check(self, result):
if result['isvalid'] and result['ismine']: if result['isvalid'] and result['ismine']:
self.is_valid = True self.is_valid = True
log.info("Coinbase address '%s' is valid" % self.address) log.info("Coinbase address '%s' is valid" % self.address)
if result['isvalid'] == True:
if not self.on_load.called: log.debug("Is Valid = %s" % result['isvalid'])
self.on_load.callback(True) 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 : elif result['isvalid'] and settings.ALLOW_NONLOCAL_WALLET == True :
self.is_valid = True self.is_valid = True
log.warning("!!! Coinbase address '%s' is valid BUT it is not local" % self.address) log.warning("!!! Coinbase address '%s' is valid BUT it is not local" % self.address)
if not self.on_load.called:
if not self.on_load.called: self.on_load.callback(True)
self.on_load.callback(True)
else:
else: self.is_valid = False
self.is_valid = False log.error("Coinbase address '%s' is NOT valid!" % self.address)
log.error("Coinbase address '%s' is NOT valid!" % self.address)
def _POS_address_check(self, result): def _POS_address_check(self, result):
print(result) if result['isvalid'] and result['ismine']:
print(result['pubkey']) self.is_valid = True
self.pubkey = result['pubkey'] log.info("Coinbase address '%s' is valid" % self.address)
print("You're PUBKEY is : ", self.pubkey) if result['isvalid'] == True:
# Fire callback when coinbaser is ready log.debug("Is Valid = %s" % result['isvalid'])
self.on_load.callback(True) 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): #def on_new_block(self):
# pass # pass

View File

@ -3,6 +3,9 @@ import halfnode
import struct import struct
import util import util
import settings import settings
import lib.logger
log = lib.logger.get_logger('coinbasetx')
if settings.COINDAEMON_Reward == 'POW': if settings.COINDAEMON_Reward == 'POW':
class CoinbaseTransaction(halfnode.CTransaction): class CoinbaseTransaction(halfnode.CTransaction):
'''Construct special transaction used for coinbase tx. '''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): def __init__(self, timestamper, coinbaser, value, flags, height, data):
super(CoinbaseTransaction, self).__init__() super(CoinbaseTransaction, self).__init__()
log.debug("Got to CoinBaseTX")
#self.extranonce = 0 #self.extranonce = 0
if len(self.extranonce_placeholder) != self.extranonce_size: if len(self.extranonce_placeholder) != self.extranonce_size:
@ -36,8 +39,8 @@ if settings.COINDAEMON_Reward == 'POW':
tx_out.nValue = value tx_out.nValue = value
tx_out.scriptPubKey = coinbaser.get_script_pubkey() tx_out.scriptPubKey = coinbaser.get_script_pubkey()
if settings.COINDAEMON_SHA256_TX == 'yes': if settings.COINDAEMON_TX == 'yes':
self.strTxComment = "" self.strTxComment = "http://github.com/ahmedbodi/stratum-mining"
self.vin.append(tx_in) self.vin.append(tx_in)
self.vout.append(tx_out) self.vout.append(tx_out)
@ -62,7 +65,7 @@ elif settings.COINDAEMON_Reward == 'POS':
def __init__(self, timestamper, coinbaser, value, flags, height, data, ntime): def __init__(self, timestamper, coinbaser, value, flags, height, data, ntime):
super(CoinbaseTransaction, self).__init__() super(CoinbaseTransaction, self).__init__()
log.debug("Got to CoinBaseTX")
#self.extranonce = 0 #self.extranonce = 0
if len(self.extranonce_placeholder) != self.extranonce_size: if len(self.extranonce_placeholder) != self.extranonce_size:
@ -85,7 +88,7 @@ elif settings.COINDAEMON_Reward == 'POS':
self.nTime = ntime self.nTime = ntime
if settings.COINDAEMON_SHA256_TX == 'yes': if settings.COINDAEMON_SHA256_TX == 'yes':
self.strTxComment = "" self.strTxComment = "http://github.com/ahmedbodi/stratum-mining"
self.vin.append(tx_in) self.vin.append(tx_in)
self.vout.append(tx_out) self.vout.append(tx_out)
@ -110,7 +113,7 @@ else:
def __init__(self, timestamper, coinbaser, value, flags, height, data, ntime): def __init__(self, timestamper, coinbaser, value, flags, height, data, ntime):
super(CoinbaseTransaction, self).__init__() super(CoinbaseTransaction, self).__init__()
log.debug("Got to CoinBaseTX")
#self.extranonce = 0 #self.extranonce = 0
if len(self.extranonce_placeholder) != self.extranonce_size: if len(self.extranonce_placeholder) != self.extranonce_size:

View File

@ -1,5 +1,7 @@
import struct import struct
import lib.logger
log = lib.logger.get_logger('extronance')
class ExtranonceCounter(object): class ExtranonceCounter(object):
'''Implementation of a counter producing '''Implementation of a counter producing
unique extranonce across all pool instances. unique extranonce across all pool instances.
@ -7,7 +9,8 @@ class ExtranonceCounter(object):
but it can be changed at any time without breaking anything.''' but it can be changed at any time without breaking anything.'''
def __init__(self, instance_id): 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>.") raise Exception("Current ExtranonceCounter implementation needs an instance_id in <0, 31>.")
# Last 5 most-significant bits represents instance_id # Last 5 most-significant bits represents instance_id
@ -22,4 +25,4 @@ class ExtranonceCounter(object):
def get_new_bin(self): def get_new_bin(self):
self.counter += 1 self.counter += 1
return struct.pack('>L', self.counter) return struct.pack('>L', self.counter)

View File

@ -16,32 +16,34 @@ from twisted.internet.protocol import Protocol
from util import * from util import *
import settings import settings
import lib.logger
log = lib.logger.get_logger('halfnode')
log.debug("Got to Halfnode")
if settings.COINDAEMON_ALGO == 'scrypt': if settings.COINDAEMON_ALGO == 'scrypt':
print("########################################### Loading LTC Scrypt Module #########################################################") log.debug("########################################### Loading LTC Scrypt Module #########################################################")
import ltc_scrypt import ltc_scrypt
elif settings.COINDAEMON_ALGO == 'quark': elif settings.COINDAEMON_ALGO == 'quark':
print("########################################### Loading Quark Module #########################################################") log.debug("########################################### Loading Quark Module #########################################################")
import quark_hash import quark_hash
else: else:
print("########################################### NOT Loading LTC Scrypt Module ######################################################") log.debug("########################################### NOT Loading LTC Scrypt Module ######################################################")
pass pass
if settings.COINDAEMON_Reward == 'POS': if settings.COINDAEMON_Reward == 'POS':
print("########################################### Loading POS Support #########################################################") log.debug("########################################### Loading POS Support #########################################################")
pass pass
else: else:
print("########################################### NOT Loading POS Support ######################################################") log.debug("########################################### NOT Loading POS Support ######################################################")
pass pass
if settings.COINDAEMON_SHA256_TX == 'yes': if settings.COINDAEMON_TX == 'yes':
print("########################################### Loading SHA256 Transaction Message Support #########################################################") log.debug("########################################### Loading SHA256 Transaction Message Support #########################################################")
pass pass
else: else:
print("########################################### NOT Loading SHA256 Transaction Message Support ######################################################") log.debug("########################################### NOT Loading SHA256 Transaction Message Support ######################################################")
pass pass
import lib.logger
log = lib.logger.get_logger('halfnode')
MY_VERSION = 31402 MY_VERSION = 31402
MY_SUBVERSION = ".4" MY_SUBVERSION = ".4"
@ -157,7 +159,7 @@ class CTransaction(object):
def __init__(self): def __init__(self):
if settings.COINDAEMON_Reward == 'POW': if settings.COINDAEMON_Reward == 'POW':
self.nVersion = 1 self.nVersion = 1
if settings.COINDAEMON_SHA256_TX == 'yes': if settings.COINDAEMON_TX == 'yes':
self.nVersion = 2 self.nVersion = 2
self.vin = [] self.vin = []
self.vout = [] self.vout = []
@ -165,14 +167,14 @@ class CTransaction(object):
self.sha256 = None self.sha256 = None
elif settings.COINDAEMON_Reward == 'POS': elif settings.COINDAEMON_Reward == 'POS':
self.nVersion = 1 self.nVersion = 1
if settings.COINDAEMON_SHA256_TX == 'yes': if settings.COINDAEMON_TX == 'yes':
self.nVersion = 2 self.nVersion = 2
self.nTime = 0 self.nTime = 0
self.vin = [] self.vin = []
self.vout = [] self.vout = []
self.nLockTime = 0 self.nLockTime = 0
self.sha256 = None self.sha256 = None
if settings.COINDAEMON_SHA256_TX == 'yes': if settings.COINDAEMON_TX == 'yes':
self.strTxComment = "" self.strTxComment = ""
def deserialize(self, f): def deserialize(self, f):
@ -189,7 +191,7 @@ class CTransaction(object):
self.vout = deser_vector(f, CTxOut) self.vout = deser_vector(f, CTxOut)
self.nLockTime = struct.unpack("<I", f.read(4))[0] self.nLockTime = struct.unpack("<I", f.read(4))[0]
self.sha256 = None self.sha256 = None
if settings.COINDAEMON_SHA256_TX == 'yes': if settings.COINDAEMON_TX == 'yes':
self.strTxComment = deser_string(f) self.strTxComment = deser_string(f)
def serialize(self): def serialize(self):
@ -206,7 +208,7 @@ class CTransaction(object):
r += ser_vector(self.vin) r += ser_vector(self.vin)
r += ser_vector(self.vout) r += ser_vector(self.vout)
r += struct.pack("<I", self.nLockTime) r += struct.pack("<I", self.nLockTime)
if settings.COINDAEMON_SHA256_TX == 'yes': if settings.COINDAEMON_TX == 'yes':
r += ser_string(self.strTxComment) r += ser_string(self.strTxComment)
return r return r

View File

@ -15,7 +15,7 @@ from lib.exceptions import SubmitException
import lib.logger import lib.logger
log = lib.logger.get_logger('template_registry') log = lib.logger.get_logger('template_registry')
log.debug("Got to Template Registry")
from mining.interfaces import Interfaces from mining.interfaces import Interfaces
from extranonce_counter import ExtranonceCounter from extranonce_counter import ExtranonceCounter
import lib.settings as settings import lib.settings as settings
@ -63,11 +63,13 @@ class TemplateRegistry(object):
def get_new_extranonce1(self): def get_new_extranonce1(self):
'''Generates unique extranonce1 (e.g. for newly '''Generates unique extranonce1 (e.g. for newly
subscribed connection.''' subscribed connection.'''
log.debug("Getting New Extronance")
return self.extranonce_counter.get_new_bin() return self.extranonce_counter.get_new_bin()
def get_last_broadcast_args(self): def get_last_broadcast_args(self):
'''Returns arguments for mining.notify '''Returns arguments for mining.notify
from last known template.''' from last known template.'''
log.debug("Getting Laat Template")
return self.last_block.broadcast_args return self.last_block.broadcast_args
def add_template(self, block,block_height): def add_template(self, block,block_height):
@ -135,7 +137,6 @@ class TemplateRegistry(object):
start = Interfaces.timestamper.time() start = Interfaces.timestamper.time()
template = self.block_template_class(Interfaces.timestamper, self.coinbaser, JobIdGenerator.get_new_id()) template = self.block_template_class(Interfaces.timestamper, self.coinbaser, JobIdGenerator.get_new_id())
print("hit template registry")
log.info(template.fill_from_rpc(data)) log.info(template.fill_from_rpc(data))
self.add_template(template,data['height']) self.add_template(template,data['height'])
@ -275,11 +276,16 @@ class TemplateRegistry(object):
if not job.is_valid(): if not job.is_valid():
# Should not happen # Should not happen
log.error("Final job validation failed!") log.exception("Final job validation failed!")
# 7. Submit block to the network # 7. Submit block to the network
serialized = binascii.hexlify(job.serialize()) 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: if on_submit:
self.update_block() self.update_block()

View File

@ -221,5 +221,5 @@ if settings.COINDAEMON_Reward == 'POW':
else: else:
def script_to_pubkey(key): def script_to_pubkey(key):
if len(key) == 66: key = binascii.unhexlify(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' return b'\x21' + key + b'\xac'

View File

@ -31,7 +31,7 @@ class DBInterface():
signal.signal(signal.SIGINT, self.signal_handler) signal.signal(signal.SIGINT, self.signal_handler)
def signal_handler(self, signal, frame): def signal_handler(self, signal, frame):
print "SIGINT Detected, shutting down" log.warning("SIGINT Detected, shutting down")
self.do_import(self.dbi, True) self.do_import(self.dbi, True)
reactor.stop() reactor.stop()

View File

@ -12,7 +12,7 @@ class DB_Mysql():
required_settings = ['PASSWORD_SALT', 'DB_MYSQL_HOST', required_settings = ['PASSWORD_SALT', 'DB_MYSQL_HOST',
'DB_MYSQL_USER', 'DB_MYSQL_PASS', 'DB_MYSQL_USER', 'DB_MYSQL_PASS',
'DB_MYSQL_DBNAME'] 'DB_MYSQL_DBNAME', 'DB_MYSQL_PORT']
for setting_name in required_settings: for setting_name in required_settings:
if not hasattr(settings, setting_name): if not hasattr(settings, setting_name):
@ -26,7 +26,8 @@ class DB_Mysql():
getattr(settings, 'DB_MYSQL_HOST'), getattr(settings, 'DB_MYSQL_HOST'),
getattr(settings, 'DB_MYSQL_USER'), getattr(settings, 'DB_MYSQL_USER'),
getattr(settings, 'DB_MYSQL_PASS'), 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.dbc = self.dbh.cursor()
self.dbh.autocommit(True) self.dbh.autocommit(True)
@ -69,8 +70,10 @@ class DB_Mysql():
checkin_times = {} checkin_times = {}
total_shares = 0 total_shares = 0
best_diff = 0 best_diff = 0
lof.debug(data)
for k, v in enumerate(data): for k, v in enumerate(data):
log.debug(v)
# for database compatibility we are converting our_worker to Y/N format # for database compatibility we are converting our_worker to Y/N format
if v[5]: if v[5]:
v[5] = 'Y' v[5] = 'Y'
@ -81,19 +84,21 @@ class DB_Mysql():
""" """
INSERT INTO `shares` INSERT INTO `shares`
(time, rem_host, username, our_result, (time, rem_host, username, our_result,
upstream_result, reason, solution) upstream_result, reason, solution, difficulty)
VALUES VALUES
(FROM_UNIXTIME(%(time)s), %(host)s, (FROM_UNIXTIME(%(time)s), %(host)s,
%(uname)s, %(uname)s,
%(lres)s, 'N', %(reason)s, %(solution)s) %(lres)s, %(result)s, %(reason)s, %(solution)s, %(difficulty)s )
""", """,
{ {
"time": v[4], "time": data[4],
"host": v[6], "host": data[6],
"uname": v[0], "uname": data[0],
"lres": v[5], "lres": data[5],
"reason": v[9], "result": data[5],
"solution": v[2] "reason": data[9],
"solution": data[2],
"difficulty": data[3]
} }
) )
@ -343,5 +348,5 @@ class DB_Mysql():
data = self.dbc.fetchone() data = self.dbc.fetchone()
if data[0] <= 0: 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?")

View File

@ -45,13 +45,14 @@ class DB_Mysql_Vardiff(DB_Mysql.DB_Mysql):
VALUES VALUES
(FROM_UNIXTIME(%(time)s), %(host)s, (FROM_UNIXTIME(%(time)s), %(host)s,
%(uname)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], "time": v[4],
"host": v[6], "host": v[6],
"uname": v[0], "uname": v[0],
"lres": v[5], "lres": v[5],
"result": data[5],
"reason": v[9], "reason": v[9],
"solution": v[2], "solution": v[2],
"difficulty": v[3] "difficulty": v[3]

View File

@ -42,36 +42,47 @@ def setup(on_startup):
try: try:
result = (yield bitcoin_rpc.getblocktemplate()) result = (yield bitcoin_rpc.getblocktemplate())
if isinstance(result, dict): if isinstance(result, dict):
print(result)
# litecoind implements version 1 of getblocktemplate # litecoind implements version 1 of getblocktemplate
if result['version'] >= 1: 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: else:
log.error("Block Version mismatch: %s" % result['version']) log.error("Block Version mismatch: %s" % result['version'])
except ConnectionRefusedError, e: 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() reactor.stop()
break break
except Exception, e: except Exception, e:
print(e)
if isinstance(e[2], str): if isinstance(e[2], str):
print(e[2]) try:
if isinstance(json.loads(e[2])['error']['message'], str): if isinstance(json.loads(e[2])['error']['message'], str):
error = json.loads(e[2])['error']['message'] error = json.loads(e[2])['error']['message']
if error == "Method not found": if error == "Method not found":
log.error("Litecoind does not support getblocktemplate!!! (time to upgrade.)") log.error("CoinD does not support getblocktemplate!!! (time to upgrade.)")
reactor.stop() reactor.stop()
elif error == "Litecoind is downloading blocks...": elif "downloading blocks" in error:
log.error("Litecoind downloading blockchain... will check back in 30 sec") log.error("CoinD downloading blockchain... will check back in 30 sec")
time.sleep(29) time.sleep(29)
else: else:
log.error("Litecoind Error: %s", error) 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 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 # Start the coinbaser
coinbaser = SimpleCoinbaser(bitcoin_rpc, getattr(settings, 'CENTRAL_WALLET')) coinbaser = SimpleCoinbaser(bitcoin_rpc, getattr(settings, 'CENTRAL_WALLET'))

View File

@ -134,7 +134,7 @@ class BasicShareLimiter(object):
if settings.VDIFF_X2_TYPE: if settings.VDIFF_X2_TYPE:
ddiff = 2 ddiff = 2
# Don't go above LITECOIN or VDIFF_MAX_TARGET # Don't go above LITECOIN or VDIFF_MAX_TARGET
if settings.USE_LITECOIN_DIFF: if settings.USE_COINDAEMON_DIFF:
self.update_litecoin_difficulty() self.update_litecoin_difficulty()
diff_max = min([settings.VDIFF_MAX_TARGET, self.litecoin_diff]) diff_max = min([settings.VDIFF_MAX_TARGET, self.litecoin_diff])
else: else:
@ -146,7 +146,7 @@ class BasicShareLimiter(object):
if ddiff < 1: if ddiff < 1:
ddiff = 1 ddiff = 1
# Don't go above LITECOIN or VDIFF_MAX_TARGET # Don't go above LITECOIN or VDIFF_MAX_TARGET
if settings.USE_LITECOIN_DIFF: if settings.USE_COINDAEMON_DIFF:
self.update_litecoin_difficulty() self.update_litecoin_difficulty()
diff_max = min([settings.VDIFF_MAX_TARGET, self.litecoin_diff]) diff_max = min([settings.VDIFF_MAX_TARGET, self.litecoin_diff])
else: else:

View File

@ -30,10 +30,10 @@ class WorkerManagerInterface(object):
def get_user_difficulty(self, worker_name): def get_user_difficulty(self, worker_name):
wd = dbi.get_user(worker_name) wd = dbi.get_user(worker_name)
if len(wd) > 6: if len(wd) > 6:
#dbi.update_worker_diff(worker_name, wd[6]) if wd[6] != 0:
return (True, wd[6]) return (True, wd[6])
else: #dbi.update_worker_diff(worker_name, wd[6])
return (False, settings.POOL_TARGET) return (False, settings.POOL_TARGET)
def register_work(self, worker_name, job_id, difficulty): def register_work(self, worker_name, job_id, difficulty):
now = Interfaces.timestamper.time() now = Interfaces.timestamper.time()
@ -105,7 +105,13 @@ class Interfaces(object):
share_limiter = None share_limiter = None
timestamper = None timestamper = None
template_registry = None template_registry = None
lib.settings = None
@classmethod
def set_settings(cls, settings):
lib.settings.setup()
cls.settings = lib.settings
@classmethod @classmethod
def set_worker_manager(cls, manager): def set_worker_manager(cls, manager):
cls.worker_manager = manager cls.worker_manager = manager

View File

@ -7,7 +7,7 @@ from stratum.pubsub import Pubsub
from interfaces import Interfaces from interfaces import Interfaces
from subscription import MiningSubscription from subscription import MiningSubscription
from lib.exceptions import SubmitException from lib.exceptions import SubmitException
import json
import lib.logger import lib.logger
log = lib.logger.get_logger('mining') log = lib.logger.get_logger('mining')
@ -21,7 +21,37 @@ class MiningService(GenericService):
service_type = 'mining' service_type = 'mining'
service_vendor = 'stratum' service_vendor = 'stratum'
is_default = True 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 @admin
def update_block(self): def update_block(self):
'''Connect this RPC call to 'litecoind -blocknotify' for '''Connect this RPC call to 'litecoind -blocknotify' for