diff --git a/lib/bitcoin_rpc_manager.py b/lib/bitcoin_rpc_manager.py index 06b6c8e..9977e87 100644 --- a/lib/bitcoin_rpc_manager.py +++ b/lib/bitcoin_rpc_manager.py @@ -124,7 +124,6 @@ class BitcoinRPCManager(object): except: self.next_connection() - def getdifficulty(self): while True: try: diff --git a/lib/block_template.py b/lib/block_template.py index e04ee53..e30bcf9 100644 --- a/lib/block_template.py +++ b/lib/block_template.py @@ -19,6 +19,7 @@ class BlockTemplate(halfnode.CBlock): coinbase_transaction_class = CoinbaseTransaction def __init__(self, timestamper, coinbaser, job_id): + print("Hit Block_template.py") super(BlockTemplate, self).__init__() self.job_id = job_id @@ -46,10 +47,13 @@ class BlockTemplate(halfnode.CBlock): #txhashes = [None] + [ binascii.unhexlify(t['hash']) for t in data['transactions'] ] txhashes = [None] + [ util.ser_uint256(int(t['hash'], 16)) for t in data['transactions'] ] mt = merkletree.MerkleTree(txhashes) + if settings.COINDAEMON_Reward == 'POW': + coinbase = self.coinbase_transaction_class(self.timestamper, self.coinbaser, data['coinbasevalue'], data['coinbaseaux']['flags'], data['height'], + settings.COINBASE_EXTRAS) + else: + coinbase = self.coinbase_transaction_class(self.timestamper, self.coinbaser, data['coinbasevalue'], data['coinbaseaux']['flags'], data['height'], + settings.COINBASE_EXTRAS, data['curtime']) - coinbase = self.coinbase_transaction_class(self.timestamper, self.coinbaser, data['coinbasevalue'], - data['coinbaseaux']['flags'], data['height'], settings.COINBASE_EXTRAS) - self.height = data['height'] self.nVersion = data['version'] self.hashPrevBlock = int(data['previousblockhash'], 16) diff --git a/lib/coinbaser.py b/lib/coinbaser.py index 97f3c88..932bdf8 100644 --- a/lib/coinbaser.py +++ b/lib/coinbaser.py @@ -9,59 +9,71 @@ log = lib.logger.get_logger('coinbaser') # TODO: Add on_* hooks in the app class SimpleCoinbaser(object): - '''This very simple coinbaser uses a constant coin address + '''This very simple coinbaser uses constant bitcoin address for all generated blocks.''' def __init__(self, bitcoin_rpc, address): - # Fire callback when coinbaser is ready - self.on_load = defer.Deferred() - + print("hit the coinbaser") + # Fire Callback when the coinbaser is ready + self.on_load = defer.Deferred() + self.address = address - self.is_valid = False # We need to check if pool can use this address - - self.bitcoin_rpc = bitcoin_rpc - self._validate() + self.is_valid = False + + self.bitcoin_rpc = bitcoin_rpc + self._validate() def _validate(self): - d = self.bitcoin_rpc.validateaddress(self.address) - d.addCallback(self._address_check) - d.addErrback(self._failure) - - def _address_check(self, result): - 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) - - 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) + d = self.bitcoin_rpc.validateaddress(self.address) + if settings.COINDAEMON_Reward == 'POW': + d.addCallback(self._POW_address_check) + else: d.addCallback(self._POS_address_check) + 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 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) + else: + self.is_valid = False + log.error("Coinbase address '%s' is NOT valid!" % self.address) - def _failure(self, failure): - log.error("Cannot validate Bitcoin address '%s'" % self.address) - raise + 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) #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) + raise def get_script_pubkey(self): - if not self.is_valid: - # Try again, maybe the coind was down? - self._validate() - raise Exception("Coinbase address is not validated!") - return util.script_to_address(self.address) + if settings.COINDAEMON_Reward == 'POW': + if not self.is_valid: + self._validate() + raise Exception("Wallet Address is Wrong") + return util.script_to_address(self.address) + else: + return util.script_to_pubkey(self.pubkey) def get_coinbase_data(self): return '' diff --git a/lib/coinbasetx.py b/lib/coinbasetx.py index 11c7e36..e2d5743 100644 --- a/lib/coinbasetx.py +++ b/lib/coinbasetx.py @@ -2,8 +2,9 @@ import binascii import halfnode import struct import util - -class CoinbaseTransaction(halfnode.CTransaction): +import settings +if settings.COINDAEMON_Reward == 'POW': + class CoinbaseTransaction(halfnode.CTransaction): '''Construct special transaction used for coinbase tx. It also implements quick serialization using pre-cached scriptSig template.''' @@ -46,4 +47,50 @@ class CoinbaseTransaction(halfnode.CTransaction): raise Exception("Incorrect extranonce size") (part1, part2) = self.vin[0]._scriptSig_template - self.vin[0].scriptSig = part1 + extranonce + part2 \ No newline at end of file + self.vin[0].scriptSig = part1 + extranonce + part2 +else: + class CoinbaseTransaction(halfnode.CTransaction): + '''Construct special transaction used for coinbase tx. + It also implements quick serialization using pre-cached + scriptSig template.''' + + extranonce_type = '>Q' + extranonce_placeholder = struct.pack(extranonce_type, int('f000000ff111111f', 16)) + extranonce_size = struct.calcsize(extranonce_type) + + def __init__(self, timestamper, coinbaser, value, flags, height, data, ntime): + super(CoinbaseTransaction, self).__init__() + + #self.extranonce = 0 + + if len(self.extranonce_placeholder) != self.extranonce_size: + raise Exception("Extranonce placeholder don't match expected length!") + + tx_in = halfnode.CTxIn() + tx_in.prevout.hash = 0L + tx_in.prevout.n = 2**32-1 + tx_in._scriptSig_template = ( + util.ser_number(height) + binascii.unhexlify(flags) + util.ser_number(int(timestamper.time())) + \ + chr(self.extranonce_size), + util.ser_string(coinbaser.get_coinbase_data() + data) + ) + + tx_in.scriptSig = tx_in._scriptSig_template[0] + self.extranonce_placeholder + tx_in._scriptSig_template[1] + + tx_out = halfnode.CTxOut() + tx_out.nValue = value + tx_out.scriptPubKey = coinbaser.get_script_pubkey() + + self.nTime = ntime + self.vin.append(tx_in) + self.vout.append(tx_out) + + # Two parts of serialized coinbase, just put part1 + extranonce + part2 to have final serialized tx + self._serialized = super(CoinbaseTransaction, self).serialize().split(self.extranonce_placeholder) + + def set_extranonce(self, extranonce): + if len(extranonce) != self.extranonce_size: + raise Exception("Incorrect extranonce size") + + (part1, part2) = self.vin[0]._scriptSig_template + self.vin[0].scriptSig = part1 + extranonce + part2 diff --git a/lib/halfnode.py b/lib/halfnode.py index 576ea8b..b03a6f5 100644 --- a/lib/halfnode.py +++ b/lib/halfnode.py @@ -138,25 +138,49 @@ class CTxOut(object): class CTransaction(object): def __init__(self): - self.nVersion = 1 - self.vin = [] - self.vout = [] - self.nLockTime = 0 - self.sha256 = None + if settings.COINDAEMON_Reward == 'POW': + self.nVersion = 1 + self.vin = [] + self.vout = [] + self.nLockTime = 0 + self.sha256 = None + else: + self.nVersion = 1 + self.nTime = 0 + self.vin = [] + self.vout = [] + self.nLockTime = 0 + self.sha256 = None def deserialize(self, f): - self.nVersion = struct.unpack(" target_user and \ + ( 'prev_jobid' not in session or session['prev_jobid'] < job_id \ + or 'prev_diff' not in session or hash_int > self.diff_to_target(session['prev_diff']) ): + raise SubmitException("Share is above target") + + # Mostly for debugging purposes + target_info = self.diff_to_target(100000) + if hash_int <= target_info: + log.info("Yay, share with diff above 100000") + + # Algebra tells us the diff_to_target is the same as hash_to_diff + share_diff = int(self.diff_to_target(hash_int)) + + + # 5. Compare hash with target of the network + if hash_int <= job.target: + # Yay! It is block candidate! + log.info("We found a block candidate! %s" % scrypt_hash_hex) + + # Reverse the header and get the potential block hash (for scrypt only) + block_hash_bin = util.doublesha(''.join([ header_bin[i*4:i*4+4][::-1] for i in range(0, 20) ])) + block_hash_hex = block_hash_bin[::-1].encode('hex_codec') + + # 6. Finalize and serialize block object + job.finalize(merkle_root_int, extranonce1_bin, extranonce2_bin, int(ntime, 16), int(nonce, 16)) + + if not job.is_valid(): + # Should not happen + log.error("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 on_submit: + self.update_block() + + if settings.SOLUTION_BLOCK_HASH: + return (header_hex, block_hash_hex, share_diff, on_submit) + else: + return (header_hex, scrypt_hash_hex, share_diff, on_submit) + + if settings.SOLUTION_BLOCK_HASH: + # Reverse the header and get the potential block hash (for scrypt only) only do this if we want to send in the block hash to the shares table + block_hash_bin = util.doublesha(''.join([ header_bin[i*4:i*4+4][::-1] for i in range(0, 20) ])) + block_hash_hex = block_hash_bin[::-1].encode('hex_codec') + return (header_hex, block_hash_hex, share_diff, None) + else: + return (header_hex, scrypt_hash_hex, share_diff, None) diff --git a/lib/util.py b/lib/util.py index 050876c..1b41659 100644 --- a/lib/util.py +++ b/lib/util.py @@ -3,6 +3,8 @@ import struct import StringIO import binascii +import settings +import bitcoin_rpc from hashlib import sha256 def deser_string(f): @@ -171,7 +173,7 @@ def address_to_pubkeyhash(addr): addr = b58decode(addr, 25) except: return None - + if addr is None: return None @@ -209,9 +211,15 @@ def ser_number(n): s.append(n) return bytes(s) -def script_to_address(addr): - d = address_to_pubkeyhash(addr) - if not d: - raise ValueError('invalid address') - (ver, pubkeyhash) = d - return b'\x76\xa9\x14' + pubkeyhash + b'\x88\xac' +if settings.COINDAEMON_Reward == 'POW': + def script_to_address(addr): + d = address_to_pubkeyhash(addr) + if not d: + raise ValueError('invalid address') + (ver, pubkeyhash) = d + return b'\x76\xa9\x14' + pubkeyhash + b'\x88\xac' +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') + return b'\x21' + key + b'\xac' diff --git a/mining/basic_share_limiter.py b/mining/basic_share_limiter.py index adc04c2..73450c2 100644 --- a/mining/basic_share_limiter.py +++ b/mining/basic_share_limiter.py @@ -125,7 +125,7 @@ class BasicShareLimiter(object): ddiff = 1 # Don't go above LITECOIN or VDIFF_MAX_TARGET self.update_litecoin_difficulty() - if settings.USE_LITECOIN_DIFF: + if settings.USE_COINDAEMON_DIFF: diff_max = min([settings.VDIFF_MAX_TARGET, self.litecoin_diff]) else: diff_max = settings.VDIFF_MAX_TARGET