def verify(self, extranonce2, ntime, nonce): return coinbase = self.coinb1 + self.extranonce1 + extranonce2 + self.coinb2 coinbase_hash_bin = doublesha(binascii.unhexlify(coinbase)) merkle_root = build_merkle_root(self.merkle_branch, coinbase_hash_bin) merkle_root = ser_uint256_be(uint256_from_str(merkle_root)) preheader = self.version + self.prevhash + merkle_root.encode("hex") + ntime + self.nbits preheader_bin = preheader.decode("hex") preheader_bin = ''.join([preheader_bin[i*4:i*4+4][::-1] for i in range(0,19)]) hash_bin = doublesha(preheader_bin + nonce.decode("hex")[::-1]) print hash_bin.encode("hex") val = struct.unpack("<I", hash_bin[-4:])[0] assert val < THRESH, (val, THRESH)
def _target(self, job_id, extranonce2, ntime, preheader_bin): try: start = time.time() first_sha = hashlib.sha256(preheader_bin) if sys.maxint > 2**32: max_nonce = 2**32 else: max_nonce = 2**31 - 1 i = 0 while i < max_nonce: if i % 100000 == 0: print i, "%.1f kh/s" % (i * .001 / (time.time() - start + .001)) if self._quit: print "QUITTING WORKER" break nonce_bin = struct.pack(">I", i) if TEST: nonce_bin = "b2957c02".decode("hex")[::-1] # header_bin = preheader_bin + nonce_bin # hash_bin = doublesha(header_bin) # assert hash_bin == finish_dsha(first_sha, nonce_bin) hash_bin = finish_dsha(first_sha, nonce_bin) val = struct.unpack("<I", hash_bin[-4:])[0] if val < THRESH: nonce = nonce_bin[::-1].encode("hex") print nonce, extranonce2, ntime print hash_bin.encode("hex") hash_int = uint256_from_str(hash_bin) block_hash_hex = "%064x" % hash_int print block_hash_hex self._cl.submit(job_id, extranonce2, ntime, nonce) break elif val < THRESH*10: print "almost: %d (<%d)" % (val, THRESH) i += 1 # elif i == 0: # print hash_bin.encode("hex") self._done_ev.set() except: traceback.print_exc() os._exit(1)
def _target(self, job_id, extranonce2, ntime, preheader_bin): try: start = time.time() first_sha = hashlib.sha256(preheader_bin) if sys.maxint > 2**32: max_nonce = 2**32 else: max_nonce = 2**31 - 1 i = 0 while i < max_nonce: if i % 100000 == 0: print i, "%.1f kh/s" % (i * .001 / (time.time() - start + .001)) if self._quit: print "QUITTING WORKER" break nonce_bin = struct.pack(">I", i) if TEST: nonce_bin = "b2957c02".decode("hex")[::-1] # header_bin = preheader_bin + nonce_bin # hash_bin = doublesha(header_bin) # assert hash_bin == finish_dsha(first_sha, nonce_bin) hash_bin = finish_dsha(first_sha, nonce_bin) val = struct.unpack("<I", hash_bin[-4:])[0] if val < THRESH: nonce = nonce_bin[::-1].encode("hex") print nonce, extranonce2, ntime print hash_bin.encode("hex") hash_int = uint256_from_str(hash_bin) block_hash_hex = "%064x" % hash_int print block_hash_hex self._cl.submit(job_id, extranonce2, ntime, nonce) break elif val < THRESH * 10: print "almost: %d (<%d)" % (val, THRESH) i += 1 # elif i == 0: # print hash_bin.encode("hex") self._done_ev.set() except: traceback.print_exc() os._exit(1)
def verify(self, extranonce2, ntime, nonce): return coinbase = self.coinb1 + self.extranonce1 + extranonce2 + self.coinb2 coinbase_hash_bin = doublesha(binascii.unhexlify(coinbase)) merkle_root = build_merkle_root(self.merkle_branch, coinbase_hash_bin) merkle_root = ser_uint256_be(uint256_from_str(merkle_root)) preheader = self.version + self.prevhash + merkle_root.encode( "hex") + ntime + self.nbits preheader_bin = preheader.decode("hex") preheader_bin = ''.join( [preheader_bin[i * 4:i * 4 + 4][::-1] for i in range(0, 19)]) hash_bin = doublesha(preheader_bin + nonce.decode("hex")[::-1]) print hash_bin.encode("hex") val = struct.unpack("<I", hash_bin[-4:])[0] assert val < THRESH, (val, THRESH)
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, 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=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 ''' log.debug("Session: %s" % session) # Share Difficulty should never be 0 or below if difficulty <= 0: 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)) # Check for job job = self.get_job(job_id, worker_name, ip) if job == None: if settings.REJECT_STALE_SHARES: # Reject stale share raise SubmitException("Job '%s' not found" % job_id) else: # Accept stale share but do not continue checking, return a bunch of nothingness log.info("Accepted Stale Share from %s, (%s %s %s %s)" % \ (worker_name, binascii.hexlify(extranonce1_bin), extranonce2, ntime, nonce)) return (None, None, None, None, None, None) # Check if ntime looks correct check_result, error_message = util.check_ntime(ntime) if not check_result: raise SubmitException(error_message) if not job.check_ntime(int(ntime, 16), getattr(settings, 'NTIME_AGE')): raise SubmitException("Ntime out of range") # Check nonce check_result, error_message = util.check_nonce(nonce) if not check_result: raise SubmitException(error_message) # 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 = util.get_ntime_bin(ntime) nonce_bin = util.get_nonce_bin(nonce) target_user = self.diff_to_target(difficulty) target_info = self.diff_to_target(100000) # 1. Build coinbase coinbase_bin = job.serialize_coinbase(extranonce1_bin, extranonce2_bin) coinbase_hash = util.get_coinbase_hash(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. Convert header into hex according to hash algorythim block_hash = util.get_hash_hex(header_bin, ntime, nonce) # 5a Compare it with target of the user check_result, message = util.check_header_target( block_hash['int'], target_user) if not check_result: log.debug( "Oops, somthing is wrong: target_user=%s, difficulty=%s, share_diff=%s" % (target_user, difficulty, int(self.diff_to_target(block_hash['int'])))) raise SubmitException("%s. Hash: %s" % (message, block_hash['hex'])) # Mostly for debugging purposes, just a celebratory message that's being carried over from older versions check_result, message = util.check_above_yay_target( block_hash['int'], target_info) if check_result: log.info(message) # Algebra tells us the diff_to_target is the same as hash_to_diff if settings.VDIFF_FLOAT: share_diff = float(self.diff_to_target(block_hash['int'])) else: share_diff = int(self.diff_to_target(block_hash['int'])) log.debug("share_diff: %s" % share_diff) log.debug("job.target: %s" % job.target) log.debug("block_hash_int: %s" % block_hash['int']) # 6. Compare hash with target of the network if util.is_block_candidate(block_hash['int'], job.target): # Yay! It is block candidate! log.info("We found a block candidate! for %i: %s | %s" % (job.height, block_hash['hex'], block_hash['check_hex'])) # 7. 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(difficulty): # Should not happen log.exception( "FINAL JOB VALIDATION FAILED!(Try enabling/disabling tx messages)" ) # 8. Submit block to the network serialized = binascii.hexlify(job.serialize()) on_submit = self.bitcoin_rpc.submitblock(serialized, block_hash['check_hex'], block_hash['hex']) if on_submit: self.update_block() return (block_hash['header_hex'], block_hash['solution_hex'], share_diff, job.prevhash_hex, job.height, on_submit) # Not a potential Block return (block_hash['header_hex'], block_hash['solution_hex'], share_diff, job.prevhash_hex, job.height, 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, 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, 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, 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, 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()) 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 run(self): difficulty = 1 while True: s = self.f.readline() if not s: break if TEST: s = """{"params": ["bf", "4d16b6f85af6e2198f44ae2a6de67f78487ae5611b77c6c0440b921e00000000", "01000000010000000000000000000000000000000000000000000000000000000000000000ffffffff20020862062f503253482f04b8864e5008", "072f736c7573682f000000000100f2052a010000001976a914d23fcdf86f7e756a64a7a9688ef9903327048ed988ac00000000", [], "00000002", "1c2ac4af", "504e86b9", false], "id": null, "method": "mining.notify"}""" extranonce1 = "08000002" s = s.strip() assert s d = simplejson.loads(s) # if d.get('method', None) == "mining.notify" and self.done: # continue print d if d.get('error', None): raise Exception() if d['id'] == 1 and 'method' not in d: subscription, extranonce1, extranonce2_size = d['result'] elif d.get('method', None) == "mining.set_difficulty": difficulty = d['params'][0] elif d.get('method', None) == "mining.notify": print "stopping worker" self.w.stop() print "stopped" params, clean_jobs = d['params'][:-1], d['params'][:-1] j = JobInfo(extranonce1, *params) self.jobs[j.id] = j extranonce2 = ((int(time.time()) << 16) + os.getpid()) & 0xffffffff extranonce2 = struct.pack(">I", extranonce2).encode("hex") if TEST: extranonce2 = "00000001" print "extranonce2 = %s" % extranonce2 coinbase = j.coinb1 + extranonce1 + extranonce2 + j.coinb2 coinbase_hash_bin = doublesha(binascii.unhexlify(coinbase)) merkle_root = build_merkle_root(j.merkle_branch, coinbase_hash_bin) merkle_root = ser_uint256_be(uint256_from_str(merkle_root)) # ntime = "504e86ed" ntime = j.ntime if TEST: ntime = "504e86ed" preheader = j.version + j.prevhash + merkle_root.encode("hex") + ntime + j.nbits preheader_bin = preheader.decode("hex") preheader_bin = ''.join([preheader_bin[i*4:i*4+4][::-1] for i in range(0,19)]) self.w.start(difficulty, j.id, extranonce2, ntime, preheader_bin) else: assert d['id'] < self.mid
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 ''' log.debug("Session: %s" % session) # Share Difficulty should never be 0 or below if difficulty <= 0 : 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)) # Check for job job = self.get_job(job_id, worker_name, ip) if job == None: if settings.REJECT_STALE_SHARES: # Reject stale share raise SubmitException("Job '%s' not found" % job_id) else: # Accept stale share but do not continue checking, return a bunch of nothingness log.info("Accepted Stale Share from %s, (%s %s %s %s)" % \ (worker_name, binascii.hexlify(extranonce1_bin), extranonce2, ntime, nonce)) return (None, None, None, None, None, None) # Check if ntime looks correct check_result, error_message = util.check_ntime(ntime) if not check_result: raise SubmitException(error_message) if not job.check_ntime(int(ntime, 16), getattr(settings, 'NTIME_AGE')): raise SubmitException("Ntime out of range") # Check nonce check_result, error_message = util.check_nonce(nonce) if not check_result: raise SubmitException(error_message) # 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 = util.get_ntime_bin(ntime) nonce_bin = util.get_nonce_bin(nonce) target_user = self.diff_to_target(difficulty) target_info = self.diff_to_target(100000) # 1. Build coinbase coinbase_bin = job.serialize_coinbase(extranonce1_bin, extranonce2_bin) coinbase_hash = util.get_coinbase_hash(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. Convert header into hex according to hash algorythim block_hash = util.get_hash_hex(header_bin, ntime, nonce) # 5a Compare it with target of the user check_result, message = util.check_header_target(block_hash['int'], target_user) if not check_result: log.debug("Oops, somthing is wrong: target_user=%s, difficulty=%s, share_diff=%s" % (target_user, difficulty, int(self.diff_to_target(block_hash['int'])))) raise SubmitException("%s. Hash: %s" % (message, block_hash['hex'])) # Mostly for debugging purposes, just a celebratory message that's being carried over from older versions check_result, message = util.check_above_yay_target(block_hash['int'], target_info) if check_result: log.info(message) # Algebra tells us the diff_to_target is the same as hash_to_diff if settings.VDIFF_FLOAT: share_diff = float(self.diff_to_target(block_hash['int'])) else: share_diff = int(self.diff_to_target(block_hash['int'])) log.debug("share_diff: %s" % share_diff) log.debug("job.target: %s" % job.target) log.debug("block_hash_int: %s" % block_hash['int']) # 6. Compare hash with target of the network if util.is_block_candidate(block_hash['int'], job.target): # Yay! It is block candidate! log.info("We found a block candidate! for %i: %s | %s" % (job.height, block_hash['hex'], block_hash['check_hex'])) # 7. 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(difficulty): # Should not happen log.exception("FINAL JOB VALIDATION FAILED!(Try enabling/disabling tx messages)") # 8. Submit block to the network serialized = binascii.hexlify(job.serialize()) on_submit = self.bitcoin_rpc.submitblock(serialized, block_hash['check_hex'], block_hash['hex']) if on_submit: self.update_block() return (block_hash['header_hex'], block_hash['solution_hex'], share_diff, job.prevhash_hex, job.height, on_submit) # Not a potential Block return (block_hash['header_hex'], block_hash['solution_hex'], share_diff, job.prevhash_hex, job.height, None)
def _target(self, difficulty, job_id, extranonce2, ntime, preheader_bin): try: start = time.time() if sys.maxint > 2**32: max_nonce = 2**32 else: max_nonce = 2**31 - 1 i = 0 THRESH = 0x00010000 / difficulty # # THRESH = 1 << difficulty # # THRESH /= 4 # THRESH = 0x00002000 print "thresh:", THRESH hashes_per_thresh = (1 << 32) / THRESH if TEST: print preheader_bin.encode("hex") preheader_bin = "01000000f615f7ce3b4fc6b8f61e8f89aedb1d0852507650533a9e3b10b9bbcc30639f279fcaa86746e1ef52d3edb3c4ad8259920d509bd073605c9bf1d59983752a6b06b817bb4ea78e011d012d59d4".decode("hex")[:-4] while i < max_nonce: if TEST: i = 0x012d59d4 if self._quit: print "QUITTING WORKER" break if i and i % 10000 == 0: hashrate = i * 1.0 / (time.time() - start + .001) print i, "%.1f kh/s (%.1fs/share))" % (hashrate * 0.001, hashes_per_thresh / hashrate) nonce_bin = struct.pack(">I", i) header_bin = preheader_bin + nonce_bin hash_bin = scrypt.hash(header_bin, header_bin, 1024, 1, 1, 32) # print # print header_bin.encode("hex") # print hash_bin.encode("hex") val = struct.unpack("<I", hash_bin[-4:])[0] # print val # print if val < THRESH: nonce = nonce_bin[::-1].encode("hex") print nonce, extranonce2, ntime print hash_bin.encode("hex") hash_int = uint256_from_str(hash_bin) block_hash_hex = "%064x" % hash_int print block_hash_hex self._cl.submit(job_id, extranonce2, ntime, nonce) elif val < THRESH*10: print "almost: %d (<%d)" % (val, THRESH) i += 1 # elif i == 0: # print hash_bin.encode("hex") self._done_ev.set() except: traceback.print_exc() os._exit(1)
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 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, 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, 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 run(self): difficulty = 1 while True: s = self.f.readline() if not s: break if TEST: s = """{"params": ["bf", "4d16b6f85af6e2198f44ae2a6de67f78487ae5611b77c6c0440b921e00000000", "01000000010000000000000000000000000000000000000000000000000000000000000000ffffffff20020862062f503253482f04b8864e5008", "072f736c7573682f000000000100f2052a010000001976a914d23fcdf86f7e756a64a7a9688ef9903327048ed988ac00000000", [], "00000002", "1c2ac4af", "504e86b9", false], "id": null, "method": "mining.notify"}""" extranonce1 = "08000002" s = s.strip() assert s d = simplejson.loads(s) # if d.get('method', None) == "mining.notify" and self.done: # continue print d if d.get('error', None): raise Exception() if d['id'] == 1 and 'method' not in d: subscription, extranonce1, extranonce2_size = d['result'] elif d.get('method', None) == "mining.set_difficulty": difficulty = d['params'][0] elif d.get('method', None) == "mining.notify": print "stopping worker" self.w.stop() print "stopped" params, clean_jobs = d['params'][:-1], d['params'][:-1] j = JobInfo(extranonce1, *params) self.jobs[j.id] = j extranonce2 = ( (int(time.time()) << 16) + os.getpid()) & 0xffffffff extranonce2 = struct.pack(">I", extranonce2).encode("hex") if TEST: extranonce2 = "00000001" print "extranonce2 = %s" % extranonce2 coinbase = j.coinb1 + extranonce1 + extranonce2 + j.coinb2 coinbase_hash_bin = doublesha(binascii.unhexlify(coinbase)) merkle_root = build_merkle_root(j.merkle_branch, coinbase_hash_bin) merkle_root = ser_uint256_be(uint256_from_str(merkle_root)) # ntime = "504e86ed" ntime = j.ntime if TEST: ntime = "504e86ed" preheader = j.version + j.prevhash + merkle_root.encode( "hex") + ntime + j.nbits preheader_bin = preheader.decode("hex") preheader_bin = ''.join([ preheader_bin[i * 4:i * 4 + 4][::-1] for i in range(0, 19) ]) self.w.start(difficulty, j.id, extranonce2, ntime, preheader_bin) else: assert d['id'] < self.mid