def start_mining(self, parent_block: Block, parent_difficulty): try: logger.debug('start_mining - TRY LOCK') with self.lock: logger.debug('start_mining - LOCKED') self.cancel() mining_blob = self._mining_block.mining_blob nonce_offset = self._mining_block.mining_nonce_offset logger.debug('!!! Mine #{} | {} ({}) | {} -> {} | {} '.format( self._mining_block.block_number, self._measurement, self._mining_block.timestamp - parent_block.timestamp, UInt256ToString(parent_difficulty), UInt256ToString(self._current_difficulty), bin2hstr(bytearray(self._current_target)))) logger.debug('!!! Mine #{} | blob: {}'.format( self._mining_block.block_number, bin2hstr(bytearray(mining_blob)))) work_seq_id = self.start( input=mining_blob, nonceOffset=nonce_offset, target=self._current_target, thread_count=self._mining_thread_count) logger.debug("MINING START [{}]".format(work_seq_id)) except Exception as e: logger.warning("Exception in start_mining") logger.exception(e) logger.debug('start_mining - UNLOCKED')
def start_mining(self, parent_block: Block, parent_difficulty): mining_xmss = self.get_mining_xmss() if not mining_xmss: logger.warning('No Mining XMSS Found') return try: self.cancel() mining_blob = self._mining_block.mining_blob nonce_offset = self._mining_block.mining_nonce_offset logger.debug('!!! Mine #{} | {} ({}) | {} -> {} | {}'.format( self._mining_block.block_number, self._measurement, self._mining_block.timestamp - parent_block.timestamp, UInt256ToString(parent_difficulty), UInt256ToString(self._current_difficulty), self._current_target)) self.start(input=mining_blob, nonceOffset=nonce_offset, target=self._current_target, thread_count=self._mining_thread_count) except Exception as e: logger.warning("Exception in start_mining") logger.exception(e)
def _add_block_metadata(self, headerhash, block_timestamp, parent_headerhash, batch): block_metadata = self._state.get_block_metadata(headerhash) if not block_metadata: block_metadata = BlockMetadata.create() parent_metadata = self._state.get_block_metadata(parent_headerhash) parent_block_difficulty = parent_metadata.block_difficulty parent_cumulative_difficulty = parent_metadata.cumulative_difficulty block_metadata.update_last_headerhashes( parent_metadata.last_N_headerhashes, parent_headerhash) measurement = self._state.get_measurement(block_timestamp, parent_headerhash, parent_metadata) block_difficulty, _ = DifficultyTracker.get( measurement=measurement, parent_difficulty=parent_block_difficulty) block_cumulative_difficulty = StringToUInt256( str( int(UInt256ToString(block_difficulty)) + int(UInt256ToString(parent_cumulative_difficulty)))) block_metadata.set_block_difficulty(block_difficulty) block_metadata.set_cumulative_difficulty(block_cumulative_difficulty) parent_metadata.add_child_headerhash(headerhash) self._state.put_block_metadata(parent_headerhash, parent_metadata, batch) self._state.put_block_metadata(headerhash, block_metadata, batch) return block_metadata
def validate_mining_nonce(self, block, enable_logging=False): parent_metadata = self.state.get_block_metadata(block.prev_headerhash) parent_block = self.state.get_block(block.prev_headerhash) measurement = self.state.get_measurement(block.timestamp, block.prev_headerhash, parent_metadata) diff, target = DifficultyTracker.get( measurement=measurement, parent_difficulty=parent_metadata.block_difficulty) if enable_logging: logger.debug('-----------------START--------------------') logger.debug('Validate #%s', block.block_number) logger.debug('block.timestamp %s', block.timestamp) logger.debug('parent_block.timestamp %s', parent_block.timestamp) logger.debug('parent_block.difficulty %s', UInt256ToString(parent_metadata.block_difficulty)) logger.debug('diff : %s | target : %s', UInt256ToString(diff), target) logger.debug('-------------------END--------------------') if not self.verify_input_cached(block.mining_blob, target): if enable_logging: logger.warning("PoW verification failed") qn = Qryptonight() tmp_hash = qn.hash(block.mining_blob) logger.warning("{}".format(tmp_hash)) logger.debug('%s', block.to_json()) return False return True
def start_mining(self, parent_block: Block, parent_difficulty, dev_config: DevConfig): logger.debug('!!! Mine #{} | {} ({}) | {} -> {} | {} '.format( self._mining_block.block_number, self._measurement, self._mining_block.timestamp - parent_block.timestamp, UInt256ToString(parent_difficulty), UInt256ToString(self._current_difficulty), bin2hstr(bytearray(self._current_target)))) logger.debug('!!! Mine #{} | blob: {}'.format( self._mining_block.block_number, bin2hstr(bytearray(self._mining_block.mining_blob(dev_config))))) miner = self.get_miner(parent_block.block_number + 1, dev_config) miner.start_mining(self._mining_block, self._current_target, dev_config)
def get_better_difficulty(self, current_cumulative_difficulty): best_cumulative_difficulty = int(UInt256ToString(current_cumulative_difficulty)) local_best = best_cumulative_difficulty best_channel = None for channel in self._peer_node_status: node_chain_state = self._peer_node_status[channel] node_cumulative_difficulty = int(UInt256ToString(node_chain_state.cumulative_difficulty)) if node_cumulative_difficulty > best_cumulative_difficulty: best_cumulative_difficulty = node_cumulative_difficulty best_channel = channel logger.debug('Local Best Diff : %s', local_best) logger.debug('Remote Best Diff : %s', best_cumulative_difficulty) return best_channel
def _try_branch_add_block(self, block, batch, check_stale=True) -> (bool, bool): """ This function returns list of bool types. The first bool represent if the block has been added successfully and the second bool represent the fork_flag, which becomes true when a block triggered into fork recovery. :param block: :param batch: :return: [Added successfully, fork_flag] """ if self._last_block.headerhash == block.prev_headerhash: if not self._apply_block(block, batch): return False, False self._state.put_block(block, batch) last_block_metadata = self._state.get_block_metadata( self._last_block.headerhash) if last_block_metadata is None: logger.warning("Could not find log metadata for %s", bin2hstr(self._last_block.headerhash)) return False, False last_block_difficulty = int( UInt256ToString(last_block_metadata.cumulative_difficulty)) new_block_metadata = self._add_block_metadata(block.headerhash, block.timestamp, block.prev_headerhash, batch) new_block_difficulty = int( UInt256ToString(new_block_metadata.cumulative_difficulty)) if new_block_difficulty > last_block_difficulty: if self._last_block.headerhash != block.prev_headerhash: fork_state = qrlstateinfo_pb2.ForkState( initiator_headerhash=block.headerhash) self._state.put_fork_state(fork_state, batch) self._state.write_batch(batch) return self._fork_recovery(block, fork_state), True self._update_chainstate(block, batch) if check_stale: self.tx_pool.check_stale_txn(self._state, block.block_number) self.trigger_miner = True return True, False
def _try_branch_add_block(self, block, batch=None) -> bool: parent_block = self.state.get_block(block.prev_headerhash) if not block.validate_parent_child_relation(parent_block): logger.warning('Failed to validate blocks parent child relation') return False address_set = self.state.prepare_address_list( block) # Prepare list for current block if self.last_block.headerhash == block.prev_headerhash: address_txn = self.state.get_state_mainchain(address_set) else: address_txn = self.state.get_state(block.prev_headerhash, address_set) if self.validate_block(block, address_txn): self.state.put_block(block, None) self.add_block_metadata(block.headerhash, block.timestamp, block.prev_headerhash, None) last_block_metadata = self.state.get_block_metadata( self.last_block.headerhash) new_block_metadata = self.state.get_block_metadata( block.headerhash) last_block_difficulty = int( UInt256ToString(last_block_metadata.cumulative_difficulty)) new_block_difficulty = int( UInt256ToString(new_block_metadata.cumulative_difficulty)) self.trigger_miner = False if new_block_difficulty > last_block_difficulty: if self.last_block.headerhash != block.prev_headerhash: self.rollback(block) return True self.state.update_mainchain_state(address_txn, block.block_number, block.headerhash) self.last_block = block self._update_mainchain(block, batch) self.tx_pool.remove_tx_in_block_from_pool(block) self.state.update_mainchain_height(block.block_number, batch) self.state.update_tx_metadata(block, batch) self.trigger_miner = True return True return False
def get_block_datapoint(self, headerhash): block = self.get_block(headerhash) if block is None: return None block_metadata = self.get_block_metadata(headerhash) prev_block_metadata = self.get_block_metadata(block.prev_headerhash) prev_block = self.get_block(block.prev_headerhash) data_point = qrl_pb2.BlockDataPoint() data_point.number = block.block_number data_point.header_hash = headerhash if prev_block is not None: data_point.header_hash_prev = prev_block.headerhash data_point.timestamp = block.timestamp data_point.time_last = 0 data_point.time_movavg = 0 data_point.difficulty = UInt256ToString( block_metadata.block_difficulty) if prev_block is not None: data_point.time_last = block.timestamp - prev_block.timestamp if prev_block.block_number == 0: data_point.time_last = config.dev.mining_setpoint_blocktime movavg = self.get_measurement(block.timestamp, block.prev_headerhash, prev_block_metadata) data_point.time_movavg = movavg # FIXME: need to consider average difficulty here data_point.hash_power = int(data_point.difficulty) * ( config.dev.mining_setpoint_blocktime / movavg) return data_point
def handle_block_height(self, source, message: xrdlegacy_pb2.LegacyMessage): """ Sends / Receives Blockheight :param source: :param message: :return: """ if message.bhData.block_number == 0: block = source.factory.last_block cumulative_difficulty = source.factory.get_cumulative_difficulty() if block.block_number == 0: return bhdata = xrd_pb2.BlockHeightData( block_number=block.block_number, block_headerhash=block.headerhash, cumulative_difficulty=bytes(cumulative_difficulty)) msg = xrdlegacy_pb2.LegacyMessage( func_name=xrdlegacy_pb2.LegacyMessage.BH, bhData=bhdata) source.send(msg) return try: UInt256ToString(message.bhData.cumulative_difficulty) except ValueError: logger.warning('Invalid Block Height Data') source.loseConnection() return source.factory.update_peer_blockheight( source.peer.full_address, message.bhData.block_number, message.bhData.block_headerhash, message.bhData.cumulative_difficulty)
def update_peer_blockheight(self, addr_remote, block_number, headerhash, cumulative_difficulty): # FIXME: Use a named tuple to improve readability? self.peer_blockheight[addr_remote] = [ block_number, headerhash, int(UInt256ToString(cumulative_difficulty)) ]
def main(): ph = PoWHelper() qm = CustomQMiner() input_bytes = [0x03, 0x05, 0x07, 0x09, 0x19] difficulty = StringToUInt256("5000") for i in range(10): boundary = ph.getBoundary(difficulty) # print("difficulty ", difficulty) print("difficulty str ", UInt256ToString(difficulty)) print("boundary ", boundary) # print("boundary str ", UInt256ToString(boundary)) start = time.time() # Set input bytes, nonce qm.setInput(input=input_bytes, nonceOffset=0, target=boundary) qm.start(thread_count=2) while not qm.solutionFound(): time.sleep(1) print("time ", qm.end - start) print("hash ", qm.solutionHash()) print() # Set a new difficulty difficulty = ph.getDifficulty(int(qm.end), int(start), difficulty)
def add_block_metadata(self, headerhash, block_timestamp, parent_headerhash, batch): block_metadata = self.state.get_block_metadata(headerhash) if not block_metadata: block_metadata = BlockMetadata.create() parent_metadata = self.state.get_block_metadata(parent_headerhash) block_difficulty = (0, ) * 32 # 32 bytes to represent 256 bit of 0 block_cumulative_difficulty = ( 0, ) * 32 # 32 bytes to represent 256 bit of 0 if not parent_metadata: parent_metadata = BlockMetadata.create() else: parent_block = self.state.get_block(parent_headerhash) if parent_block: parent_block_difficulty = parent_metadata.block_difficulty parent_cumulative_difficulty = parent_metadata.cumulative_difficulty if not parent_metadata.is_orphan: block_metadata.update_last_headerhashes( parent_metadata.last_N_headerhashes, parent_headerhash) measurement = self.state.get_measurement( block_timestamp, parent_headerhash, parent_metadata) block_difficulty, _ = DifficultyTracker.get( measurement=measurement, parent_difficulty=parent_block_difficulty) block_cumulative_difficulty = StringToUInt256( str( int(UInt256ToString(block_difficulty)) + int(UInt256ToString(parent_cumulative_difficulty))) ) block_metadata.set_orphan(parent_metadata.is_orphan) block_metadata.set_block_difficulty(block_difficulty) block_metadata.set_cumulative_difficulty(block_cumulative_difficulty) parent_metadata.add_child_headerhash(headerhash) self.state.put_block_metadata(parent_headerhash, parent_metadata, batch) self.state.put_block_metadata(headerhash, block_metadata, batch) # Call once to populate the cache self.state.get_block_datapoint(headerhash)
def validate_mining_nonce(self, blockheader: BlockHeader, enable_logging=True): with self.lock: parent_metadata = self.get_block_metadata( blockheader.prev_headerhash) parent_block = self._state.get_block(blockheader.prev_headerhash) measurement = self.get_measurement(blockheader.timestamp, blockheader.prev_headerhash, parent_metadata) diff, target = DifficultyTracker.get( measurement=measurement, parent_difficulty=parent_metadata.block_difficulty) if enable_logging: logger.debug('-----------------START--------------------') logger.debug('Validate #%s', blockheader.block_number) logger.debug('block.timestamp %s', blockheader.timestamp) logger.debug('parent_block.timestamp %s', parent_block.timestamp) logger.debug('parent_block.difficulty %s', UInt256ToString(parent_metadata.block_difficulty)) logger.debug('diff %s', UInt256ToString(diff)) logger.debug('target %s', bin2hstr(target)) logger.debug('-------------------END--------------------') if not PoWValidator().verify_input(blockheader.mining_blob, target): if enable_logging: logger.warning("PoW verification failed") qn = Qryptonight() tmp_hash = qn.hash(blockheader.mining_blob) logger.warning("{}".format(bin2hstr(tmp_hash))) logger.debug('%s', blockheader.to_json()) return False return True
def _try_branch_add_block(self, block, batch=None) -> bool: address_set = self.state.prepare_address_list( block) # Prepare list for current block if self.last_block.headerhash == block.prev_headerhash: address_txn = self.state.get_state_mainchain(address_set) else: address_txn, rollback_headerhash, hash_path = self.state.get_state( block.prev_headerhash, address_set) if block.apply_state_changes(address_txn): self.state.put_block(block, None) self.add_block_metadata(block.headerhash, block.timestamp, block.prev_headerhash, None) last_block_metadata = self.state.get_block_metadata( self.last_block.headerhash) new_block_metadata = self.state.get_block_metadata( block.headerhash) last_block_difficulty = int( UInt256ToString(last_block_metadata.cumulative_difficulty)) new_block_difficulty = int( UInt256ToString(new_block_metadata.cumulative_difficulty)) if new_block_difficulty > last_block_difficulty: if self.last_block.headerhash != block.prev_headerhash: self.rollback(rollback_headerhash, hash_path, block.block_number) self.state.put_addresses_state(address_txn) self.last_block = block self._update_mainchain(block, batch) self.tx_pool.remove_tx_in_block_from_pool(block) self.tx_pool.check_stale_txn(block.block_number) self.state.update_mainchain_height(block.block_number, batch) self.state.update_tx_metadata(block, batch) self.trigger_miner = True return True return False
def test_adaptive_target(self): ph = PoWHelper() parent_difficulty = StringToUInt256("5000") current_difficulty = ph.getDifficulty( measurement=104, parent_difficulty=parent_difficulty) expected_difficulty = '4644' print(parent_difficulty) print(expected_difficulty) print(current_difficulty) self.assertEqual(expected_difficulty, UInt256ToString(current_difficulty)) target = ph.getTarget(current_difficulty) expected_target = "12766941454368345787240450318120704813017110301439674670851728194227068997120" self.assertEqual(expected_target, UInt256ToString(target))
def handle_chain_state(self, source, message: qrllegacy_pb2.LegacyMessage): P2PBaseObserver._validate_message(message, qrllegacy_pb2.LegacyMessage.CHAINSTATE) message.chainStateData.timestamp = ntp.getTime() # Receiving time try: UInt256ToString(message.chainStateData.cumulative_difficulty) except ValueError: logger.warning('Invalid Cumulative Difficulty sent by peer') source.loseConnection() return self._peer_node_status[source] = message.chainStateData
def main(): persistent_state = State() chain_manager = ChainManager(state=persistent_state) chain_manager.load(GenesisBlock()) ph = PoWHelper() difficulty = StringToUInt256('5000') filename = os.path.expanduser( "~/crypto/qryptonight/modeling/blockdata.csv") with open(filename, 'w') as f: f.write("i,timestamp,prev_timestamp,delta,difficulty,target\n") prev_timestamp = None for i in range(chain_manager.height): block = chain_manager.get_block_by_number(i) if i == 0: prev_timestamp = block.blockheader.timestamp continue target = ph.getTarget(difficulty) delta = block.blockheader.timestamp - prev_timestamp outs = "{},{},{},{},{},{}\n".format(i, block.blockheader.timestamp, prev_timestamp, delta, UInt256ToString(difficulty), UInt256ToString(target)) f.write(outs) difficulty = ph.getDifficulty(block.blockheader.timestamp, prev_timestamp, difficulty) difficulty = StringToUInt256( str(max(2, int(UInt256ToString(difficulty))))) prev_timestamp = block.blockheader.timestamp
def handle_chain_state(self, source, message: qrllegacy_pb2.LegacyMessage): P2PBaseObserver._validate_message(message, qrllegacy_pb2.LegacyMessage.CHAINSTATE) message.chainStateData.timestamp = ntp.getTime() # Receiving time try: UInt256ToString(message.chainStateData.cumulative_difficulty) except ValueError: logger.warning('Invalid Cumulative Difficulty sent by peer') source.loseConnection() return self._peer_node_status[source] = message.chainStateData if not self._get_version_compatibility(message.chainStateData.version): logger.warning("Disconnecting from Peer %s running incompatible node version %s", source.peer.ip, message.veData.version) source.loseConnection() return
def test_numberBack(self): input_vector = ( 122, 19, 248, 230, 14, 172, 65, 216, 102, 28, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ) value = UInt256ToString(input_vector) expected_value = "55217455456816260776929245529948378455782781241038999928326084774751073468416" self.assertEqual(expected_value, value)
def test_empty(self): with self.assertRaises(TypeError): UInt256ToString(None) with self.assertRaises(ValueError): UInt256ToString(b'')
def update_peer_blockheight(self, connection_id, block_number, headerhash, cumulative_difficulty): self.peer_blockheight[connection_id] = [ block_number, headerhash, int(UInt256ToString(cumulative_difficulty)) ]
difficulty = StringToUInt256('5000') delta = 0 filename = os.path.expanduser("~/crypto/qryptonight/modeling/blockdata.csv") with open(filename, 'w') as f: f.write("i,timestamp,prev_timestamp,delta,difficulty,boundary\n") prev_timestamp = None for i in range(chain_manager.height): block = chain_manager.get_block_by_number(i) if i == 0: prev_timestamp = block.blockheader.timestamp continue boundary = ph.getBoundary(difficulty) delta = block.blockheader.timestamp - prev_timestamp outs = "{},{},{},{},{},{}\n".format(i, block.blockheader.timestamp, prev_timestamp, delta, UInt256ToString(difficulty), UInt256ToString(boundary)) f.write(outs) difficulty = ph.getDifficulty(block.blockheader.timestamp, prev_timestamp, difficulty) difficulty = StringToUInt256(str(max(2, int(UInt256ToString(difficulty))))) prev_timestamp = block.blockheader.timestamp
difficulty = StringToUInt256('5000') delta = 0 filename = os.path.expanduser("~/crypto/qryptonight/modeling/blockdata.csv") with open(filename, 'w') as f: f.write("i,timestamp,prev_timestamp,delta,difficulty,target\n") prev_timestamp = None for i in range(chain_manager.height): block = chain_manager.get_block_by_number(i) if i == 0: prev_timestamp = block.blockheader.timestamp continue target = ph.getTarget(difficulty) delta = block.blockheader.timestamp - prev_timestamp outs = "{},{},{},{},{},{}\n".format(i, block.blockheader.timestamp, prev_timestamp, delta, UInt256ToString(difficulty), UInt256ToString(target)) f.write(outs) difficulty = ph.getDifficulty(block.blockheader.timestamp, prev_timestamp, difficulty) difficulty = StringToUInt256( str(max(2, int(UInt256ToString(difficulty))))) prev_timestamp = block.blockheader.timestamp