def workable_block_header(self, template): """Takes a block template and creates a block header from it that is pre-processed into the SHA-256 message format. """ gen_tx, gen_tx_hash, _gen_tx_full_hash = self.generation_tx_for_template(template) tx_hashes = ( [gen_tx_hash] + [unhexlify(tx['txid'])[::-1] for tx in template['transactions']] ) merkle_root = tx_merkle_root(tx_hashes) merkle_root_words = bytearray() for word in chunks(merkle_root, 4): merkle_root_words += word[::-1] prev_block_hash_words = bytearray() for word in chunks(unhexlify(template['previousblockhash']), 4): # Prepend because template items are in RPC byte order. prev_block_hash_words[0:0] = word header_words = b''.join(( # Version pack(">L", template['version']), # Previous Block Hash prev_block_hash_words, # Merkle Root Hash merkle_root_words, # Time pack(">L", template['curtime']), # Target Bits unhexlify(template['bits']), # Nonce pack(">L", 0) # Will be replaced by nonce as iterated. )) return header_words, gen_tx
def workable_block_header(self, template): """Takes a block template and creates a block header from it that is pre-processed into the SHA-256 message format. """ gen_tx, gen_tx_hash, _gen_tx_full_hash = self.generation_tx_for_template( template) tx_hashes = ( [gen_tx_hash] + [unhexlify(tx['txid'])[::-1] for tx in template['transactions']]) merkle_root = tx_merkle_root(tx_hashes) merkle_root_words = bytearray() for word in chunks(merkle_root, 4): merkle_root_words += word[::-1] prev_block_hash_words = bytearray() for word in chunks(unhexlify(template['previousblockhash']), 4): # Prepend because template items are in RPC byte order. prev_block_hash_words[0:0] = word header_words = b''.join(( # Version pack(">L", template['version']), # Previous Block Hash prev_block_hash_words, # Merkle Root Hash merkle_root_words, # Time pack(">L", template['curtime']), # Target Bits unhexlify(template['bits']), # Nonce pack(">L", 0) # Will be replaced by nonce as iterated. )) return header_words, gen_tx
def set_difficulty(self, difficulty): self.difficulty = difficulty bits = '%08x' % bytereverse(difficulty) true_target = '%064x' % ( int(bits[2:], 16) * 2 ** (8 * (int(bits[:2], 16) - 3)),) true_target = ''.join(list(chunks(true_target, 2))[::-1]) self.true_target = unpack('<8I', unhexlify(true_target))
def submittable_block_header(self, result, nonce): header = bytearray() # Un-reverse the SHA-2 message words. for word in chunks(result.header, 4): header += word[::-1] header += pack('>3I', int(result.time), int(result.difficulty), int(nonce)) return header
def refresh_job(self, j): j.extranonce2 = self.increment_nonce(j.extranonce2) coinbase = j.coinbase1 + self.extranonce + j.extranonce2 + j.coinbase2 merkle_root = sha256(sha256(unhexlify(coinbase)).digest()).digest() for hash_ in j.merkle_branch: merkle_root = sha256( sha256(merkle_root + unhexlify(hash_)).digest()).digest() merkle_root_bak = ''.join(['%02x' % b for b in merkle_root]) merkle_root_reversed = b'' for word in chunks(merkle_root, 4): merkle_root_reversed += word[::-1] merkle_root = merkle_root_reversed.hex() j.block_header = ''.join( [j.version, j.prevhash, merkle_root, j.ntime, j.nbits]) j.time = time() return j
def refresh_job(self, j): j.extranonce2 = self.increment_nonce(j.extranonce2) coinbase = j.coinbase1 + self.extranonce + j.extranonce2 + j.coinbase2 merkle_root = sha256(sha256(unhexlify(coinbase)).digest()).digest() for hash_ in j.merkle_branch: merkle_root = sha256( sha256(merkle_root + unhexlify(hash_)).digest()).digest() merkle_root_reversed = b'' for word in chunks(merkle_root, 4): merkle_root_reversed += word[::-1] merkle_root = merkle_root_reversed.hex() j.block_header = ''.join( [j.version, j.prevhash, merkle_root, j.ntime, j.nbits]) j.time = time() return j
def decode(self, server, block_header, target, job_id=None, extranonce2=None): if block_header: job = Object() binary_data = unhexlify(block_header) data0 = list(unpack('<16I', binary_data[:64])) + ([0] * 48) job.target = unpack('<8I', unhexlify(target)) job.header = binary_data[:68] job.merkle_end = uint32(unpack('<I', binary_data[64:68])[0]) job.time = uint32(unpack('<I', binary_data[68:72])[0]) job.difficulty = uint32(unpack('<I', binary_data[72:76])[0]) job.state = sha256(STATE, data0) job.targetQ = 2 ** 256 // int(''.join(list(chunks(target, 2))[::-1]), 16) job.job_id = job_id job.extranonce2 = extranonce2 job.server = server if job.difficulty != self.difficulty: self.set_difficulty(job.difficulty) return job
def queue_work(self, work, miner=None): target = ''.join( list(chunks('%064x' % self.server_difficulty, 2))[::-1]) self.switch.queue_work(self, work.block_header, target, work.job_id, work.extranonce2, miner)
def handle_message(self, message): # Miner API if 'method' in message: # mining.notify if message['method'] == 'mining.notify': params = message['params'] j = Object() j.job_id = params[0] j.prevhash = params[1] #john j.prevhash = ''.join([ j.prevhash[i] + j.prevhash[i + 1] for i in range(0, len(j.prevhash), 2) ][::-1]) prev_block_hash_words = bytearray() for word in chunks(unhexlify(j.prevhash), 4): # Prepend because template items are in RPC byte order. prev_block_hash_words[0:0] = word j.prevhash = ''.join( ['%02x' % b for b in prev_block_hash_words]) j.coinbase1 = params[2] j.coinbase2 = params[3] j.merkle_branch = params[4] j.version = params[5] j.nbits = params[6] j.ntime = params[7] clear_jobs = params[8] if clear_jobs: self.jobs.clear() j.extranonce2 = self.extranonce2_size * '00' j = self.refresh_job(j) self.jobs[j.job_id] = j self.current_job = j self.queue_work(j) self.switch.connection_ok() # mining.get_version if message['method'] == 'mining.get_version': with self.send_lock: self.send_message({ "error": None, "id": message['id'], "result": self.user_agent }) # mining.set_difficulty elif message['method'] == 'mining.set_difficulty': say_line("Setting new difficulty: %s", message['params'][0]) self.server_difficulty = min( MIN_DIFFICULTY, int(BASE_DIFFICULTY // message['params'][0])) # client.reconnect elif message['method'] == 'client.reconnect': address, port = self.server().host.split(':', 1) (new_address, new_port, timeout) = message['params'][:3] if new_address: address = new_address if new_port is not None: port = new_port say_line("%s asked us to reconnect to %s:%d in %d seconds", (self.server().name, address, port, timeout)) self.server().host = address + ':' + str(port) Timer(timeout, self.reconnect).start() # client.add_peers elif message['method'] == 'client.add_peers': hosts = [{ 'host': host[0], 'port': host[1] } for host in message['params'][0]] self.switch.add_servers(hosts) # responses to server API requests elif 'result' in message: # response to mining.subscribe # store extranonce and extranonce2_size if message['id'] == 's': self.extranonce = message['result'][1] self.extranonce2_size = message['result'][2] self.subscribed = True # check if this is submit confirmation (message id should be in submits dictionary) # cleanup if necessary elif message['id'] in self.submits: miner, nonce = self.submits[message['id']][:2] accepted = message['result'] self.switch.report(miner, nonce, accepted) del self.submits[message['id']] if monotonic() - self.last_submits_cleanup > 3600: now = monotonic() for key, value in self.submits.items(): if now - value[2] > 3600: del self.submits[key] self.last_submits_cleanup = now # response to mining.authorize elif message['id'] == self.server().user: if not message['result']: say_line('authorization failed with %s:%s@%s', (self.server().user, self.server().pwd, self.server().host)) self.authorized = False else: self.authorized = True