def mine(self, transaction_list): if len(transaction_list) > MiningService.TRANSACTIONS_PER_BLOCK: raise Exception("Transactions count should be less than " + str(MiningService.TRANSACTIONS_PER_BLOCK) + 1) block_number = self.writer_service.get_head_block_number() + 1 prev_block_hash = self.writer_service.get_head_block_hash() block_data_without_nonce = Block.block_data_without_nonce(block_number, prev_block_hash, transaction_list) transactions = {} for t in transaction_list: transactions[t.get_id()] = t nonce = 0 logging.info("Mining block : " + str(block_number)) while nonce < self.__max_nonce: block_data = block_data_without_nonce + str(nonce) block_data_hash = md5(block_data.encode()).hexdigest() if self.satisfies_difficulty(block_data_hash): logging.info("Block " + str(block_number) + " mined with nonce " + str(nonce) + " : ") #print(bin(int(block_data_hash, 16))[2:].zfill(len(block_data_hash) * 4)) block = Block(block_number, prev_block_hash, transactions, nonce, block_data_hash) logging.info(block.convert_to_dict()) self.writer_service.write(block_data_hash, block) break nonce += 1 # Ideally, we should shuffle the transactions and repeat the process till we get a valid nonce if nonce == self.__max_nonce: raise Exception("Couldn't find a valid nonce for the data.")
def mine_new_transaction_set(self, transaction_list): if len(transaction_list) > PoolMiningService.TRANSACTIONS_PER_BLOCK: raise Exception("Transactions count should be less than " + str(PoolMiningService.TRANSACTIONS_PER_BLOCK) + 1) transactions = {} for t in transaction_list: transactions[t.get_id()] = t block_number = self.writer_service.get_head_block_number() + 1 prev_block_hash = self.writer_service.get_head_block_hash() block_data_without_nonce = Block.block_data_without_nonce( block_number, prev_block_hash, transaction_list) self.cur_block_in_buffer = { "block_data_without_nonce": block_data_without_nonce, "block_hash": md5(block_data_without_nonce.encode()).hexdigest(), "block_number": block_number, "prev_block_hash": prev_block_hash, "transactions": transactions } block_with_nonce_range = {"block": block_data_without_nonce} for data_node in self.DATA_NODES_ADDRESS: block_with_nonce_range["nonce_start"] = self.cur_nonce_start_value block_with_nonce_range[ "nonce_end"] = self.cur_nonce_start_value + self.NONCE_RANGE_PER_NODE self.network_service.send_block_for_mining(data_node, block_with_nonce_range) self.cur_nonce_start_value += self.NONCE_RANGE_PER_NODE
def fetch_blockchain_from(self, target_peer): url = "http://{}/block/all".format(target_peer) logging.info("Fetching blockchain from " + url) response = requests.get(url=url) blockchain_json = response.json()['data'] blockchain = [] for block_json in blockchain_json: block = Block.load_from_json(block_json) blockchain.append(block) return blockchain
def validate_and_add_block(self, nonce, block_hash): logging.info("\n\n\n") if block_hash != self.cur_block_in_buffer["block_hash"]: logging.info(block_hash) logging.info(self.cur_block_in_buffer["block_hash"]) logging.error("block_hash not equal to hash in buffer...\n\n\n\n") return block_data = self.cur_block_in_buffer[ "block_data_without_nonce"] + str(nonce) block_data_hash = md5(block_data.encode()).hexdigest() if not self.satisfies_difficulty(block_data_hash): logging.error("Nonce of the block does not meet mining criteria") return self.reset_pool() block = Block(self.cur_block_in_buffer["block_number"], self.cur_block_in_buffer["prev_block_hash"], self.cur_block_in_buffer["transactions"], nonce, block_data_hash) logging.info(block.convert_to_dict()) self.writer_service.write(block_data_hash, block)
def on_post(self, req, resp): data = json.loads(req.stream.read().decode()) new_block_json = data['block'] new_block = Block.load_from_json(new_block_json) sender = data['sender'] logging.info("Received new block") validate_and_insert_block(new_block, sender) response = {'status': 'success'} response = json.dumps(response) resp.body = response
def validate_block(block): logging.info("Validating block...") transactions_list = [] for transaction in block.transactions.values(): transactions_list.append(transaction) block_data_without_nonce = Block.block_data_without_nonce(block.block_number, block.prev_block_hash, transactions_list) block_data = block_data_without_nonce + str(block.nonce) block_data_hash = hashlib.md5(block_data.encode()).hexdigest() if not pool_mining_service.satisfies_difficulty(block_data_hash): logging.error("Nonce of the block does not meet mining criteria") return False for transaction in block.transactions.values(): if not transaction.verify(): logging.error("Transaction with an invalid signature encountered") return False logging.info("Block validated successfully.\n") return True
def __init__(self): if WriterService.__instance is not None: raise Exception( "Singleton instance already exists. Use WriterService.get_instance() to get that instance." ) WriterService.__instance = self with open('./config.json', 'r') as f: self.config = json.load(f) # The 'head_block_hash' file, if exists, stores the block hash of the head block. # Check to see if the file exists, and if so, read the corresponding # block, and assign it to the head_block property try: with open(self.config['LOCAL_PATH'] + "head_block_hash") as f: head_block_hash = f.read() with open(self.config['LOCAL_PATH'] + head_block_hash + ".json") as f: block_json = json.loads(f.read()) self.head_block = Block.load_from_json(block_json) except FileNotFoundError: pass