def mine(self): while True: block = self.mine_block() if not block: continue logger.info("Block {} found at height {} and nonce {}" .format(block.block_header.hash, block.height, block.block_header.nonce)) if self.blockchain.add_block(block): self.mempool.remove_unconfirmed_transactions(block.transactions[1:]) message = {"host": self.HOST, "type": MessageType.BLOCK_HEADER.value, "data": block.block_header.to_json()} Queue.enqueue(message) return
def post_to_inbox(): body = request.json # TODO: validate sender really is who they say they are using signature host = request.environ.get('HTTP_X_FORWARDED_FOR') or request.environ.get( 'REMOTE_ADDR') msg_type = body.get('type') if MessageType(msg_type) in MessageType: msg = {'host': host, 'type': msg_type, 'data': body.get('data')} Queue.enqueue(msg) response.status = 200 return json.dumps({'success': True}) response.status = 400 return json.dumps({'success': False})
def worker(self): while True: msg = Queue.dequeue() sender = msg.get('host', '') msg_type = MessageType(msg.get('type')) data = msg.get('data') if msg_type == MessageType.BLOCK_HEADER: block_header = BlockHeader.from_dict(json.loads(data)) if sender == self.HOST: self.api_client.broadcast_block_inv([block_header.hash], self.HOST) else: self.__process_block_header(block_header, sender) continue elif msg_type == MessageType.UNCONFIRMED_TRANSACTION: unconfirmed_transaction = Transaction.from_dict(data) if sender == self.HOST: # transaction already validated before being enqueued valid = True else: valid = self.validator.validate_transaction( unconfirmed_transaction) if valid: self.api_client.broadcast_unconfirmed_transaction_inv( [unconfirmed_transaction.tx_hash], self.HOST) continue elif msg_type == MessageType.BLOCK_INV: missing_block_headers = [] for block_hash in data: # aggregate unknown block header hashes block_header = self.blockchain.get_block_header_by_hash( block_hash) if block_header is None: missing_block_headers.append(block_hash) for block_hash in missing_block_headers: # We don't have these blocks in our database. Fetch them from the sender block_header = self.api_client.request_block_header( sender, self.FULL_NODE_PORT, block_hash=block_hash) self.__process_block_header(block_header, sender) continue elif msg_type == MessageType.UNCONFIRMED_TRANSACTION_INV: missing_transactions = [] new_unconfirmed_transactions = [] for tx_hash in data: # skip known unconfirmed transactions transaction = self.blockchain.get_transaction_by_hash( tx_hash) if transaction: continue unconfirmed_transaction = self.mempool.get_unconfirmed_transaction( tx_hash) if unconfirmed_transaction: continue missing_transactions.append(tx_hash) for tx_hash in missing_transactions: # retrieve unknown unconfirmed transactions transaction = self.api_client.request_transaction( sender, self.FULL_NODE_PORT, tx_hash) valid = self.validator.validate_transaction(transaction) if valid: # validate and store retrieved unconfirmed transactions self.mempool.push_unconfirmed_transaction(transaction) new_unconfirmed_transactions.append(tx_hash) if len(new_unconfirmed_transactions): # broadcast new unconfirmed transactions self.api_client.broadcast_unconfirmed_transaction_inv( new_unconfirmed_transactions) continue else: logger.warn("Encountered unknown message type %s from %s", msg_type, sender) pass