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
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
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
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
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