Beispiel #1
0
    def get_spent(self, txid, output, current_transactions=[]):
        transactions = backend.query.get_spent(self.connection, txid, output)
        transactions = list(transactions) if transactions else []
        if len(transactions) > 1:
            raise core_exceptions.CriticalDoubleSpend(
                '`{}` was spent more than once. There is a problem'
                ' with the chain'.format(txid))

        current_spent_transactions = []
        for ctxn in current_transactions:
            for ctxn_input in ctxn.inputs:
                if ctxn_input.fulfills and\
                   ctxn_input.fulfills.txid == txid and\
                   ctxn_input.fulfills.output == output:
                    current_spent_transactions.append(ctxn)

        transaction = None
        if len(transactions) + len(current_spent_transactions) > 1:
            raise DoubleSpend('tx "{}" spends inputs twice'.format(txid))
        elif transactions:
            transaction = Transaction.from_db(self, transactions[0])
        elif current_spent_transactions:
            transaction = current_spent_transactions[0]

        return transaction
Beispiel #2
0
    def get_block(self, block_id):
        """Get the block with the specified `block_id`.

        Returns the block corresponding to `block_id` or None if no match is
        found.

        Args:
            block_id (int): block id of the block to get.
        """

        block = backend.query.get_block(self.connection, block_id)
        latest_block = self.get_latest_block()
        latest_block_height = latest_block['height'] if latest_block else 0

        if not block and block_id > latest_block_height:
            return

        result = {'height': block_id, 'transactions': []}

        if block:
            transactions = backend.query.get_transactions(
                self.connection, block['transactions'])
            result['transactions'] = [
                t.to_dict() for t in Transaction.from_db(self, transactions)
            ]

        return result
Beispiel #3
0
    def get_block(self, block_id):
        """Get the block with the specified `block_id`.

        Returns the block corresponding to `block_id` or None if no match is
        found.

        Args:
            block_id (int): block id of the block to get.
        """

        block = backend.query.get_block(self.connection, block_id)
        latest_block = self.get_latest_block()
        latest_block_height = latest_block['height'] if latest_block else 0

        if not block and block_id > latest_block_height:
            return

        result = {'height': block_id,
                  'transactions': []}

        if block:
            transactions = backend.query.get_transactions(self.connection, block['transactions'])
            result['transactions'] = [t.to_dict() for t in Transaction.from_db(self, transactions)]

        return result
Beispiel #4
0
    def get_spent(self, txid, output, current_transactions=[]):
        transactions = backend.query.get_spent(self.connection, txid,
                                               output)
        transactions = list(transactions) if transactions else []
        if len(transactions) > 1:
            raise core_exceptions.CriticalDoubleSpend(
                '`{}` was spent more than once. There is a problem'
                ' with the chain'.format(txid))

        current_spent_transactions = []
        for ctxn in current_transactions:
            for ctxn_input in ctxn.inputs:
                if ctxn_input.fulfills and\
                   ctxn_input.fulfills.txid == txid and\
                   ctxn_input.fulfills.output == output:
                    current_spent_transactions.append(ctxn)

        transaction = None
        if len(transactions) + len(current_spent_transactions) > 1:
            raise DoubleSpend('tx "{}" spends inputs twice'.format(txid))
        elif transactions:
            transaction = Transaction.from_db(self, transactions[0])
        elif current_spent_transactions:
            transaction = current_spent_transactions[0]

        return transaction
Beispiel #5
0
    def get_block(self, block_id, include_status=False):
        """Get the block with the specified `block_id` (and optionally its status)

        Returns the block corresponding to `block_id` or None if no match is
        found.

        Args:
            block_id (str): block id of the block to get
            include_status (bool): also return the status of the block
                       the return value is then a tuple: (block, status)
        """
        # get block from database
        if isinstance(block_id, str):
            block_id = int(block_id)

        block = backend.query.get_block(self.connection, block_id)
        if block:
            transactions = backend.query.get_transactions(
                self.connection, block['transactions'])
            transactions = Transaction.from_db(self, transactions)

            block = {'height': block['height'], 'transactions': []}
            block_txns = block['transactions']
            for txn in transactions:
                block_txns.append(txn.to_dict())

        status = None
        if include_status:
            # NOTE: (In Tendermint) a block is an abstract entity which
            # exists only after it has been validated
            if block:
                status = self.BLOCK_VALID
            return block, status
        else:
            return block
    def get_transaction(self, txid, include_status=False):
        """Get the transaction with the specified `txid` (and optionally its status)

        This query begins by looking in the bigchain table for all blocks containing
        a transaction with the specified `txid`. If one of those blocks is valid, it
        returns the matching transaction from that block. Else if some of those
        blocks are undecided, it returns a matching transaction from one of them. If
        the transaction was found in invalid blocks only, or in no blocks, then this
        query looks for a matching transaction in the backlog table, and if it finds
        one there, it returns that.

        Args:
            txid (str): transaction id of the transaction to get
            include_status (bool): also return the status of the transaction
                                   the return value is then a tuple: (tx, status)

        Returns:
            A :class:`~.models.Transaction` instance if the transaction
            was found in a valid block, an undecided block, or the backlog table,
            otherwise ``None``.
            If :attr:`include_status` is ``True``, also returns the
            transaction's status if the transaction was found.
        """

        response, tx_status = None, None

        validity = self.get_blocks_status_containing_tx(txid)
        check_backlog = True

        if validity:
            # Disregard invalid blocks, and return if there are no valid or undecided blocks
            validity = {
                _id: status
                for _id, status in validity.items()
                if status != Bigchain.BLOCK_INVALID
            }
            if validity:

                # The transaction _was_ found in an undecided or valid block,
                # so there's no need to look in the backlog table
                check_backlog = False

                tx_status = self.TX_UNDECIDED
                # If the transaction is in a valid or any undecided block, return it. Does not check
                # if transactions in undecided blocks are consistent, but selects the valid block
                # before undecided ones
                for target_block_id in validity:
                    if validity[target_block_id] == Bigchain.BLOCK_VALID:
                        tx_status = self.TX_VALID
                        break

                # Query the transaction in the target block and return
                response = backend.query.get_transaction_from_block(
                    self.connection, txid, target_block_id)

        if check_backlog:
            response = backend.query.get_transaction_from_backlog(
                self.connection, txid)

            if response:
                tx_status = self.TX_IN_BACKLOG

        if response:
            if tx_status == self.TX_IN_BACKLOG:
                response = Transaction.from_dict(response)
            else:
                # If we are reading from the bigchain collection the asset is
                # not in the transaction so we need to fetch the asset and
                # reconstruct the transaction.
                response = Transaction.from_db(self, response)

        if include_status:
            return response, tx_status
        else:
            return response
Beispiel #7
0
    def get_transaction(self, txid, include_status=False):
        """Get the transaction with the specified `txid` (and optionally its status)

        This query begins by looking in the bigchain table for all blocks containing
        a transaction with the specified `txid`. If one of those blocks is valid, it
        returns the matching transaction from that block. Else if some of those
        blocks are undecided, it returns a matching transaction from one of them. If
        the transaction was found in invalid blocks only, or in no blocks, then this
        query looks for a matching transaction in the backlog table, and if it finds
        one there, it returns that.

        Args:
            txid (str): transaction id of the transaction to get
            include_status (bool): also return the status of the transaction
                                   the return value is then a tuple: (tx, status)

        Returns:
            A :class:`~.models.Transaction` instance if the transaction
            was found in a valid block, an undecided block, or the backlog table,
            otherwise ``None``.
            If :attr:`include_status` is ``True``, also returns the
            transaction's status if the transaction was found.
        """

        response, tx_status = None, None

        blocks_validity_status = self.get_blocks_status_containing_tx(txid)
        check_backlog = True

        if blocks_validity_status:
            # Disregard invalid blocks, and return if there are no valid or undecided blocks
            blocks_validity_status = {
                _id: status for _id, status in blocks_validity_status.items()
                if status != Bigchain.BLOCK_INVALID
            }
            if blocks_validity_status:

                # The transaction _was_ found in an undecided or valid block,
                # so there's no need to look in the backlog table
                check_backlog = False

                tx_status = self.TX_UNDECIDED
                # If the transaction is in a valid or any undecided block, return it. Does not check
                # if transactions in undecided blocks are consistent, but selects the valid block
                # before undecided ones
                for target_block_id in blocks_validity_status:
                    if blocks_validity_status[target_block_id] == Bigchain.BLOCK_VALID:
                        tx_status = self.TX_VALID
                        break

                # Query the transaction in the target block and return
                response = backend.query.get_transaction_from_block(self.connection, txid, target_block_id)

        if check_backlog:
            response = backend.query.get_transaction_from_backlog(self.connection, txid)

            if response:
                tx_status = self.TX_IN_BACKLOG

        if response:
            if tx_status == self.TX_IN_BACKLOG:
                response = Transaction.from_dict(response)
            else:
                # If we are reading from the bigchain collection the asset is
                # not in the transaction so we need to fetch the asset and
                # reconstruct the transaction.
                response = Transaction.from_db(self, response)

        if include_status:
            return response, tx_status
        else:
            return response