Example #1
0
 def create_transaction(self, to, amount, fee, prev_hash):
     self.check_peers()
     transaction = Transaction(self.get_public_key(),
                               to,
                               amount,
                               fee,
                               prev_hash=prev_hash)
     transaction.sign(self.get_private_key())
     return self.api_client.broadcast_transaction(transaction)
Example #2
0
 def request_transaction(self, node, port, tx_hash):
     url = self.TRANSACTIONS_URL.format(node, port, tx_hash)
     try:
         response = requests.get(url)
         if response.status_code == 200:
             tx_dict = response.json()
             transaction = Transaction(
                 tx_dict['source'],
                 tx_dict['destination'],
                 tx_dict['amount'],
                 tx_dict['fee'],
                 tx_dict['prev_hash'],
                 tx_dict['tx_type'],
                 tx_dict['timestamp'],
                 tx_dict['tx_hash'],
                 tx_dict['asset'],
                 tx_dict['data'],
                 tx_dict['signature']
             )
             if transaction.tx_hash != tx_dict['tx_hash']:
                 logger.warn("Invalid transaction hash: {} should be {}.  Transaction ignored."
                             .format(tx_dict['tx_hash'], transaction.tx_hash))
                 return None
             return transaction
     except requests.exceptions.RequestException as re:
         logger.warn("Request Exception with host: {}".format(node))
         self.peers.record_downtime(node)
     return None
Example #3
0
 def get_all_unconfirmed_transactions_iter(self):
     sql = 'SELECT * FROM unconfirmed_transactions'
     with sqlite3.connect(self.POOL_DB) as conn:
         cursor = conn.cursor()
         cursor.execute(sql)
         for transaction in cursor:
             yield Transaction(transaction[1], transaction[2],
                               transaction[3], transaction[4],
                               transaction[10], transaction[7],
                               transaction[5], transaction[0],
                               transaction[8], transaction[9],
                               transaction[6])
Example #4
0
 def get_unconfirmed_transaction(self, tx_hash):
     sql = "SELECT * FROM unconfirmed_transactions WHERE hash='{}'".format(
         tx_hash)
     with sqlite3.connect(self.POOL_DB) as conn:
         cursor = conn.cursor()
         cursor.execute(sql)
         data = cursor.fetchone()
     if data is None:
         return None
     transaction = data[0]
     return Transaction(transaction[1], transaction[2], transaction[3],
                        transaction[4], transaction[10], transaction[7],
                        transaction[5], transaction[0], transaction[8],
                        transaction[9], transaction[6])
Example #5
0
 def get_unconfirmed_transactions_chunk(self, chunk_size=None):
     sql = 'SELECT * FROM unconfirmed_transactions ORDER BY fee DESC LIMIT {}'.format(
         chunk_size)
     transactions = []
     with sqlite3.connect(self.POOL_DB) as conn:
         cursor = conn.cursor()
         cursor.execute(sql)
         for transaction in cursor:
             transactions.append(
                 Transaction(transaction[1], transaction[2], transaction[3],
                             transaction[4], transaction[10],
                             transaction[7], transaction[5], transaction[0],
                             transaction[8], transaction[9],
                             transaction[6]))
     return transactions
Example #6
0
 def from_dict(cls, block_dict):
     return cls(block_dict['height'], [
         Transaction(transaction['source'],
                     transaction['destination'],
                     transaction['amount'],
                     transaction['fee'],
                     tx_type=transaction['tx_type'],
                     timestamp=transaction['timestamp'],
                     asset=transaction['asset'],
                     data=transaction['data'],
                     prev_hash=transaction['prev_hash'],
                     signature=transaction['signature'])
         for transaction in block_dict['transactions']
     ], block_dict['previous_hash'], block_dict['timestamp'],
                block_dict['nonce'])
Example #7
0
    def mine_block(self):
        latest_block = self.blockchain.get_tallest_block_header()
        if latest_block is not None:
            latest_block_header = latest_block[0]
            latest_block_height = latest_block[2]
            new_block_height = latest_block_height + 1
            previous_hash = latest_block_header.hash
        else:
            new_block_height = 1
            previous_hash = ""

        transactions = self.mempool.get_unconfirmed_transactions_chunk(
            self.MAX_TRANSACTIONS_PER_BLOCK)
        if transactions is None or len(transactions) == 0:
            fees = 0
        else:
            fees = sum(t.fee for t in transactions)

        coinbase_prev_hash = "0" if new_block_height == 1 \
            else self.blockchain.get_coinbase_hash_by_block_hash(previous_hash)
        # coinbase
        coinbase = Transaction("0",
                               self.REWARD_ADDRESS,
                               self.blockchain.get_reward(new_block_height) +
                               fees,
                               0,
                               prev_hash=coinbase_prev_hash,
                               tx_type=TransactionType.COINBASE.value,
                               signature="")
        transactions.insert(0, coinbase)

        timestamp = int(time.time())
        i = 0
        block = Block(new_block_height, transactions, previous_hash, timestamp)

        while block.block_header.hash_difficulty < self.blockchain.calculate_hash_difficulty(
        ):
            latest_block = self.blockchain.get_tallest_block_header()
            if latest_block is not None:
                latest_block_header = latest_block[0]
                latest_block_height = latest_block[2]
                if latest_block_height >= new_block_height or latest_block_header.hash != previous_hash:
                    # Next block in sequence was mined by another node.  Stop mining current block.
                    return None
            i += 1
            block.block_header.nonce = i
        return block
Example #8
0
def post_transactions():
    mempool = Mempool()
    validator = Validator()
    body = request.json
    transaction = Transaction.from_dict(body['transaction'])
    if transaction.tx_hash != body['transaction']['tx_hash']:
        logger.info("Invalid transaction hash: {} should be {}".format(
            body['transaction']['tx_hash'], transaction.tx_hash))
        response.status = 406
        return json.dumps({'message': 'Invalid transaction hash'})
    if mempool.get_unconfirmed_transaction(transaction.tx_hash) is None \
            and validator.validate_transaction(transaction) \
            and mempool.push_unconfirmed_transaction(transaction):
        response.status = 200
        return json.dumps({'success': True, 'tx_hash': transaction.tx_hash})
    response.status = 406
    return json.dumps({'success': False, 'reason': 'Invalid transaction'})
Example #9
0
 def get_transaction_by_hash(self, transaction_hash, branch=0):
     sql = "SELECT * FROM transactions WHERE hash='{}' AND branch={}".format(
         transaction_hash, branch)
     with sqlite3.connect(self.CHAIN_DB) as conn:
         cursor = conn.cursor()
         cursor.execute(sql)
         transaction = cursor.fetchone()
     return Transaction(transaction[1],
                        transaction[2],
                        transaction[3],
                        transaction[4],
                        tx_type=transaction[7],
                        timestamp=transaction[5],
                        tx_hash=transaction[0],
                        signature=transaction[6],
                        asset=transaction[8],
                        data=transaction[9])
Example #10
0
 def get_transactions_by_block_hash(self, block_hash):
     transactions = []
     sql = "SELECT * FROM transactions WHERE blockHash='{}' ORDER BY hash ASC".format(
         block_hash)
     with sqlite3.connect(self.CHAIN_DB) as conn:
         cursor = conn.cursor()
         cursor.execute(sql)
         for transaction in cursor:
             transactions.append(
                 Transaction(transaction[1],
                             transaction[2],
                             transaction[3],
                             transaction[4],
                             tx_type=transaction[7],
                             timestamp=transaction[5],
                             tx_hash=transaction[0],
                             signature=transaction[6],
                             asset=transaction[9],
                             data=transaction[10],
                             prev_hash=transaction[12]))
     return transactions
Example #11
0
 def get_transaction_history(self, address, branch=0):
     # TODO: convert this to return a generator
     transactions = []
     sql = "SELECT * FROM transactions WHERE (src='{}' OR dest='{}') AND branch={}".format(
         address, address, branch)
     with sqlite3.connect(self.CHAIN_DB) as conn:
         cursor = conn.cursor()
         cursor.execute(sql)
         for transaction in cursor:
             transactions.append(
                 Transaction(transaction[1],
                             transaction[2],
                             transaction[3],
                             transaction[4],
                             tx_type=transaction[7],
                             timestamp=transaction[5],
                             tx_hash=transaction[0],
                             signature=transaction[6],
                             asset=transaction[9],
                             data=transaction[10],
                             prev_hash=transaction[12]))
     return transactions
Example #12
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