Beispiel #1
0
 def get_all_block_headers_iter(self, branch=0):
     # yields tuples of BlockHeader, branch, height
     sql = 'SELECT * FROM blocks WHERE branch={}'.format(branch)
     with sqlite3.connect(self.CHAIN_DB) as conn:
         cursor = conn.cursor()
         cursor.execute(sql)
         for block in cursor:
             yield BlockHeader(block[1], block[2], block[5], block[4],
                               block[6]), block[7], block[3]
Beispiel #2
0
 def get_block_header_by_hash(self, block_hash):
     # returns tuple of BlockHeader, branch, height
     sql = "SELECT * FROM blocks WHERE hash='{}'".format(block_hash)
     with sqlite3.connect(self.CHAIN_DB) as conn:
         cursor = conn.cursor()
         cursor.execute(sql)
         block = cursor.fetchone()
     if block is None:
         return None
     return BlockHeader(block[1], block[2], block[5], block[4],
                        block[6]), block[7], block[3]
Beispiel #3
0
 def get_tallest_block_header(self, branch=0):
     # returns tuple of BlockHeader, branch, height
     sql = 'SELECT * FROM blocks WHERE height = (SELECT MAX(height) FROM blocks WHERE branch={})'.format(
         branch)
     with sqlite3.connect(self.CHAIN_DB) as conn:
         cursor = conn.cursor()
         cursor.execute(sql)
         block = cursor.fetchone()
     if block is None:
         return None
     return BlockHeader(block[1], block[2], block[5], block[4],
                        block[6]), block[7], block[3]
Beispiel #4
0
 def get_block_headers_range_iter(self,
                                  start_height,
                                  stop_height,
                                  branch=0):
     # yields tuples of BlockHeader, branch, height
     sql = 'SELECT * FROM blocks WHERE height >= {} AND height <= {} AND branch={} ORDER BY height ASC'\
         .format(start_height, stop_height, branch)
     with sqlite3.connect(self.CHAIN_DB) as conn:
         cursor = conn.cursor()
         cursor.execute(sql)
         for block in cursor:
             yield BlockHeader(block[1], block[2], block[5], block[4],
                               block[6]), block[7], block[3]
Beispiel #5
0
 def get_block_headers_by_height(self, height):
     # returns tuples of BlockHeader, branch, height
     block_headers = []
     sql = 'SELECT * FROM blocks WHERE height={} ORDER BY branch'.format(
         height)
     with sqlite3.connect(self.CHAIN_DB) as conn:
         cursor = conn.cursor()
         cursor.execute(sql)
         for block in cursor:
             block_headers.append(
                 (BlockHeader(block[1], block[2], block[5], block[4],
                              block[6]), block[7], block[3]))
     return block_headers
Beispiel #6
0
 def request_block_header(self, node, port, block_hash=None, height=None):
     if block_hash is not None:
         url = self.BLOCKS_URL.format(node, port, "hash", block_hash)
     elif height is not None:
         url = self.BLOCKS_URL.format(node, port, "height", height)
     else:
         url = self.BLOCKS_URL.format(node, port, "height", "latest")
     try:
         response = requests.get(url)
         if response.status_code == 200:
             block_dict = response.json()
             block_header = BlockHeader(block_dict['previous_hash'],
                                        block_dict['merkle_root'],
                                        block_dict['timestamp'],
                                        block_dict['nonce'],
                                        block_dict['version'])
             return block_header
     except requests.exceptions.RequestException as re:
         logger.warn("Request Exception with host: {}".format(node))
         self.peers.record_downtime(node)
     return None
Beispiel #7
0
 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