def withFirstTwo(self, f1, f2): print('withFirstTwo called') print('f1: ' + str(f1)) print('f2: ' + str(f2)) steps = self._steps print(str(len(steps)) + ' steps') f = doublesha(f1 + f2) for s in steps: f = doublesha(f + s) return f
def recalculate(self, detailed=False): L = self.data steps = [] if detailed: detail = [] PreL = [] StartL = 0 else: detail = None PreL = [None] StartL = 2 Ll = len(L) if detailed or Ll > 1: while True: if detailed: detail += L if Ll == 1: break steps.append(L[1]) if Ll % 2: L += [L[-1]] L = PreL + [ doublesha(L[i] + L[i + 1]) for i in range(StartL, Ll, 2) ] Ll = len(L) self._steps = steps self.detail = detail
def hash_steps(self): if self._hash_steps == None: if settings.COINDAEMON_ALGO == 'heavy': self._hash_steps = heavycoin_hash.getHash(''.join(self._steps), len(''.join(self._steps))) else: self._hash_steps = doublesha(''.join(self._steps)) return self._hash_steps
def recalculate(self, detailed=False): L = self.data steps = [] if detailed: detail = [] PreL = [] StartL = 0 else: detail = None PreL = [None] StartL = 2 Ll = len(L) if detailed or Ll > 1: while True: if detailed: detail += L if Ll == 1: break steps.append(L[1]) if Ll % 2: L += [L[-1]] if settings.COINDAEMON_ALGO == 'heavy': L = PreL + [heavycoin_hash.getHash(L[i] + L[i + 1], len(L[i] + L[i + 1])) for i in range(StartL, Ll, 2)] else: L = PreL + [doublesha(L[i] + L[i + 1]) for i in range(StartL, Ll, 2)] Ll = len(L) self._steps = steps self.detail = detail
def recalculate(self, detailed=False): L = self.data steps = [] if detailed: detail = [] PreL = [] StartL = 0 else: detail = None PreL = [None] StartL = 2 Ll = len(L) print('passing to merkle tree: ' + str(Ll)) if detailed or Ll > 2: # next line is vDinar only first_step = True while True: if detailed: detail += L if Ll == 1: break # next line is vDinar only if not first_step: steps.append(L[1]) # original next line: if Ll % 2: if Ll % 2: L += [L[-1]] L = PreL + [doublesha(L[i] + L[i + 1]) for i in range(StartL, Ll, 2)] Ll = len(L) # next lines are vDinar only if first_step: first_step = False self._steps = steps self.detail = detail
def recalculate(self, detailed=False): L = self.data steps = [] if detailed: detail = [] PreL = [] StartL = 0 else: detail = None PreL = [None] StartL = 2 Ll = len(L) if detailed or Ll > 1: while True: if detailed: detail += L if Ll == 1: break steps.append(L[1]) if Ll % 2: L += [L[-1]] L = PreL + [doublesha(L[i] + L[i + 1]) for i in range(StartL, Ll, 2)] Ll = len(L) self._steps = steps self.detail = detail
def recalculate(self, detailed=False): L = self.data steps = [] if detailed: detail = [] PreL = [] StartL = 0 else: detail = None PreL = [None] StartL = 2 Ll = len(L) if detailed or Ll > 1: while True: if detailed: detail += L if Ll == 1: break steps.append(L[1]) if Ll % 2: L += [L[-1]] if settings.COINDAEMON_ALGO == 'heavy': L = PreL + [ heavycoin_hash.getHash(L[i] + L[i + 1], len(L[i] + L[i + 1])) for i in range(StartL, Ll, 2) ] else: L = PreL + [ doublesha(L[i] + L[i + 1]) for i in range(StartL, Ll, 2) ] Ll = len(L) self._steps = steps self.detail = detail
def withFirst(self, f): steps = self._steps for s in steps: if settings.COINDAEMON_ALGO == 'heavy': f = heavycoin_hash.getHash(f + s, len(f + s)) else: f = doublesha(f + s) return f
def hash_steps(self): if self._hash_steps == None: if settings.COINDAEMON_ALGO == 'heavy': self._hash_steps = heavycoin_hash.getHash( ''.join(self._steps), len(''.join(self._steps))) else: self._hash_steps = doublesha(''.join(self._steps)) return self._hash_steps
def submit_share(self, job_id, worker_name, session, extranonce1_bin, data, difficulty): job = self.get_job(job_id) if job == None: raise SubmitException("Job '%s' not found" % job_id) ntime = util.flip(data[136:144]) if not job.check_ntime(int(ntime, 16)): raise SubmitException("Ntime out of range") if not job.register_submit(data): log.info("Duplicate from %s, (%s %s)" % \ (worker_name, binascii.hexlify(extranonce1_bin), data)) raise SubmitException("Duplicate share") hash_int = gapcoin_hash.getpowdiff(str(data)) block_hash_bin = util.doublesha(binascii.unhexlify(data[0:168])) block_hash_hex = util.rev(binascii.hexlify(block_hash_bin)) '''log.info("block_hash_hex %s" % block_hash_hex) log.info("shrint %s" % hash_int) log.info("jobint %s" % job.target)%f log.info("target %s" % difficulty)''' if hash_int < difficulty: raise SubmitException("Share less than target") share_diff = float(float(hash_int) / float(pow(2, 48))) if hash_int >= job.target: log.info("BLOCK CANDIDATE! %s" % block_hash_hex) extranonce2_bin = struct.pack('>L', 0) #self.last_block.vtx[0].set_extranonce(extranonce1_bin + extranonce2_bin) #txs = binascii.hexlify(util.ser_vector(self.last_block.vtx)) job.vtx[0].set_extranonce(extranonce1_bin + extranonce2_bin) txs = binascii.hexlify(util.ser_vector(job.vtx)) serialized = str(data) + str(txs) on_submit = self.bitcoin_rpc.submitblock(str(data), str(txs), block_hash_hex) if on_submit: self.update_block() return (block_hash_hex, share_diff, on_submit) return (block_hash_hex, share_diff, None)
def withFirst(self, f): steps = self._steps for s in steps: f = doublesha(f + s) return f
def hash_steps(self): if self._hash_steps == None: self._hash_steps = doublesha("".join(self._steps)) return self._hash_steps
class TemplateRegistry(object): '''Implements the main logic of the pool. Keep track on valid block templates, provide internal interface for stratum service and implements block validation and submits.''' def __init__(self, block_template_class, coinbaser, bitcoin_rpc, instance_id, on_template_callback, on_block_callback): self.prevhashes = {} self.jobs = weakref.WeakValueDictionary() 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 self.on_block_callback = on_block_callback self.on_template_callback = on_template_callback self.last_block = None self.update_in_progress = False self.last_update = None # Create first block template on startup self.update_block() 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 Laat Template") return self.last_block.broadcast_args def add_template(self, block,block_height): '''Adds new template to the registry. It also clean up templates which should not be used anymore.''' prevhash = block.prevhash_hex if prevhash in self.prevhashes.keys(): new_block = False else: new_block = True self.prevhashes[prevhash] = [] # Blocks sorted by prevhash, so it's easy to drop # them on blockchain update self.prevhashes[prevhash].append(block) # Weak reference for fast lookup using job_id self.jobs[block.job_id] = block # Use this template for every new request self.last_block = block # Drop templates of obsolete blocks for ph in self.prevhashes.keys(): if ph != prevhash: del self.prevhashes[ph] log.info("New template for %s" % prevhash) if new_block: # Tell the system about new block # It is mostly important for share manager self.on_block_callback(prevhash, block_height) # Everything is ready, let's broadcast jobs! self.on_template_callback(new_block) #from twisted.internet import reactor #reactor.callLater(10, self.on_block_callback, new_block) def update_block(self): '''Registry calls the getblocktemplate() RPC and build new block template.''' if self.update_in_progress: # Block has been already detected return self.update_in_progress = True self.last_update = Interfaces.timestamper.time() d = self.bitcoin_rpc.getblocktemplate() d.addCallback(self._update_block) d.addErrback(self._update_block_failed) def _update_block_failed(self, failure): log.error(str(failure)) self.update_in_progress = False def _update_block(self, data): start = Interfaces.timestamper.time() template = self.block_template_class(Interfaces.timestamper, self.coinbaser, JobIdGenerator.get_new_id()) log.info(template.fill_from_rpc(data)) self.add_template(template,data['height']) log.info("Update finished, %.03f sec, %d txes" % \ (Interfaces.timestamper.time() - start, len(template.vtx))) self.update_in_progress = False return data def diff_to_target(self, difficulty): '''Converts difficulty to target''' diff1 = coindef.diff1() return diff1 / difficulty def get_job(self, job_id, worker_name, ip=False): '''For given job_id returns BlockTemplate instance or None''' try: j = self.jobs[job_id] except: log.info("Job id '%s' not found, worker_name: '%s'" % (job_id, worker_name)) if ip: log.info("Worker submited invalid Job id: IP %s", str(ip)) return None # Now we have to check if job is still valid. # Unfortunately weak references are not bulletproof and # old reference can be found until next run of garbage collector. if j.prevhash_hex not in self.prevhashes: log.info("Prevhash of job '%s' is unknown" % job_id) return None if j not in self.prevhashes[j.prevhash_hex]: log.info("Job %s is unknown" % job_id) return None return j def submit_share(self, job_id, worker_name, session, extranonce1_bin, extranonce2, ntime, nonce, difficulty, ip=False): '''Check parameters and finalize block template. If it leads to valid block candidate, asynchronously submits the block back to the bitcoin network. - extranonce1_bin is binary. No checks performed, it should be from session data - job_id, extranonce2, ntime, nonce - in hex form sent by the client - difficulty - decimal number from session, again no checks performed - submitblock_callback - reference to method which receive result of submitblock() ''' # Check if extranonce2 looks correctly. extranonce2 is in hex form... if len(extranonce2) != self.extranonce2_size * 2: raise SubmitException("Incorrect size of extranonce2. Expected %d chars" % (self.extranonce2_size*2)) # Check for job job = self.get_job(job_id, worker_name, ip) if job == None: raise SubmitException("Job '%s' not found" % job_id) # Check if ntime looks correct if len(ntime) != 8: raise SubmitException("Incorrect size of ntime. Expected 8 chars") if not job.check_ntime(int(ntime, 16)): raise SubmitException("Ntime out of range") # Check nonce if len(nonce) != 8: raise SubmitException("Incorrect size of nonce. Expected 8 chars") # Check for duplicated submit if not job.register_submit(extranonce1_bin, extranonce2, ntime, nonce): log.info("Duplicate from %s, (%s %s %s %s)" % \ (worker_name, binascii.hexlify(extranonce1_bin), extranonce2, ntime, nonce)) raise SubmitException("Duplicate share") # Now let's do the hard work! # --------------------------- # 0. Some sugar extranonce2_bin = binascii.unhexlify(extranonce2) ntime_bin = binascii.unhexlify(ntime) nonce_bin = binascii.unhexlify(nonce) # 1. Build coinbase coinbase_bin = job.serialize_coinbase(extranonce1_bin, extranonce2_bin) coinbase_hash = util.doublesha(coinbase_bin) # 2. Calculate merkle root merkle_root_bin = job.merkletree.withFirst(coinbase_hash) merkle_root_int = util.uint256_from_str(merkle_root_bin) # 3. Serialize header with given merkle, ntime and nonce header_bin = job.serialize_header(merkle_root_int, ntime_bin, nonce_bin) # 4. Reverse header and compare it with target of the user hash_bin = algo.getPoWHash(''.join([ header_bin[i*4:i*4+4][::-1] for i in range(0, 20) ])) hash_int = util.uint256_from_str(hash_bin) scrypt_hash_hex = "%064x" % hash_int header_hex = binascii.hexlify(header_bin) if coindef.header() = True: header_hex = header_hex+"000000800000000000000000000000000000000000000000000000000000000000000000000000000000000080020000" target_user = self.diff_to_target(difficulty) if hash_int > target_user: 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.exception("FINAL JOB VALIDATION FAILED!(Try enabling/disabling tx messages)") # 7. Submit block to the network serialized = binascii.hexlify(job.serialize()) on_submit = self.bitcoin_rpc.submitblock(serialized, block_hash_hex, scrypt_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)
def submit_share(self, job_id, worker_name, session, extranonce1_bin, extranonce2, ntime, nonce, difficulty): '''Check parameters and finalize block template. If it leads to valid block candidate, asynchronously submits the block back to the bitcoin network. - extranonce1_bin is binary. No checks performed, it should be from session data - job_id, extranonce2, ntime, nonce - in hex form sent by the client - difficulty - decimal number from session, again no checks performed - submitblock_callback - reference to method which receive result of submitblock() ''' # Check if extranonce2 looks correctly. extranonce2 is in hex form... if len(extranonce2) != self.extranonce2_size * 2: raise SubmitException( "Incorrect size of extranonce2. Expected %d chars" % (self.extranonce2_size * 2)) # Check for job job = self.get_job(job_id) if job == None: raise SubmitException("Job '%s' not found" % job_id) # Check if ntime looks correct if len(ntime) != 8: raise SubmitException("Incorrect size of ntime. Expected 8 chars") if not job.check_ntime(int(ntime, 16)): raise SubmitException("Ntime out of range") # Check nonce if len(nonce) != 8: raise SubmitException("Incorrect size of nonce. Expected 8 chars") # Check for duplicated submit if not job.register_submit(extranonce1_bin, extranonce2, ntime, nonce): log.info("Duplicate from %s, (%s %s %s %s)" % \ (worker_name, binascii.hexlify(extranonce1_bin), extranonce2, ntime, nonce)) raise SubmitException("Duplicate share") # Now let's do the hard work! # --------------------------- # 0. Some sugar extranonce2_bin = binascii.unhexlify(extranonce2) ntime_bin = binascii.unhexlify(ntime) nonce_bin = binascii.unhexlify(nonce) # 1. Build coinbase coinbase_bin = job.serialize_coinbase(extranonce1_bin, extranonce2_bin) coinbase_hash = util.doublesha(coinbase_bin) # 2. Calculate merkle root merkle_root_bin = job.merkletree.withFirst(coinbase_hash) merkle_root_int = util.uint256_from_str(merkle_root_bin) # 3. Serialize header with given merkle, ntime and nonce header_bin = job.serialize_header(merkle_root_int, ntime_bin, nonce_bin) # 4. Reverse header and compare it with target of the user hash_bin = yac_scrypt.getPoWHash( ''.join([header_bin[i * 4:i * 4 + 4][::-1] for i in range(0, 20)]), int(ntime, 16)) hash_int = util.uint256_from_str(hash_bin) scrypt_hash_hex = "%064x" % hash_int header_hex = binascii.hexlify(header_bin) header_hex = header_hex + "000000800000000000000000000000000000000000000000000000000000000000000000000000000000000080020000" target_user = self.diff_to_target(difficulty) if hash_int > 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) # 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, scrypt_hash_hex) return (header_hex, scrypt_hash_hex, share_diff, on_submit) return (header_hex, scrypt_hash_hex, share_diff, None)
def submit_share(self, job_id, worker_name, extranonce1_bin, extranonce2, ntime, nonce, difficulty, payment_type): '''Check parameters and finalize block template. If it leads to valid block candidate, asynchronously submits the block back to the bitcoin network. - extranonce1_bin is binary. No checks performed, it should be from session data - job_id, extranonce2, ntime, nonce - in hex form sent by the client - difficulty - decimal number from session, again no checks performed - submitblock_callback - reference to method which receive result of submitblock() ''' # Check if extranonce2 looks correctly. extranonce2 is in hex form... if len(extranonce2) != self.extranonce2_size * 2: raise SubmitException("Incorrect size of extranonce2. Expected %d chars" % (self.extranonce2_size*2)) # Check for job job = self.get_job(job_id) if job == None: raise SubmitException("Job '%s' not found" % job_id) # Check if ntime looks correct if len(ntime) != 8: raise SubmitException("Incorrect size of ntime. Expected 8 chars") if not job.check_ntime(int(ntime, 16)): raise SubmitException("Ntime out of range") # Check nonce if len(nonce) != 8: raise SubmitException("Incorrect size of nonce. Expected 8 chars") # Check for duplicated submit if not job.register_submit(extranonce1_bin, extranonce2, ntime, nonce): logger.log('bad_client', worker_name, "Duplicate from %s, (%s %s %s %s)" % \ (worker_name, binascii.hexlify(extranonce1_bin), extranonce2, ntime, nonce)) raise SubmitException("Duplicate share") # Now let's do the hard work! # --------------------------- # 0. Some sugar extranonce2_bin = binascii.unhexlify(extranonce2) ntime_bin = binascii.unhexlify(ntime) nonce_bin = binascii.unhexlify(nonce) # 1. Build coinbase coinbase_bin = job.serialize_coinbase(extranonce1_bin, extranonce2_bin) coinbase_hash = util.doublesha(coinbase_bin) # 2. Calculate merkle root merkle_root_bin = job.merkletree.withFirst(coinbase_hash) merkle_root_int = util.uint256_from_str(merkle_root_bin) # 3. Serialize header with given merkle, ntime and nonce header_bin = job.serialize_header(merkle_root_int, ntime_bin, nonce_bin) # 4. Reverse header and compare it with target of the user hash_bin = util.doublesha(''.join([ header_bin[i*4:i*4+4][::-1] for i in range(0, 20) ])) hash_int = util.uint256_from_str(hash_bin) block_hash_hex = "%064x" % hash_int header_hex = binascii.hexlify(header_bin) target_user = self.diff_to_target(difficulty) #logger.log('share', worker_name, 'HASH %064x' % hash_int, 'TARGET %064x' % job.target, 'DIFF %d' % difficulty) if hash_int > target_user: logger.log('bad_client', 'Share is above target') raise SubmitException("Share is above target") if payment_type == 'PPS': logger.log('share', worker_name, 'HASH %064x' % hash_int, 'TARGET %064x' % job.target, 'DIFF %d' % difficulty) logger.log('pplns', worker_name, 'HASH %064x' % hash_int, 'DIFF %d' % difficulty, 'PAY 0') if payment_type == 'PPLNS': logger.log('pplns', worker_name, 'HASH %064x' % hash_int, 'DIFF %d' % difficulty, 'PAY 1') # 5. Compare hash with target of the network if hash_int <= job.target: # Yay! It is block candidate! logger.log('block', worker_name, block_hash_hex) # 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 logger.log('error', "Final job validation failed!") # 7. Submit block to the network serialized = binascii.hexlify(job.serialize()) on_submit = self.bitcoin_rpc.submitblock(serialized) logger.log('submitblock', serialized) return (True, worker_name, block_hash_hex) return (False, worker_name, block_hash_hex)
def hash_steps(self): if self._hash_steps == None: self._hash_steps = doublesha(''.join(self._steps)) return self._hash_steps
def submit_share(self, job_id, worker_name, extranonce1_bin, extranonce2, ntime, nonce, difficulty, payment_type): '''Check parameters and finalize block template. If it leads to valid block candidate, asynchronously submits the block back to the bitcoin network. - extranonce1_bin is binary. No checks performed, it should be from session data - job_id, extranonce2, ntime, nonce - in hex form sent by the client - difficulty - decimal number from session, again no checks performed - submitblock_callback - reference to method which receive result of submitblock() ''' # Check if extranonce2 looks correctly. extranonce2 is in hex form... if len(extranonce2) != self.extranonce2_size * 2: raise SubmitException( "Incorrect size of extranonce2. Expected %d chars" % (self.extranonce2_size * 2)) # Check for job job = self.get_job(job_id) if job == None: raise SubmitException("Job '%s' not found" % job_id) # Check if ntime looks correct if len(ntime) != 8: raise SubmitException("Incorrect size of ntime. Expected 8 chars") if not job.check_ntime(int(ntime, 16)): raise SubmitException("Ntime out of range") # Check nonce if len(nonce) != 8: raise SubmitException("Incorrect size of nonce. Expected 8 chars") # Check for duplicated submit if not job.register_submit(extranonce1_bin, extranonce2, ntime, nonce): logger.log('bad_client', worker_name, "Duplicate from %s, (%s %s %s %s)" % \ (worker_name, binascii.hexlify(extranonce1_bin), extranonce2, ntime, nonce)) raise SubmitException("Duplicate share") # Now let's do the hard work! # --------------------------- # 0. Some sugar extranonce2_bin = binascii.unhexlify(extranonce2) ntime_bin = binascii.unhexlify(ntime) nonce_bin = binascii.unhexlify(nonce) # 1. Build coinbase coinbase_bin = job.serialize_coinbase(extranonce1_bin, extranonce2_bin) coinbase_hash = util.doublesha(coinbase_bin) # 2. Calculate merkle root merkle_root_bin = job.merkletree.withFirst(coinbase_hash) merkle_root_int = util.uint256_from_str(merkle_root_bin) # 3. Serialize header with given merkle, ntime and nonce header_bin = job.serialize_header(merkle_root_int, ntime_bin, nonce_bin) # 4. Reverse header and compare it with target of the user hash_bin = util.doublesha(''.join( [header_bin[i * 4:i * 4 + 4][::-1] for i in range(0, 20)])) hash_int = util.uint256_from_str(hash_bin) block_hash_hex = "%064x" % hash_int header_hex = binascii.hexlify(header_bin) target_user = self.diff_to_target(difficulty) #logger.log('share', worker_name, 'HASH %064x' % hash_int, 'TARGET %064x' % job.target, 'DIFF %d' % difficulty) if hash_int > target_user: logger.log('bad_client', 'Share is above target') raise SubmitException("Share is above target") if payment_type == 'PPS': logger.log('share', worker_name, 'HASH %064x' % hash_int, 'TARGET %064x' % job.target, 'DIFF %d' % difficulty) logger.log('pplns', worker_name, 'HASH %064x' % hash_int, 'DIFF %d' % difficulty, 'PAY 0') if payment_type == 'PPLNS': logger.log('pplns', worker_name, 'HASH %064x' % hash_int, 'DIFF %d' % difficulty, 'PAY 1') # 5. Compare hash with target of the network if hash_int <= job.target: # Yay! It is block candidate! logger.log('block', worker_name, block_hash_hex) # 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 logger.log('error', "Final job validation failed!") # 7. Submit block to the network serialized = binascii.hexlify(job.serialize()) on_submit = self.bitcoin_rpc.submitblock(serialized) logger.log('submitblock', serialized) return (True, worker_name, block_hash_hex) return (False, worker_name, block_hash_hex)
def submit_share(self, job_id, worker_name, extranonce1_bin, extranonce2, ntime, nonce, difficulty): '''Check parameters and finalize block template. If it leads to valid block candidate, asynchronously submits the block back to the bitcoin network. - extranonce1_bin is binary. No checks performed, it should be from session data - job_id, extranonce2, ntime, nonce - in hex form sent by the client - difficulty - decimal number from session, again no checks performed - submitblock_callback - reference to method which receive result of submitblock() ''' global rsk_last_received_share_time global rsk_submitted_shares start = Interfaces.timestamper.time() logid = util.id_generator() log.info( json.dumps({ "rsk": "[RSKLOG]", "tag": "[SHARE_RECEIVED_START]", "uuid": logid, "start": start, "elapsed": 0 })) # Check if extranonce2 looks correctly. extranonce2 is in hex form... if len(extranonce2) != self.extranonce2_size * 2: raise SubmitException( "Incorrect size of extranonce2. Expected %d chars" % (self.extranonce2_size * 2)) # Check for job job = self.get_job(job_id) if job == None: raise SubmitException("Job '%s' not found" % job_id) # Check if ntime looks correct if len(ntime) != 8: raise SubmitException("Incorrect size of ntime. Expected 8 chars") if not job.check_ntime(int(ntime, 16)): raise SubmitException("Ntime out of range") # Check nonce if len(nonce) != 8: raise SubmitException("Incorrect size of nonce. Expected 8 chars") # Convert from hex to binary extranonce2_bin = binascii.unhexlify(extranonce2) ntime_bin = binascii.unhexlify(ntime) nonce_bin = binascii.unhexlify(nonce) # Check for duplicated submit if not job.register_submit(extranonce1_bin, extranonce2_bin, ntime_bin, nonce_bin): log.info("Duplicate from %s, (%s %s %s %s)" % \ (worker_name, binascii.hexlify(extranonce1_bin), extranonce2, ntime, nonce)) raise SubmitException("Duplicate share") # Now let's do the hard work! # --------------------------- # 1. Build coinbase coinbase_bin = job.serialize_coinbase(extranonce1_bin, extranonce2_bin) coinbase_hash = util.doublesha(coinbase_bin) # 2. Calculate merkle root merkle_root_bin = job.merkletree.withFirst(coinbase_hash) merkle_root_int = util.uint256_from_str(merkle_root_bin) # 3. Serialize header with given merkle, ntime and nonce header_bin = job.serialize_header(merkle_root_int, ntime_bin, nonce_bin) # 4. Reverse header and compare it with target of the user # header 80-bytes (19*4 + 4) header_le = ''.join( [header_bin[i * 4:i * 4 + 4][::-1] for i in range(0, 20)]) hash_bin = util.doublesha(header_le) hash_int = util.uint256_from_str(hash_bin) block_hash_hex = "%064x" % hash_int header_hex = binascii.hexlify(header_bin) log.info( json.dumps({ "rsk": "[RSKLOG]", "tag": "[SHARE_RECEIVED_HEX]", "uuid": logid, "start": Interfaces.timestamper.time(), "elapsed": 0, "data": block_hash_hex })) if not settings.RSK_DEV_MODE: target_user = self.diff_to_target(difficulty) if hash_int > target_user: 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") # 5. Compare hash with target of the network log.info("Hash_Int: %s, Job.Target %s" % (hash_int, job.target)) btc_solution = hash_int <= job.target rsk_solution = False if self.rootstock_rpc is not None: rsk_solution = hash_int <= self.rootstock_rpc.rsk_target and self._is_rsk_tag_in_coinbase( coinbase_bin) on_submit_rsk = None on_submit = None if btc_solution or rsk_solution: log.info("We found a block candidate! %s" % block_hash_hex) job.finalize(merkle_root_int, extranonce1_bin, extranonce2_bin, int(ntime, 16), int(nonce, 16)) if btc_solution: serialized = binascii.hexlify(job.serialize()) on_submit = self.bitcoin_rpc.submitblock(serialized) log.info( json.dumps({ "rsk": "[RSKLOG]", "tag": "[BTC_SUBMITBLOCK]", "uuid": util.id_generator(), "start": start, "elapsed": Interfaces.timestamper.time(), "data": block_hash_hex })) if rsk_solution: if rsk_last_received_share_time is None: rsk_last_received_share_time = int(round(time() * 1000)) rsk_submitted_shares = 0 last_received_share_time_now = int(round(time() * 1000)) if last_received_share_time_now - rsk_last_received_share_time >= 1000: rsk_submitted_shares = 0 rsk_last_received_share_time = last_received_share_time_now if last_received_share_time_now - rsk_last_received_share_time < 1000 and rsk_submitted_shares < 3: rsk_submitted_shares += 1 else: return (header_hex, block_hash_hex, on_submit, on_submit_rsk) serialized = binascii.hexlify(job.serialize()) block_header_hex = binascii.hexlify(header_le) coinbase_hex = binascii.hexlify(coinbase_bin) coinbase_hash_hex = binascii.hexlify(coinbase_hash) merkle_hashes_array = [ binascii.hexlify(x) for x in job.merkletree._steps ] merkle_hashes_array.insert(0, coinbase_hash_hex) merkle_hashes = ' '.join(merkle_hashes_array) txn_count = hex(len(merkle_hashes_array))[2:] on_submit_rsk = self.rootstock_rpc.submitBitcoinBlockPartialMerkle( block_hash_hex, block_header_hex, coinbase_hex, merkle_hashes, txn_count) log.info( json.dumps({ "rsk": "[RSKLOG]", "tag": "[RSK_SUBMITBLOCK]", "uuid": util.id_generator(), "start": start, "elapsed": Interfaces.timestamper.time(), "data": block_hash_hex })) return (header_hex, block_hash_hex, on_submit, on_submit_rsk)
def calcparent(self, hash1, hash2): if type(hash1) == long: hash1 = util.ser_uint256(hash1) if type(hash2) == long: hash2 = util.ser_uint256(hash2) return util.doublesha(hash1 + hash2)
def submit_share(self, job_id, worker_name, session, extranonce1_bin, extranonce2, ntime, nonce, difficulty, ip=False): '''Check parameters and finalize block template. If it leads to valid block candidate, asynchronously submits the block back to the bitcoin network. - extranonce1_bin is binary. No checks performed, it should be from session data - job_id, extranonce2, ntime, nonce - in hex form sent by the client - difficulty - decimal number from session, again no checks performed - submitblock_callback - reference to method which receive result of submitblock() ''' # Check if extranonce2 looks correctly. extranonce2 is in hex form... if len(extranonce2) != self.extranonce2_size * 2: raise SubmitException("Incorrect size of extranonce2. Expected %d chars" % (self.extranonce2_size*2)) # Check for job job = self.get_job(job_id, worker_name, ip) if job == None: raise SubmitException("Job '%s' not found" % job_id) # Check if ntime looks correct if len(ntime) != 8: raise SubmitException("Incorrect size of ntime. Expected 8 chars") if not job.check_ntime(int(ntime, 16)): raise SubmitException("Ntime out of range") # Check nonce if len(nonce) != 8: raise SubmitException("Incorrect size of nonce. Expected 8 chars") # Check for duplicated submit if not job.register_submit(extranonce1_bin, extranonce2, ntime, nonce): log.info("Duplicate from %s, (%s %s %s %s)" % \ (worker_name, binascii.hexlify(extranonce1_bin), extranonce2, ntime, nonce)) raise SubmitException("Duplicate share") # Now let's do the hard work! # --------------------------- # 0. Some sugar extranonce2_bin = binascii.unhexlify(extranonce2) ntime_bin = binascii.unhexlify(ntime) nonce_bin = binascii.unhexlify(nonce) # 1. Build coinbase coinbase_bin = job.serialize_coinbase(extranonce1_bin, extranonce2_bin) coinbase_hash = util.doublesha(coinbase_bin) # 2. Calculate merkle root merkle_root_bin = job.merkletree.withFirst(coinbase_hash) merkle_root_int = util.uint256_from_str(merkle_root_bin) # 3. Serialize header with given merkle, ntime and nonce header_bin = job.serialize_header(merkle_root_int, ntime_bin, nonce_bin) # 4. Reverse header and compare it with target of the user hash_bin = algo.getPoWHash(''.join([ header_bin[i*4:i*4+4][::-1] for i in range(0, 20) ])) hash_int = util.uint256_from_str(hash_bin) scrypt_hash_hex = "%064x" % hash_int header_hex = binascii.hexlify(header_bin) if coindef.header() = True: header_hex = header_hex+"000000800000000000000000000000000000000000000000000000000000000000000000000000000000000080020000"
def submit_share(self, job_id, worker_name, session, extranonce1_bin, extranonce2, ntime, nonce, difficulty): '''Check parameters and finalize block template. If it leads to valid block candidate, asynchronously submits the block back to the bitcoin network. - extranonce1_bin is binary. No checks performed, it should be from session data - job_id, extranonce2, ntime, nonce - in hex form sent by the client - difficulty - decimal number from session, again no checks performed - submitblock_callback - reference to method which receive result of submitblock() ''' # Check if extranonce2 looks correctly. extranonce2 is in hex form... if len(extranonce2) != self.extranonce2_size * 2: raise SubmitException("Incorrect size of extranonce2. Expected %d chars" % (self.extranonce2_size*2)) # Check for job job = self.get_job(job_id) if job == None: raise SubmitException("Job '%s' not found" % job_id) # Check if ntime looks correct if len(ntime) != 8: raise SubmitException("Incorrect size of ntime. Expected 8 chars") if not job.check_ntime(int(ntime, 16)): raise SubmitException("Ntime out of range") # Check nonce if len(nonce) != 8: raise SubmitException("Incorrect size of nonce. Expected 8 chars") # Check for duplicated submit if not job.register_submit(extranonce1_bin, extranonce2, ntime, nonce): log.info("Duplicate from %s, (%s %s %s %s)" % \ (worker_name, binascii.hexlify(extranonce1_bin), extranonce2, ntime, nonce)) raise SubmitException("Duplicate share") # Now let's do the hard work! # --------------------------- # 0. Some sugar extranonce2_bin = binascii.unhexlify(extranonce2) ntime_bin = binascii.unhexlify(ntime) nonce_bin = binascii.unhexlify(nonce) # 1. Build coinbase coinbase_bin = job.serialize_coinbase(extranonce1_bin, extranonce2_bin) coinbase_hash = util.doublesha(coinbase_bin) # 2. Calculate merkle root merkle_root_bin = job.merkletree.withFirst(coinbase_hash) merkle_root_int = util.uint256_from_str(merkle_root_bin) # 3. Serialize header with given merkle, ntime and nonce header_bin = job.serialize_header(merkle_root_int, ntime_bin, nonce_bin) # 4. Reverse header and compare it with target of the user if settings.COINDAEMON_ALGO == 'scrypt': hash_bin = ltc_scrypt.getPoWHash(''.join([ header_bin[i*4:i*4+4][::-1] for i in range(0, 20) ])) elif settings.COINDAEMON_ALGO == 'scrypt-jane': hash_bin = yac_scrypt.getPoWHash(''.join([ header_bin[i*4:i*4+4][::-1] for i in range(0, 20) ]), int(ntime, 16)) elif settings.COINDAEMON_ALGO == 'quark': hash_bin = quark_hash.getPoWHash(''.join([ header_bin[i*4:i*4+4][::-1] for i in range(0, 20) ])) else: hash_bin = util.doublesha(''.join([ header_bin[i*4:i*4+4][::-1] for i in range(0, 20) ])) hash_int = util.uint256_from_str(hash_bin) scrypt_hash_hex = "%064x" % hash_int header_hex = binascii.hexlify(header_bin) if settings.COINDAEMON_ALGO == 'scrypt' or settings.COINDAEMON_ALGO == 'scrypt-jane': header_hex = header_hex+"000000800000000000000000000000000000000000000000000000000000000000000000000000000000000080020000" elif settings.COINDAEMON_ALGO == 'quark': header_hex = header_hex+"000000800000000000000000000000000000000000000000000000000000000000000000000000000000000080020000" else: pass target_user = self.diff_to_target(difficulty) if hash_int > target_user: 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) #if settings.COINDAEMON_ALGO == 'scrypt' or settings.COINDAEMON_ALGO == 'sha256d': # if settings.COINDAEMON_Reward == 'POW': 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') #else: block_hash_hex = hash_bin[::-1].encode('hex_codec') #else: block_hash_hex = 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.exception("FINAL JOB VALIDATION FAILED!(Try enabling/disabling tx messages)") # 7. Submit block to the network serialized = binascii.hexlify(job.serialize()) #just try both block hash and scrypt hash when checking for block creation on_submit = self.bitcoin_rpc.submitblock(serialized, block_hash_hex, scrypt_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)
def submit_share(self, job_id, worker_name, session, extranonce1_bin, extranonce2, ntime, nonce, difficulty): '''Check parameters and finalize block template. If it leads to valid block candidate, asynchronously submits the block back to the bitcoin network. - extranonce1_bin is binary. No checks performed, it should be from session data - job_id, extranonce2, ntime, nonce - in hex form sent by the client - difficulty - decimal number from session, again no checks performed - submitblock_callback - reference to method which receive result of submitblock() ''' # Check if extranonce2 looks correctly. extranonce2 is in hex form... if len(extranonce2) != self.extranonce2_size * 2: raise SubmitException("Incorrect size of extranonce2. Expected %d chars" % (self.extranonce2_size*2)) # Check for job job = self.get_job(job_id) if job == None: raise SubmitException("Job '%s' not found" % job_id) # Check if ntime looks correct if len(ntime) != 8: raise SubmitException("Incorrect size of ntime. Expected 8 chars") if not job.check_ntime(int(ntime, 16)): raise SubmitException("Ntime out of range") # Check nonce if len(nonce) != 8: raise SubmitException("Incorrect size of nonce. Expected 8 chars") # Check for duplicated submit if not job.register_submit(extranonce1_bin, extranonce2, ntime, nonce): log.info("Duplicate from %s, (%s %s %s %s)" % \ (worker_name, binascii.hexlify(extranonce1_bin), extranonce2, ntime, nonce)) raise SubmitException("Duplicate share") # Now let's do the hard work! # --------------------------- # 0. Some sugar extranonce2_bin = binascii.unhexlify(extranonce2) ntime_bin = binascii.unhexlify(ntime) nonce_bin = binascii.unhexlify(nonce) # 1. Build coinbase coinbase_bin = job.serialize_coinbase(extranonce1_bin, extranonce2_bin) coinbase_hash = util.doublesha(coinbase_bin) # 2. Calculate merkle root merkle_root_bin = job.merkletree.withFirst(coinbase_hash) merkle_root_int = util.uint256_from_str(merkle_root_bin) # 3. Serialize header with given merkle, ntime and nonce header_bin = job.serialize_header(merkle_root_int, ntime_bin, nonce_bin) # 4. Reverse header and compare it with target of the user hash_bin = util.scrypt(''.join([ header_bin[i*4:i*4+4][::-1] for i in range(0, 20) ])) hash_int = util.uint256_from_str(hash_bin) block_hash_hex = "%064x" % hash_int header_hex = binascii.hexlify(header_bin) target_user = self.diff_to_target(difficulty) if hash_int > 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" % block_hash_hex) # 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) return (header_hex, block_hash_hex, share_diff, on_submit) return (header_hex, block_hash_hex, share_diff, None)
def submit_share(self, job_id, worker_name, session, extranonce1_bin, extranonce2, ntime, nonce, difficulty, ip, submit_time): '''Check parameters and finalize block template. If it leads to valid block candidate, asynchronously submits the block back to the bitcoin network. - extranonce1_bin is binary. No checks performed, it should be from session data - job_id, extranonce2, ntime, nonce - in hex form sent by the client - difficulty - decimal number from session, again no checks performed - submitblock_callback - reference to method which receive result of submitblock() ''' # Check if extranonce2 looks correctly. extranonce2 is in hex form... if len(extranonce2) != self.extranonce2_size * 2: raise SubmitException( "Incorrect size of extranonce2. Expected %d chars" % (self.extranonce2_size * 2)) # Check for job job = self.get_job(job_id) if job == None: raise SubmitException("Job '%s' not found" % job_id) # Check if ntime looks correct if len(ntime) != 8: raise SubmitException("Incorrect size of ntime. Expected 8 chars") if not job.check_ntime(int(ntime, 16)): raise SubmitException("Ntime out of range") # Check nonce if len(nonce) != 8: raise SubmitException("Incorrect size of nonce. Expected 8 chars") # Check for duplicated submit if not job.register_submit(extranonce1_bin, extranonce2, ntime, nonce): log.info("Duplicate from %s, (%s %s %s %s)" % \ (worker_name, binascii.hexlify(extranonce1_bin), extranonce2, ntime, nonce)) raise SubmitException("Duplicate share") # Now let's do the hard work! # --------------------------- # 0. Some sugar extranonce2_bin = binascii.unhexlify(extranonce2) ntime_bin = binascii.unhexlify(ntime) nonce_bin = binascii.unhexlify(nonce) # 1. Build coinbase coinbase_bin = job.serialize_coinbase(extranonce1_bin, extranonce2_bin) coinbase_hash = util.doublesha(coinbase_bin) # 2. Calculate merkle root merkle_root_bin = job.merkletree.withFirst(coinbase_hash) merkle_root_int = util.uint256_from_str(merkle_root_bin) # 3. Serialize header with given merkle, ntime and nonce header_bin = job.serialize_header(merkle_root_int, ntime_bin, nonce_bin) # 4. Reverse header and compare it with target of the user if settings.DAEMON_ALGO == 'scrypt': hash_bin = ltc_scrypt.getPoWHash(header_bin) elif settings.DAEMON_ALGO == 'yescrypt': hash_bin = yescrypt_hash.getPoWHash(header_bin) elif settings.DAEMON_ALGO == 'qubit': hash_bin = qubit_hash.getPoWHash(header_bin) else: hash_bin = util.doublesha(header_bin) hash_int = util.uint256_from_str(hash_bin) pow_hash_hex = "%064x" % hash_int header_hex = binascii.hexlify(header_bin) target_user = self.diff_to_target(difficulty) if hash_int > target_user: raise SubmitException("Share is above target") # Mostly for debugging purposes target_info = self.diff_to_target(1000) if hash_int <= target_info: log.info("Yay, share with diff above 1000") # Algebra tells us the diff_to_target is the same as hash_to_diff share_diff = float(self.diff_to_target(hash_int)) on_submit = None aux_submit = None block_hash_bin = util.doublesha(header_bin) block_hash_hex = block_hash_bin[::-1].encode('hex_codec') if hash_int <= job.target: log.info( "MAINNET BLOCK CANDIDATE! %s diff(%f/%f)" % (block_hash_hex, share_diff, self.diff_to_target(job.target))) job.finalize(merkle_root_int, extranonce1_bin, extranonce2_bin, int(ntime, 16), int(nonce, 16)) if not job.is_valid(): log.exception("FINAL JOB VALIDATION FAILED!") serialized = binascii.hexlify(job.serialize()) if settings.SOLUTION_BLOCK_HASH: on_submit = self.bitcoin_rpc.submitblock( serialized, block_hash_hex) else: on_submit = self.bitcoin_rpc.submitblock( serialized, pow_hash_hex) '''if on_submit: self.update_block()''' # Check auxiliary merged chains for chain in range(len(job.auxs)): if hash_int <= job.aux_targets[chain]: log.info("FOUND MERGED BLOCK! %s diff(%f/%f)" % (job.auxs[chain]['hash'], share_diff, self.diff_to_target(job.aux_targets[chain]))) coinbase_hex = binascii.hexlify(coinbase_bin) branch_count = job.merkletree.branchCount() branch_hex = job.merkletree.branchHex() merkle_link = util.calculate_merkle_link( job.merkle_hashes, job.tree[job.auxs[chain]['chainid']]) submission = coinbase_hex + block_hash_hex + branch_count + branch_hex + '00000000' + merkle_link + header_hex aux_submit = self.aux_rpc.conns[chain].getauxblock( job.auxs[chain]['hash'], submission) aux_submit.addCallback( Interfaces.share_manager.on_submit_aux_block, worker_name, header_hex, job.auxs[chain]['hash'], submit_time, ip, share_diff) '''if aux_submit: self.update_auxs()''' if settings.SOLUTION_BLOCK_HASH: return (header_hex, block_hash_hex, share_diff, on_submit) else: return (header_hex, pow_hash_hex, share_diff, on_submit)
def submit_share(self, job_id, worker_name, extranonce1_bin, extranonce2, ntime, nonce, difficulty): '''Check parameters and finalize block template. If it leads to valid block candidate, asynchronously submits the block back to the bitcoin network. - extranonce1_bin is binary. No checks performed, it should be from session data - job_id, extranonce2, ntime, nonce - in hex form sent by the client - difficulty - decimal number from session, again no checks performed - submitblock_callback - reference to method which receive result of submitblock() ''' # Check if extranonce2 looks correctly. extranonce2 is in hex form... if len(extranonce2) != self.extranonce2_size * 2: raise SubmitException("Incorrect size of extranonce2. Expected %d chars" % (self.extranonce2_size*2)) # Check for job job = self.get_job(job_id) if job == None: raise SubmitException("Job '%s' not found" % job_id) # Check if ntime looks correct if len(ntime) != 8: raise SubmitException("Incorrect size of ntime. Expected 8 chars") if not job.check_ntime(int(ntime, 16)): raise SubmitException("Ntime out of range") # Check nonce if len(nonce) != 8: raise SubmitException("Incorrect size of nonce. Expected 8 chars") # Check for duplicated submit if not job.register_submit(extranonce1_bin, extranonce2, ntime, nonce): log.info("Duplicate from %s, (%s %s %s %s)" % \ (worker_name, binascii.hexlify(extranonce1_bin), extranonce2, ntime, nonce)) raise SubmitException("Duplicate share") # Now let's do the hard work! # --------------------------- # 0. Some sugar extranonce2_bin = binascii.unhexlify(extranonce2) ntime_bin = binascii.unhexlify(ntime) nonce_bin = binascii.unhexlify(nonce) # 1. Build coinbase coinbase_bin = job.serialize_coinbase(extranonce1_bin, extranonce2_bin) coinbase_hash = util.doublesha(coinbase_bin) # 2. Calculate merkle root merkle_root_bin = job.merkletree.withFirst(coinbase_hash) merkle_root_int = util.uint256_from_str(merkle_root_bin) # 3. Serialize header with given merkle, ntime and nonce header_bin = job.serialize_header(merkle_root_int, ntime_bin, nonce_bin) # 4. Reverse header and compare it with target of the user hash_bin = util.doublesha(''.join([ header_bin[i*4:i*4+4][::-1] for i in range(0, 20) ])) hash_int = util.uint256_from_str(hash_bin) block_hash_hex = "%064x" % hash_int header_hex = binascii.hexlify(header_bin) target_user = self.diff_to_target(difficulty) if hash_int > target_user: # For testing purposes ONLY if not config.ACCEPT_SHARES_ABOVE_TARGET: raise SubmitException("Share is above target") # 5. Compare hash with target of the network if hash_int <= job.target or \ (nonce == config.ACCEPT_INVALID_BLOCK__NONCE): # Yay! It is block candidate! log.info("We found a block candidate! %s" % block_hash_hex) # 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. Get block value for statistical purposes block_value = job.get_value() # 8. Submit block to the network serialized = binascii.hexlify(job.serialize()) on_submit = self.bitcoin_rpc.submitblock(serialized) return (header_hex, block_hash_hex, block_value, on_submit) return (header_hex, block_hash_hex, None, None)
def submit_share(self, job_id, worker_name, session, extranonce1_bin, extranonce2, ntime, nonce, difficulty): '''Check parameters and finalize block template. If it leads to valid block candidate, asynchronously submits the block back to the bitcoin network. - extranonce1_bin is binary. No checks performed, it should be from session data - job_id, extranonce2, ntime, nonce - in hex form sent by the client - difficulty - decimal number from session, again no checks performed - submitblock_callback - reference to method which receive result of submitblock() ''' # Check if extranonce2 looks correctly. extranonce2 is in hex form... if len(extranonce2) != self.extranonce2_size * 2: raise SubmitException("Incorrect size of extranonce2. Expected %d chars" % (self.extranonce2_size*2)) # Check for job job = self.get_job(job_id) if job == None: raise SubmitException("Job '%s' not found" % job_id) # Check if ntime looks correct if len(ntime) != 8: raise SubmitException("Incorrect size of ntime. Expected 8 chars") if not job.check_ntime(int(ntime, 16)): raise SubmitException("Ntime out of range") # Check nonce if len(nonce) != 8: raise SubmitException("Incorrect size of nonce. Expected 8 chars") # Check for duplicated submit if not job.register_submit(extranonce1_bin, extranonce2, ntime, nonce): log.info("Duplicate from %s, (%s %s %s %s)" % \ (worker_name, binascii.hexlify(extranonce1_bin), extranonce2, ntime, nonce)) raise SubmitException("Duplicate share") # Now let's do the hard work! # --------------------------- # 0. Some sugar extranonce2_bin = binascii.unhexlify(extranonce2) ntime_bin = binascii.unhexlify(ntime) nonce_bin = binascii.unhexlify(nonce) # 1. Build coinbase coinbase_bin = job.serialize_coinbase(extranonce1_bin, extranonce2_bin) coinbase_hash = util.doublesha(coinbase_bin) # 2. Calculate merkle root merkle_root_bin = job.merkletree.withFirst(coinbase_hash) merkle_root_int = util.uint256_from_str(merkle_root_bin) # 3. Serialize header with given merkle, ntime and nonce header_bin = job.serialize_header(merkle_root_int, ntime_bin, nonce_bin) # 4. Reverse header and compare it with target of the user if settings.COINDAEMON_ALGO == 'scrypt': hash_bin = ltc_scrypt.getPoWHash(''.join([ header_bin[i*4:i*4+4][::-1] for i in range(0, 20) ])) elif settings.COINDAEMON_ALGO == 'scrypt-jane': hash_bin = yac_scrypt.getPoWHash(''.join([ header_bin[i*4:i*4+4][::-1] for i in range(0, 20) ]), int(ntime, 16)) elif settings.COINDAEMON_ALGO == 'quark': hash_bin = quark_hash.getPoWHash(''.join([ header_bin[i*4:i*4+4][::-1] for i in range(0, 20) ])) else: hash_bin = util.doublesha(''.join([ header_bin[i*4:i*4+4][::-1] for i in range(0, 20) ])) hash_int = util.uint256_from_str(hash_bin) scrypt_hash_hex = "%064x" % hash_int header_hex = binascii.hexlify(header_bin) if settings.COINDAEMON_ALGO == 'scrypt' or settings.COINDAEMON_ALGO == 'scrypt-jane': header_hex = header_hex+"000000800000000000000000000000000000000000000000000000000000000000000000000000000000000080020000" elif settings.COINDAEMON_ALGO == 'quark': header_hex = header_hex+"000000800000000000000000000000000000000000000000000000000000000000000000000000000000000080020000" else: pass target_user = self.diff_to_target(difficulty) if hash_int > target_user: 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) #if settings.COINDAEMON_ALGO == 'scrypt' or settings.COINDAEMON_ALGO == 'sha256d': # if settings.COINDAEMON_Reward == 'POW': 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') #else: block_hash_hex = hash_bin[::-1].encode('hex_codec') #else: block_hash_hex = 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.exception("FINAL JOB VALIDATION FAILED!(Try enabling/disabling tx messages)") # 7. Submit block to the network serialized = binascii.hexlify(job.serialize()) 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() 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)
def submit_share(self, job_id, worker_name, session, extranonce1_bin, extranonce2, ntime, nonce, difficulty, ip=False): '''Check parameters and finalize block template. If it leads to valid block candidate, asynchronously submits the block back to the bitcoin network. - extranonce1_bin is binary. No checks performed, it should be from session data - job_id, extranonce2, ntime, nonce - in hex form sent by the client - difficulty - decimal number from session - submitblock_callback - reference to method which receive result of submitblock() - difficulty is checked to see if its lower than the vardiff minimum target or pool target from conf/config.py and if it is the share is rejected due to it not meeting the requirements for a share ''' if settings.VARIABLE_DIFF == True: # Share Diff Should never be 0 if difficulty < settings.VDIFF_MIN_TARGET: log.exception( "Worker %s @ IP: %s seems to be submitting Fake Shares" % (worker_name, ip)) raise SubmitException( "Diff is %s Share Rejected Reporting to Admin" % (difficulty)) else: if difficulty < settings.POOL_TARGET: log.exception( "Worker %s @ IP: %s seems to be submitting Fake Shares" % (worker_name, ip)) raise SubmitException( "Diff is %s Share Rejected Reporting to Admin" % (difficulty)) # Check if extranonce2 looks correctly. extranonce2 is in hex form... if len(extranonce2) != self.extranonce2_size * 2: raise SubmitException( "Incorrect size of extranonce2. Expected %d chars" % (self.extranonce2_size * 2)) # normalize the case to prevent duplication of valid shares by the client ntime = ntime.lower() nonce = nonce.lower() extranonce2 = extranonce2.lower() # Check for job job = self.get_job(job_id, worker_name, ip) if job == None: raise SubmitException("Job '%s' not found" % job_id) # Check if ntime looks correct if len(ntime) != 8: raise SubmitException("Incorrect size of ntime. Expected 8 chars") if not job.check_ntime(int(ntime, 16)): raise SubmitException("Ntime out of range") # Check nonce if len(nonce) != 8: raise SubmitException("Incorrect size of nonce. Expected 8 chars") # 0. Some sugar extranonce2_bin = binascii.unhexlify(extranonce2) ntime_bin = binascii.unhexlify(ntime) nonce_bin = binascii.unhexlify(nonce) # Check for duplicated submit if not job.register_submit(extranonce1_bin, extranonce2_bin, ntime_bin, nonce_bin): log.info("Duplicate from %s, (%s %s %s %s)" % \ (worker_name, binascii.hexlify(extranonce1_bin), extranonce2, ntime, nonce)) raise SubmitException("Duplicate share") # Now let's do the hard work! # --------------------------- # 1. Build coinbase coinbase_bin = job.serialize_coinbase(extranonce1_bin, extranonce2_bin) coinbase_hash = util.doublesha(coinbase_bin) # 2. Calculate merkle root merkle_root_bin = job.merkletree.withFirst(coinbase_hash) merkle_root_int = util.uint256_from_str(merkle_root_bin) # 3. Serialize header with given merkle, ntime and nonce header_bin = job.serialize_header(merkle_root_int, ntime_bin, nonce_bin) # 4. Reverse header and compare it with target of the user hash_bin = algolib.getPoWHash(''.join( [header_bin[i * 4:i * 4 + 4][::-1] for i in range(0, 20)])) hash_int = util.uint256_from_str(hash_bin) scrypt_hash_hex = "%064x" % hash_int header_hex = binascii.hexlify(header_bin) if settings.CUSTOM_HEADER != None: header_hex = header_hex + settings.CUSTOM_HEADER target_user = self.diff_to_target(difficulty) if hash_int > target_user: 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) 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.exception( "FINAL JOB VALIDATION FAILED!(Try enabling/disabling tx messages)" ) # 7. Submit block to the network serialized = binascii.hexlify(job.serialize()) on_submit = self.bitcoin_rpc.submitblock(serialized, block_hash_hex, scrypt_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: 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)
def submit_share(self, job_id, worker_name, session, extranonce1_bin, extranonce2, ntime, nonce, difficulty, ip, submit_time): '''Check parameters and finalize block template. If it leads to valid block candidate, asynchronously submits the block back to the bitcoin network. - extranonce1_bin is binary. No checks performed, it should be from session data - job_id, extranonce2, ntime, nonce - in hex form sent by the client - difficulty - decimal number from session, again no checks performed - submitblock_callback - reference to method which receive result of submitblock() ''' # Check if extranonce2 looks correctly. extranonce2 is in hex form... if len(extranonce2) != self.extranonce2_size * 2: raise SubmitException("Incorrect size of extranonce2. Expected %d chars" % (self.extranonce2_size*2)) # Check for job job = self.get_job(job_id) if job == None: raise SubmitException("Job '%s' not found" % job_id) # Check if ntime looks correct if len(ntime) != 8: raise SubmitException("Incorrect size of ntime. Expected 8 chars") if not job.check_ntime(int(ntime, 16)): raise SubmitException("Ntime out of range") # Check nonce if len(nonce) != 8: raise SubmitException("Incorrect size of nonce. Expected 8 chars") # Check for duplicated submit if not job.register_submit(extranonce1_bin, extranonce2, ntime, nonce): log.info("Duplicate from %s, (%s %s %s %s)" % \ (worker_name, binascii.hexlify(extranonce1_bin), extranonce2, ntime, nonce)) raise SubmitException("Duplicate share") # Now let's do the hard work! # --------------------------- # 0. Some sugar extranonce2_bin = binascii.unhexlify(extranonce2) ntime_bin = binascii.unhexlify(ntime) nonce_bin = binascii.unhexlify(nonce) # 1. Build coinbase coinbase_bin = job.serialize_coinbase(extranonce1_bin, extranonce2_bin) coinbase_hash = util.doublesha(coinbase_bin) # 2. Calculate merkle root merkle_root_bin = job.merkletree.withFirst(coinbase_hash) merkle_root_int = util.uint256_from_str(merkle_root_bin) # 3. Serialize header with given merkle, ntime and nonce header_bin = job.serialize_header(merkle_root_int, ntime_bin, nonce_bin) # 4. Reverse header and compare it with target of the user if settings.DAEMON_ALGO == 'scrypt': hash_bin = ltc_scrypt.getPoWHash(header_bin) elif settings.DAEMON_ALGO == 'yescrypt': hash_bin = yescrypt_hash.getPoWHash(header_bin) elif settings.DAEMON_ALGO == 'qubit': hash_bin = qubit_hash.getPoWHash(header_bin) else: hash_bin = util.doublesha(header_bin) hash_int = util.uint256_from_str(hash_bin) pow_hash_hex = "%064x" % hash_int header_hex = binascii.hexlify(header_bin) target_user = self.diff_to_target(difficulty) if hash_int > target_user: raise SubmitException("Share is above target") # Mostly for debugging purposes target_info = self.diff_to_target(1000) if hash_int <= target_info: log.info("Yay, share with diff above 1000") # Algebra tells us the diff_to_target is the same as hash_to_diff share_diff = float(self.diff_to_target(hash_int)) on_submit = None aux_submit = None block_hash_bin = util.doublesha(header_bin) block_hash_hex = block_hash_bin[::-1].encode('hex_codec') if hash_int <= job.target: log.info("MAINNET BLOCK CANDIDATE! %s diff(%f/%f)" % (block_hash_hex, share_diff, self.diff_to_target(job.target))) job.finalize(merkle_root_int, extranonce1_bin, extranonce2_bin, int(ntime, 16), int(nonce, 16)) if not job.is_valid(): log.exception("FINAL JOB VALIDATION FAILED!") serialized = binascii.hexlify(job.serialize()) if settings.SOLUTION_BLOCK_HASH: on_submit = self.bitcoin_rpc.submitblock(serialized, block_hash_hex) else: on_submit = self.bitcoin_rpc.submitblock(serialized, pow_hash_hex) '''if on_submit: self.update_block()''' # Check auxiliary merged chains for chain in range(len(job.auxs)): if hash_int <= job.aux_targets[chain]: log.info("FOUND MERGED BLOCK! %s diff(%f/%f)" % (job.auxs[chain]['hash'], share_diff, self.diff_to_target(job.aux_targets[chain]))) coinbase_hex = binascii.hexlify(coinbase_bin) branch_count = job.merkletree.branchCount() branch_hex = job.merkletree.branchHex() merkle_link = util.calculate_merkle_link(job.merkle_hashes, job.tree[job.auxs[chain]['chainid']]) submission = coinbase_hex + block_hash_hex + branch_count + branch_hex + '00000000' + merkle_link + header_hex; aux_submit = self.aux_rpc.conns[chain].getauxblock(job.auxs[chain]['hash'], submission) aux_submit.addCallback(Interfaces.share_manager.on_submit_aux_block, worker_name, header_hex, job.auxs[chain]['hash'], submit_time, ip, share_diff) '''if aux_submit: self.update_auxs()''' if settings.SOLUTION_BLOCK_HASH: return (header_hex, block_hash_hex, share_diff, on_submit) else: return (header_hex, pow_hash_hex, share_diff, on_submit)