Cleaned up Logging, POS/POW checking and added more debug logs for errors

This commit is contained in:
Ahmed Bodiwala 2013-12-28 01:49:45 +00:00
parent 36e185e54e
commit 6e0ec479b9
16 changed files with 150 additions and 97 deletions

View File

@ -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,10 +41,10 @@ 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.debug("Submitting Block with Submit Block ")
log.info([block_hex,])
resp = (yield self._call('submitblock', [block_hex,]))
except Exception:
@ -53,11 +54,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))
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)
@ -83,20 +85,20 @@ class BitcoinRPC(object):
@defer.inlineCallbacks
def validateaddress(self, address):
resp = (yield self._call('validateaddress', [address,]))
defer.returnValue(json.loads(resp)['result'])
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)
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)

View File

@ -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()

View File

@ -7,6 +7,10 @@ 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
import settings
@ -19,7 +23,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

View File

@ -17,6 +17,7 @@ class BlockUpdater(object):
'''
def __init__(self, registry, bitcoin_rpc):
log.debug("Got to Block Updater")
self.bitcoin_rpc = bitcoin_rpc
self.registry = registry
self.clock = None

View File

@ -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 coinbaser")
# Fire Callback when the coinbaser is ready
self.on_load = defer.Deferred()
@ -31,49 +31,71 @@ class SimpleCoinbaser(object):
d.addErrback(self._failure)
def _POW_address_check(self, result):
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("Is Script = %s" % result['isscript'])
log.debug("PubKey = %s " % result['pubkey'])
log.debug("Is Compressed = %s " % result['iscompressed'])
log.debug("Account = %s " % result['account'])
if result['isvalid'] and result['ismine']:
self.is_valid = True
log.info("Wallet address '%s' is valid" % self.address)
if not self.on_load.called:
self.on_load.callback(True)
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)
elif result['isvalid'] and settings.ALLOW_NONLOCAL_WALLET == True :
self.is_valid = True
log.warning("!!! Wallet address '%s' is valid BUT it is not local" % self.address)
if not self.on_load.called:
self.on_load.callback(True)
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)
log.exception("Wallet 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'] == True:
log.debug("Is Valid = %s" % result['isvalid'])
log.debug("Address = %s " % result['address'])
log.debug("Is Script = %s" % result['isscript'])
log.debug("PubKey = %s " % result['pubkey'])
log.debug("Is Compressed = %s " % result['iscompressed'])
log.debug("Account = %s " % result['account'])
if result['isvalid'] and result['ismine']:
self.is_valid = True
log.info("Wallet address '%s' is valid" % self.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("!!! Wallet 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.exception("Wallet address '%s' is NOT valid!" % self.address)
#def on_new_block(self):
# pass
#def on_new_template(self):
# pass
def _failure(self, failure):
log.error("Cannot validate Bitcoin address '%s'" % self.address)
log.exception("Cannot validate Wallet address '%s'" % self.address)
raise
def get_script_pubkey(self):
if settings.COINDAEMON_Reward == 'POW':
if not self.is_valid:
self._validate()
raise Exception("Wallet Address is Wrong")
self._validate()
return util.script_to_address(self.address)
else:
return util.script_to_pubkey(self.pubkey)
else: return util.script_to_pubkey(self.pubkey)
def get_coinbase_data(self):
return ''

View File

@ -3,6 +3,10 @@ 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 +19,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:
@ -62,7 +66,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:
@ -110,7 +114,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:

View File

@ -1,4 +1,7 @@
import struct
import lib.logger
log = lib.logger.get_logger('extronance')
class ExtranonceCounter(object):
'''Implementation of a counter producing
@ -9,7 +12,8 @@ class ExtranonceCounter(object):
def __init__(self, instance_id):
if instance_id < 0 or instance_id > 31:
raise Exception("Current ExtranonceCounter implementation needs an instance_id in <0, 31>.")
log.debug("Got To Extronance")
# Last 5 most-significant bits represents instance_id
# The rest is just an iterator of jobs.
self.counter = instance_id << 27
@ -22,4 +26,4 @@ class ExtranonceCounter(object):
def get_new_bin(self):
self.counter += 1
return struct.pack('>L', self.counter)

View File

@ -14,35 +14,36 @@ from Crypto.Hash import SHA256
from twisted.internet.protocol import Protocol
from util import *
import settings
if settings.COINDAEMON_ALGO == 'scrypt':
print("########################################### Loading LTC Scrypt Module #########################################################")
import ltc_scrypt
elif settings.COINDAEMON_ALGO == 'quark':
print("########################################### Loading Quark Module #########################################################")
import quark_hash
else:
print("########################################### NOT Loading LTC Scrypt Module ######################################################")
pass
if settings.COINDAEMON_Reward == 'POS':
print("########################################### Loading POS Support #########################################################")
pass
else:
print("########################################### NOT Loading POS Support ######################################################")
pass
if settings.COINDAEMON_TX_MSG == 'yes':
print("########################################### Loading SHA256 Transaction Message Support #########################################################")
print(settings.Tx_Message)
pass
else:
print("########################################### NOT Loading SHA256 Transaction Message Support ######################################################")
pass
import lib.logger
log = lib.logger.get_logger('halfnode')
log.debug("Got to Halfnode")
if settings.COINDAEMON_ALGO == 'scrypt':
log.debug("########################################### Loading LTC Scrypt #########################################################")
import ltc_scrypt
elif settings.COINDAEMON_ALGO == 'quark':
log.debug("########################################### Loading Quark Support #########################################################")
import quark_hash
else:
log.debug("########################################### Loading SHA256 Support ######################################################")
pass
if settings.COINDAEMON_Reward == 'POS':
log.debug("########################################### Loading POS Support #########################################################")
pass
else:
log.debug("########################################### Loading POW Support ######################################################")
pass
if settings.COINDAEMON_TX_MSG == 'yes':
log.debug("########################################### Loading Transaction Message Support #########################################################")
log.info(settings.Tx_Message)
pass
else:
pass
MY_VERSION = 31402
MY_SUBVERSION = ".4"

View File

@ -46,7 +46,7 @@ class TemplateRegistry(object):
self.extranonce_counter = ExtranonceCounter(instance_id)
self.extranonce2_size = block_template_class.coinbase_transaction_class.extranonce_size \
- self.extranonce_counter.get_size()
log.debug("Got to Template Registry")
self.coinbaser = coinbaser
self.block_template_class = block_template_class
self.bitcoin_rpc = bitcoin_rpc
@ -63,11 +63,13 @@ class TemplateRegistry(object):
def get_new_extranonce1(self):
'''Generates unique extranonce1 (e.g. for newly
subscribed connection.'''
log.debug("Getting Unique 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 arguments needed for mining.notify")
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,15 @@ class TemplateRegistry(object):
if not job.is_valid():
# Should not happen
log.error("Final job validation failed!")
log.info("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)
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()

View File

@ -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'

View File

@ -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()

View File

@ -81,11 +81,11 @@ 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, 'N', %(reason)s, %(solution)s, %(difficulty)s)
""",
{
"time": v[4],
@ -93,7 +93,8 @@ class DB_Mysql():
"uname": v[0],
"lres": v[5],
"reason": v[9],
"solution": v[2]
"solution": v[2],
"difficulty": v[3]
}
)
@ -344,5 +345,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?")

View File

@ -44,11 +44,13 @@ def setup(on_startup):
if isinstance(result, dict):
# litecoind implements version 1 of getblocktemplate
if result['version'] >= 1:
result = (yield bitcoin_rpc.getinfo())
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!")
@ -64,19 +66,23 @@ def setup(on_startup):
except Exception, e:
if isinstance(e[2], str):
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'))

View File

@ -103,11 +103,11 @@ class BasicShareLimiter(object):
# Set up and log our check
self.worker_stats[worker_name]['last_rtc'] = ts
avg = self.worker_stats[worker_name]['buffer'].avg()
log.info("Checking Retarget for %s (%i) avg. %i target %i+-%i" % (worker_name, current_difficulty, avg,
log.debug("Checking Retarget for %s (%i) avg. %i target %i+-%i" % (worker_name, current_difficulty, avg,
self.target, self.variance))
if avg < 1:
log.info("Reseting avg = 1 since it's SOOO low")
log.warning("Reseting avg = 1 since it's SOOO low")
avg = 1
# Figure out our Delta-Diff
@ -163,7 +163,7 @@ class BasicShareLimiter(object):
new_diff = current_difficulty * ddiff
else:
new_diff = current_difficulty + ddiff
log.info("Retarget for %s %i old: %i new: %i" % (worker_name, ddiff, current_difficulty, new_diff))
log.debug("Retarget for %s %i old: %i new: %i" % (worker_name, ddiff, current_difficulty, new_diff))
self.worker_stats[worker_name]['buffer'].clear()
session = connection_ref().get_session()
@ -174,6 +174,8 @@ class BasicShareLimiter(object):
session['difficulty'] = new_diff
connection_ref().rpc('mining.set_difficulty', [new_diff, ], is_notification=True)
log.debug("Notified of New Difficulty")
connection_ref().rpc('mining.notify', [work_id, prevhash, coinb1, coinb2, merkle_branch, version, nbits, ntime, False, ], is_notification=True)
dbi.update_worker_diff(worker_name, new_diff)
log.debug("Sent new work")
dbi.update_worker_diff(worker_name, new_diff)

View File

@ -76,7 +76,7 @@ class ShareManagerInterface(object):
pass
def on_submit_share(self, worker_name, block_header, block_hash, difficulty, timestamp, is_valid, ip, invalid_reason, share_diff):
log.info("%s (%s) %s %s" % (block_hash, share_diff, 'valid' if is_valid else 'INVALID', worker_name))
log.debug("%s (%s) %s %s" % (block_hash, share_diff, 'valid' if is_valid else 'INVALID', worker_name))
dbi.queue_share([worker_name, block_header, block_hash, difficulty, timestamp, is_valid, ip, self.block_height, self.prev_hash,
invalid_reason, share_diff ])

View File

@ -12,7 +12,7 @@ def _WorkLogPruner_I(wl):
if now > userwork[wli][2] + 120:
del userwork[wli]
pruned += 1
log.debug('Pruned %d jobs' % (pruned,))
log.info('Pruned %d jobs' % (pruned,))
def WorkLogPruner(wl):
while True: