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_spent(self, txid, output, current_transactions=[]): transactions = backend.query.get_spent(self.connection, txid, output) transactions = list(transactions) if transactions else [] for ctxn in current_transactions: for ctxn_input in ctxn.inputs: if ctxn_input.fulfills.txid == txid and\ ctxn_input.fulfills.output == output: transactions.append(ctxn.to_dict()) transaction = None if len(transactions) > 1: raise core_exceptions.CriticalDoubleSpend( '`{}` was spent more than once. There is a problem' ' with the chain'.format(txid)) elif transactions: transaction = transactions[0] if transaction and transaction['operation'] == 'CREATE': asset = backend.query.get_asset(self.connection, transaction['id']) if asset: transaction['asset'] = asset else: transaction['asset'] = {'data': None} return Transaction.from_dict(transaction) elif transaction and transaction['operation'] == 'TRANSFER': return Transaction.from_dict(transaction) else: return None
def get_spent(self, txid, output): """Check if a `txid` was already used as an input. A transaction can be used as an input for another transaction. Bigchain needs to make sure that a given `(txid, output)` is only used once. This method will check if the `(txid, output)` has already been spent in a transaction that is in either the `VALID`, `UNDECIDED` or `BACKLOG` state. Args: txid (str): The id of the transaction output (num): the index of the output in the respective transaction Returns: The transaction (Transaction) that used the `(txid, output)` as an input else `None` Raises: CriticalDoubleSpend: If the given `(txid, output)` was spent in more than one valid transaction. """ # checks if an input was already spent # checks if the bigchain has any transaction with input {'txid': ..., # 'output': ...} transactions = list( backend.query.get_spent(self.connection, txid, output)) # a transaction_id should have been spent at most one time # determine if these valid transactions appear in more than one valid # block num_valid_transactions = 0 non_invalid_transactions = [] for transaction in transactions: # ignore transactions in invalid blocks # FIXME: Isn't there a faster solution than doing I/O again? txn, status = self.get_transaction(transaction['id'], include_status=True) if status == self.TX_VALID: num_valid_transactions += 1 # `txid` can only have been spent in at most on valid block. if num_valid_transactions > 1: raise core_exceptions.CriticalDoubleSpend( '`{}` was spent more than once. There is a problem' ' with the chain'.format(txid)) # if its not and invalid transaction if status is not None: transaction.update({'metadata': txn.metadata}) non_invalid_transactions.append(transaction) if non_invalid_transactions: return Transaction.from_dict(non_invalid_transactions[0])
def get_spent(self, txid, output): """Check if a `txid` was already used as an input. A transaction can be used as an input for another transaction. Bigchain needs to make sure that a given `txid` is only used once. Args: txid (str): The id of the transaction output (num): the index of the output in the respective transaction Returns: The transaction (Transaction) that used the `txid` as an input else `None` """ # checks if an input was already spent # checks if the bigchain has any transaction with input {'txid': ..., # 'output': ...} transactions = list( backend.query.get_spent(self.connection, txid, output)) # a transaction_id should have been spent at most one time if transactions: # determine if these valid transactions appear in more than one valid block num_valid_transactions = 0 for transaction in transactions: # ignore invalid blocks # FIXME: Isn't there a faster solution than doing I/O again? if self.get_transaction(transaction['id']): num_valid_transactions += 1 if num_valid_transactions > 1: raise core_exceptions.CriticalDoubleSpend( '`{}` was spent more than once. There is a problem' ' with the chain'.format(txid)) if num_valid_transactions: return Transaction.from_dict(transactions[0]) else: # all queried transactions were invalid return None else: return None