mirror of
https://github.com/bigchaindb/bigchaindb.git
synced 2024-10-13 13:34:05 +00:00
Problem: Bigchain class is unused and redundant (#2366)
* Problem: core.py contains an unused class, `Bigchain` Solution: Remove core.py. Refactor BigchainDB Class to remove inheritance from Bigchain. * Problem: core.py contains an unused class, `Bigchain` Solution: Remove core.py. Refactor BigchainDB Class to remove inheritance from Bigchain. * Fixed flake8 complaint about too many blank lines * Attempting to fix Sphinx docs. This may result in some redundant commits, as I don't know what I'm doing, and I can't experiment without running the CI... Sorry in advance! * Attempting to fix Sphinx docs. This may result in some redundant commits, as I don't know what I'm doing, and I can't experiment without running the CI... Sorry in advance! * Updating from master changed BigchainDB.process_post_response to a private method, so I had to align with that. * Fixed a couple stale references to bigchaindb.Bigchain in docstrings * Missed a reference to `Bigchain` in a patch call... * Merge with master and re-do some changes
This commit is contained in:
parent
f243b252ca
commit
4d2e58416c
@ -4,9 +4,9 @@ A high-level description of the files and subdirectories of BigchainDB.
|
|||||||
|
|
||||||
## Files
|
## Files
|
||||||
|
|
||||||
### [`core.py`](./core.py)
|
### [`tendermint/lib.py`](./tendermint/lib.py)
|
||||||
|
|
||||||
The `Bigchain` class is defined here. Most node-level operations and database interactions are found in this file. This is the place to start if you are interested in implementing a server API, since many of these class methods concern BigchainDB interacting with the outside world.
|
The `BigchainDB` class is defined here. Most node-level operations and database interactions are found in this file. This is the place to start if you are interested in implementing a server API, since many of these class methods concern BigchainDB interacting with the outside world.
|
||||||
|
|
||||||
### [`models.py`](./models.py)
|
### [`models.py`](./models.py)
|
||||||
|
|
||||||
|
@ -84,5 +84,5 @@ config = {
|
|||||||
# the user wants to reconfigure the node. Check ``bigchaindb.config_utils``
|
# the user wants to reconfigure the node. Check ``bigchaindb.config_utils``
|
||||||
# for more info.
|
# for more info.
|
||||||
_config = copy.deepcopy(config)
|
_config = copy.deepcopy(config)
|
||||||
from bigchaindb.core import Bigchain # noqa
|
from bigchaindb.tendermint import BigchainDB # noqa
|
||||||
from bigchaindb.version import __version__ # noqa
|
from bigchaindb.version import __version__ # noqa
|
||||||
|
@ -97,7 +97,7 @@ def run_configure(args):
|
|||||||
def run_upsert_validator(args):
|
def run_upsert_validator(args):
|
||||||
"""Store validators which should be synced with Tendermint"""
|
"""Store validators which should be synced with Tendermint"""
|
||||||
|
|
||||||
b = bigchaindb.tendermint.lib.BigchainDB()
|
b = bigchaindb.tendermint.BigchainDB()
|
||||||
public_key = public_key_from_base64(args.public_key)
|
public_key = public_key_from_base64(args.public_key)
|
||||||
validator = {'pub_key': {'type': 'ed25519',
|
validator = {'pub_key': {'type': 'ed25519',
|
||||||
'data': public_key},
|
'data': public_key},
|
||||||
@ -113,7 +113,7 @@ def run_upsert_validator(args):
|
|||||||
|
|
||||||
|
|
||||||
def _run_init():
|
def _run_init():
|
||||||
bdb = bigchaindb.tendermint.lib.BigchainDB()
|
bdb = bigchaindb.tendermint.BigchainDB()
|
||||||
|
|
||||||
schema.init_database(connection=bdb.connection)
|
schema.init_database(connection=bdb.connection)
|
||||||
|
|
||||||
|
@ -1,434 +0,0 @@
|
|||||||
from bigchaindb import exceptions as core_exceptions
|
|
||||||
|
|
||||||
import bigchaindb
|
|
||||||
|
|
||||||
from bigchaindb import backend, config_utils
|
|
||||||
from bigchaindb.consensus import BaseConsensusRules
|
|
||||||
from bigchaindb.models import Transaction
|
|
||||||
|
|
||||||
|
|
||||||
class Bigchain(object):
|
|
||||||
"""Bigchain API
|
|
||||||
|
|
||||||
Create, read, sign, write transactions to the database
|
|
||||||
"""
|
|
||||||
|
|
||||||
BLOCK_INVALID = 'invalid'
|
|
||||||
"""return if a block is invalid"""
|
|
||||||
|
|
||||||
BLOCK_VALID = TX_VALID = 'valid'
|
|
||||||
"""return if a block is valid, or tx is in valid block"""
|
|
||||||
|
|
||||||
BLOCK_UNDECIDED = TX_UNDECIDED = 'undecided'
|
|
||||||
"""return if block is undecided, or tx is in undecided block"""
|
|
||||||
|
|
||||||
TX_IN_BACKLOG = 'backlog'
|
|
||||||
"""return if transaction is in backlog"""
|
|
||||||
|
|
||||||
def __init__(self, connection=None):
|
|
||||||
"""Initialize the Bigchain instance
|
|
||||||
|
|
||||||
A Bigchain instance has several configuration parameters (e.g. host).
|
|
||||||
If a parameter value is passed as an argument to the Bigchain
|
|
||||||
__init__ method, then that is the value it will have.
|
|
||||||
Otherwise, the parameter value will come from an environment variable.
|
|
||||||
If that environment variable isn't set, then the value
|
|
||||||
will come from the local configuration file. And if that variable
|
|
||||||
isn't in the local configuration file, then the parameter will have
|
|
||||||
its default value (defined in bigchaindb.__init__).
|
|
||||||
|
|
||||||
Args:
|
|
||||||
connection (:class:`~bigchaindb.backend.connection.Connection`):
|
|
||||||
A connection to the database.
|
|
||||||
"""
|
|
||||||
consensusPlugin = bigchaindb.config.get('consensus_plugin')
|
|
||||||
|
|
||||||
if consensusPlugin:
|
|
||||||
self.consensus = config_utils.load_consensus_plugin(consensusPlugin)
|
|
||||||
else:
|
|
||||||
self.consensus = BaseConsensusRules
|
|
||||||
|
|
||||||
def delete_transaction(self, *transaction_id):
|
|
||||||
"""Delete a transaction from the backlog.
|
|
||||||
|
|
||||||
Args:
|
|
||||||
*transaction_id (str): the transaction(s) to delete
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
The database response.
|
|
||||||
"""
|
|
||||||
|
|
||||||
return backend.query.delete_transaction(self.connection, *transaction_id)
|
|
||||||
|
|
||||||
def get_stale_transactions(self):
|
|
||||||
"""Get a cursor of stale transactions.
|
|
||||||
|
|
||||||
Transactions are considered stale if they have been assigned a node, but are still in the
|
|
||||||
backlog after some amount of time specified in the configuration
|
|
||||||
"""
|
|
||||||
|
|
||||||
return backend.query.get_stale_transactions(self.connection)
|
|
||||||
|
|
||||||
def validate_transaction(self, transaction):
|
|
||||||
"""Validate a transaction.
|
|
||||||
|
|
||||||
Args:
|
|
||||||
transaction (Transaction): transaction to validate.
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
The transaction if the transaction is valid else it raises an
|
|
||||||
exception describing the reason why the transaction is invalid.
|
|
||||||
"""
|
|
||||||
|
|
||||||
return self.consensus.validate_transaction(self, transaction)
|
|
||||||
|
|
||||||
def is_new_transaction(self, txid, exclude_block_id=None):
|
|
||||||
"""Return True if the transaction does not exist in any
|
|
||||||
VALID or UNDECIDED block. Return False otherwise.
|
|
||||||
|
|
||||||
Args:
|
|
||||||
txid (str): Transaction ID
|
|
||||||
exclude_block_id (str): Exclude block from search
|
|
||||||
"""
|
|
||||||
block_statuses = self.get_blocks_status_containing_tx(txid)
|
|
||||||
block_statuses.pop(exclude_block_id, None)
|
|
||||||
for status in block_statuses.values():
|
|
||||||
if status != self.BLOCK_INVALID:
|
|
||||||
return False
|
|
||||||
return True
|
|
||||||
|
|
||||||
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
|
|
||||||
|
|
||||||
def get_status(self, txid):
|
|
||||||
"""Retrieve the status of a transaction with `txid` from bigchain.
|
|
||||||
|
|
||||||
Args:
|
|
||||||
txid (str): transaction id of the transaction to query
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
(string): transaction status ('valid', 'undecided',
|
|
||||||
or 'backlog'). If no transaction with that `txid` was found it
|
|
||||||
returns `None`
|
|
||||||
"""
|
|
||||||
_, status = self.get_transaction(txid, include_status=True)
|
|
||||||
return status
|
|
||||||
|
|
||||||
def get_blocks_status_containing_tx(self, txid):
|
|
||||||
"""Retrieve block ids and statuses related to a transaction
|
|
||||||
|
|
||||||
Transactions may occur in multiple blocks, but no more than one valid block.
|
|
||||||
|
|
||||||
Args:
|
|
||||||
txid (str): transaction id of the transaction to query
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
A dict of blocks containing the transaction,
|
|
||||||
e.g. {block_id_1: 'valid', block_id_2: 'invalid' ...}, or None
|
|
||||||
"""
|
|
||||||
|
|
||||||
# First, get information on all blocks which contain this transaction
|
|
||||||
blocks = backend.query.get_blocks_status_from_transaction(self.connection, txid)
|
|
||||||
if blocks:
|
|
||||||
# Determine the election status of each block
|
|
||||||
blocks_validity_status = {
|
|
||||||
block['id']: self.block_election_status(block)
|
|
||||||
for block in blocks
|
|
||||||
}
|
|
||||||
|
|
||||||
# NOTE: If there are multiple valid blocks with this transaction,
|
|
||||||
# something has gone wrong
|
|
||||||
if list(blocks_validity_status.values()).count(Bigchain.BLOCK_VALID) > 1:
|
|
||||||
block_ids = str([
|
|
||||||
block for block in blocks_validity_status
|
|
||||||
if blocks_validity_status[block] == Bigchain.BLOCK_VALID
|
|
||||||
])
|
|
||||||
raise core_exceptions.CriticalDoubleInclusion(
|
|
||||||
'Transaction {tx} is present in '
|
|
||||||
'multiple valid blocks: {block_ids}'
|
|
||||||
.format(tx=txid, block_ids=block_ids))
|
|
||||||
|
|
||||||
return blocks_validity_status
|
|
||||||
|
|
||||||
else:
|
|
||||||
return None
|
|
||||||
|
|
||||||
def get_asset_by_id(self, asset_id):
|
|
||||||
"""Returns the asset associated with an asset_id.
|
|
||||||
|
|
||||||
Args:
|
|
||||||
asset_id (str): The asset id.
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
dict if the asset exists else None.
|
|
||||||
"""
|
|
||||||
cursor = backend.query.get_asset_by_id(self.connection, asset_id)
|
|
||||||
cursor = list(cursor)
|
|
||||||
if cursor:
|
|
||||||
return cursor[0]['asset']
|
|
||||||
|
|
||||||
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])
|
|
||||||
|
|
||||||
# Either no transaction was returned spending the `(txid, output)` as
|
|
||||||
# input or the returned transactions are not valid.
|
|
||||||
|
|
||||||
def get_owned_ids(self, owner):
|
|
||||||
"""Retrieve a list of ``txid`` s that can be used as inputs.
|
|
||||||
|
|
||||||
Args:
|
|
||||||
owner (str): base58 encoded public key.
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
:obj:`list` of TransactionLink: list of ``txid`` s and ``output`` s
|
|
||||||
pointing to another transaction's condition
|
|
||||||
"""
|
|
||||||
return self.get_outputs_filtered(owner, spent=False)
|
|
||||||
|
|
||||||
def get_outputs_filtered(self, owner, spent=None):
|
|
||||||
"""Get a list of output links filtered on some criteria
|
|
||||||
|
|
||||||
Args:
|
|
||||||
owner (str): base58 encoded public_key.
|
|
||||||
spent (bool): If ``True`` return only the spent outputs. If
|
|
||||||
``False`` return only unspent outputs. If spent is
|
|
||||||
not specified (``None``) return all outputs.
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
:obj:`list` of TransactionLink: list of ``txid`` s and ``output`` s
|
|
||||||
pointing to another transaction's condition
|
|
||||||
"""
|
|
||||||
outputs = self.fastquery.get_outputs_by_public_key(owner)
|
|
||||||
if spent is None:
|
|
||||||
return outputs
|
|
||||||
elif spent is True:
|
|
||||||
return self.fastquery.filter_unspent_outputs(outputs)
|
|
||||||
elif spent is False:
|
|
||||||
return self.fastquery.filter_spent_outputs(outputs)
|
|
||||||
|
|
||||||
def get_transactions_filtered(self, asset_id, operation=None):
|
|
||||||
"""Get a list of transactions filtered on some criteria
|
|
||||||
"""
|
|
||||||
txids = backend.query.get_txids_filtered(self.connection, asset_id,
|
|
||||||
operation)
|
|
||||||
for txid in txids:
|
|
||||||
tx, status = self.get_transaction(txid, True)
|
|
||||||
if status == self.TX_VALID:
|
|
||||||
yield tx
|
|
||||||
|
|
||||||
# TODO: check that the votings structure is correctly constructed
|
|
||||||
def validate_block(self, block):
|
|
||||||
"""Validate a block.
|
|
||||||
|
|
||||||
Args:
|
|
||||||
block (Block): block to validate.
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
The block if the block is valid else it raises and exception
|
|
||||||
describing the reason why the block is invalid.
|
|
||||||
"""
|
|
||||||
return self.consensus.validate_block(self, block)
|
|
||||||
|
|
||||||
def write_block(self, block):
|
|
||||||
"""Write a block to bigchain.
|
|
||||||
|
|
||||||
Args:
|
|
||||||
block (Block): block to write to bigchain.
|
|
||||||
"""
|
|
||||||
|
|
||||||
# Decouple assets from block
|
|
||||||
assets, block_dict = block.decouple_assets()
|
|
||||||
metadatas, block_dict = block.decouple_metadata(block_dict)
|
|
||||||
|
|
||||||
# write the assets
|
|
||||||
if assets:
|
|
||||||
self.write_assets(assets)
|
|
||||||
|
|
||||||
if metadatas:
|
|
||||||
self.write_metadata(metadatas)
|
|
||||||
|
|
||||||
# write the block
|
|
||||||
return backend.query.store_block(self.connection, block_dict)
|
|
||||||
|
|
||||||
def get_assets(self, asset_ids):
|
|
||||||
"""Return a list of assets that match the asset_ids
|
|
||||||
|
|
||||||
Args:
|
|
||||||
asset_ids (:obj:`list` of :obj:`str`): A list of asset_ids to
|
|
||||||
retrieve from the database.
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
list: The list of assets returned from the database.
|
|
||||||
"""
|
|
||||||
return backend.query.get_assets(self.connection, asset_ids)
|
|
||||||
|
|
||||||
def get_metadata(self, txn_ids):
|
|
||||||
"""Return a list of metadata that match the transaction ids (txn_ids)
|
|
||||||
|
|
||||||
Args:
|
|
||||||
txn_ids (:obj:`list` of :obj:`str`): A list of txn_ids to
|
|
||||||
retrieve from the database.
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
list: The list of metadata returned from the database.
|
|
||||||
"""
|
|
||||||
return backend.query.get_metadata(self.connection, txn_ids)
|
|
||||||
|
|
||||||
def write_assets(self, assets):
|
|
||||||
"""Writes a list of assets into the database.
|
|
||||||
|
|
||||||
Args:
|
|
||||||
assets (:obj:`list` of :obj:`dict`): A list of assets to write to
|
|
||||||
the database.
|
|
||||||
"""
|
|
||||||
return backend.query.store_assets(self.connection, assets)
|
|
||||||
|
|
||||||
def write_metadata(self, metadata):
|
|
||||||
"""Writes a list of metadata into the database.
|
|
||||||
|
|
||||||
Args:
|
|
||||||
metadata (:obj:`list` of :obj:`dict`): A list of metadata to write to
|
|
||||||
the database.
|
|
||||||
"""
|
|
||||||
return backend.query.write_metadata(self.connection, metadata)
|
|
||||||
|
|
||||||
def text_search(self, search, *, limit=0, table='assets'):
|
|
||||||
"""Return an iterator of assets that match the text search
|
|
||||||
|
|
||||||
Args:
|
|
||||||
search (str): Text search string to query the text index
|
|
||||||
limit (int, optional): Limit the number of returned documents.
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
iter: An iterator of assets that match the text search.
|
|
||||||
"""
|
|
||||||
objects = backend.query.text_search(self.connection, search, limit=limit,
|
|
||||||
table=table)
|
|
||||||
|
|
||||||
# TODO: This is not efficient. There may be a more efficient way to
|
|
||||||
# query by storing block ids with the assets and using fastquery.
|
|
||||||
# See https://github.com/bigchaindb/bigchaindb/issues/1496
|
|
||||||
for obj in objects:
|
|
||||||
tx, status = self.get_transaction(obj['id'], True)
|
|
||||||
if status == self.TX_VALID:
|
|
||||||
yield obj
|
|
@ -14,7 +14,7 @@ class Transaction(Transaction):
|
|||||||
"""Validate transaction spend
|
"""Validate transaction spend
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
bigchain (Bigchain): an instantiated bigchaindb.Bigchain object.
|
bigchain (BigchainDB): an instantiated bigchaindb.tendermint.BigchainDB object.
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
The transaction (Transaction) if the transaction is valid else it
|
The transaction (Transaction) if the transaction is valid else it
|
||||||
@ -108,8 +108,8 @@ class Transaction(Transaction):
|
|||||||
asset from the asset table and reconstructs the transaction.
|
asset from the asset table and reconstructs the transaction.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
bigchain (:class:`~bigchaindb.Bigchain`): An instance of Bigchain
|
bigchain (:class:`~bigchaindb.tendermint.BigchainDB`): An instance
|
||||||
used to perform database queries.
|
of BigchainDB used to perform database queries.
|
||||||
tx_dict_list (:list:`dict` or :obj:`dict`): The transaction dict or
|
tx_dict_list (:list:`dict` or :obj:`dict`): The transaction dict or
|
||||||
list of transaction dict as returned from the database.
|
list of transaction dict as returned from the database.
|
||||||
|
|
||||||
|
@ -14,9 +14,9 @@ except ImportError:
|
|||||||
from sha3 import sha3_256
|
from sha3 import sha3_256
|
||||||
|
|
||||||
import requests
|
import requests
|
||||||
|
|
||||||
import bigchaindb
|
import bigchaindb
|
||||||
from bigchaindb import backend, config_utils
|
from bigchaindb import backend, config_utils
|
||||||
from bigchaindb import Bigchain
|
|
||||||
from bigchaindb.models import Transaction
|
from bigchaindb.models import Transaction
|
||||||
from bigchaindb.common.exceptions import (SchemaValidationError,
|
from bigchaindb.common.exceptions import (SchemaValidationError,
|
||||||
ValidationError,
|
ValidationError,
|
||||||
@ -24,15 +24,45 @@ from bigchaindb.common.exceptions import (SchemaValidationError,
|
|||||||
from bigchaindb.tendermint.utils import encode_transaction, merkleroot
|
from bigchaindb.tendermint.utils import encode_transaction, merkleroot
|
||||||
from bigchaindb.tendermint import fastquery
|
from bigchaindb.tendermint import fastquery
|
||||||
from bigchaindb import exceptions as core_exceptions
|
from bigchaindb import exceptions as core_exceptions
|
||||||
|
from bigchaindb.consensus import BaseConsensusRules
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
class BigchainDB(Bigchain):
|
class BigchainDB(object):
|
||||||
|
"""Bigchain API
|
||||||
|
|
||||||
def __init__(self, connection=None, **kwargs):
|
Create, read, sign, write transactions to the database
|
||||||
super().__init__(**kwargs)
|
"""
|
||||||
|
|
||||||
|
BLOCK_INVALID = 'invalid'
|
||||||
|
"""return if a block is invalid"""
|
||||||
|
|
||||||
|
BLOCK_VALID = TX_VALID = 'valid'
|
||||||
|
"""return if a block is valid, or tx is in valid block"""
|
||||||
|
|
||||||
|
BLOCK_UNDECIDED = TX_UNDECIDED = 'undecided'
|
||||||
|
"""return if block is undecided, or tx is in undecided block"""
|
||||||
|
|
||||||
|
TX_IN_BACKLOG = 'backlog'
|
||||||
|
"""return if transaction is in backlog"""
|
||||||
|
|
||||||
|
def __init__(self, connection=None):
|
||||||
|
"""Initialize the Bigchain instance
|
||||||
|
|
||||||
|
A Bigchain instance has several configuration parameters (e.g. host).
|
||||||
|
If a parameter value is passed as an argument to the Bigchain
|
||||||
|
__init__ method, then that is the value it will have.
|
||||||
|
Otherwise, the parameter value will come from an environment variable.
|
||||||
|
If that environment variable isn't set, then the value
|
||||||
|
will come from the local configuration file. And if that variable
|
||||||
|
isn't in the local configuration file, then the parameter will have
|
||||||
|
its default value (defined in bigchaindb.__init__).
|
||||||
|
|
||||||
|
Args:
|
||||||
|
connection (:class:`~bigchaindb.backend.connection.Connection`):
|
||||||
|
A connection to the database.
|
||||||
|
"""
|
||||||
config_utils.autoconfigure()
|
config_utils.autoconfigure()
|
||||||
self.mode_list = ('broadcast_tx_async',
|
self.mode_list = ('broadcast_tx_async',
|
||||||
'broadcast_tx_sync',
|
'broadcast_tx_sync',
|
||||||
@ -40,12 +70,20 @@ class BigchainDB(Bigchain):
|
|||||||
self.tendermint_host = bigchaindb.config['tendermint']['host']
|
self.tendermint_host = bigchaindb.config['tendermint']['host']
|
||||||
self.tendermint_port = bigchaindb.config['tendermint']['port']
|
self.tendermint_port = bigchaindb.config['tendermint']['port']
|
||||||
self.endpoint = 'http://{}:{}/'.format(self.tendermint_host, self.tendermint_port)
|
self.endpoint = 'http://{}:{}/'.format(self.tendermint_host, self.tendermint_port)
|
||||||
|
|
||||||
|
consensusPlugin = bigchaindb.config.get('consensus_plugin')
|
||||||
|
|
||||||
|
if consensusPlugin:
|
||||||
|
self.consensus = config_utils.load_consensus_plugin(consensusPlugin)
|
||||||
|
else:
|
||||||
|
self.consensus = BaseConsensusRules
|
||||||
|
|
||||||
self.connection = connection if connection else backend.connect(**bigchaindb.config['database'])
|
self.connection = connection if connection else backend.connect(**bigchaindb.config['database'])
|
||||||
|
|
||||||
def post_transaction(self, transaction, mode):
|
def post_transaction(self, transaction, mode):
|
||||||
"""Submit a valid transaction to the mempool."""
|
"""Submit a valid transaction to the mempool."""
|
||||||
if not mode or mode not in self.mode_list:
|
if not mode or mode not in self.mode_list:
|
||||||
raise ValidationError(('Mode must be one of the following {}.')
|
raise ValidationError('Mode must be one of the following {}.'
|
||||||
.format(', '.join(self.mode_list)))
|
.format(', '.join(self.mode_list)))
|
||||||
|
|
||||||
payload = {
|
payload = {
|
||||||
@ -86,7 +124,7 @@ class BigchainDB(Bigchain):
|
|||||||
# else:
|
# else:
|
||||||
# return (500, 'Error while validating the transaction')
|
# return (500, 'Error while validating the transaction')
|
||||||
|
|
||||||
def _process_status_code(self, status_code, failure_msg):
|
def process_status_code(self, status_code, failure_msg):
|
||||||
return (202, '') if status_code == 0 else (500, failure_msg)
|
return (202, '') if status_code == 0 else (500, failure_msg)
|
||||||
|
|
||||||
def store_transaction(self, transaction):
|
def store_transaction(self, transaction):
|
||||||
@ -237,6 +275,37 @@ class BigchainDB(Bigchain):
|
|||||||
else:
|
else:
|
||||||
return transaction
|
return transaction
|
||||||
|
|
||||||
|
def get_transactions_filtered(self, asset_id, operation=None):
|
||||||
|
"""Get a list of transactions filtered on some criteria
|
||||||
|
"""
|
||||||
|
txids = backend.query.get_txids_filtered(self.connection, asset_id,
|
||||||
|
operation)
|
||||||
|
for txid in txids:
|
||||||
|
tx, status = self.get_transaction(txid, True)
|
||||||
|
if status == self.TX_VALID:
|
||||||
|
yield tx
|
||||||
|
|
||||||
|
def get_outputs_filtered(self, owner, spent=None):
|
||||||
|
"""Get a list of output links filtered on some criteria
|
||||||
|
|
||||||
|
Args:
|
||||||
|
owner (str): base58 encoded public_key.
|
||||||
|
spent (bool): If ``True`` return only the spent outputs. If
|
||||||
|
``False`` return only unspent outputs. If spent is
|
||||||
|
not specified (``None``) return all outputs.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
:obj:`list` of TransactionLink: list of ``txid`` s and ``output`` s
|
||||||
|
pointing to another transaction's condition
|
||||||
|
"""
|
||||||
|
outputs = self.fastquery.get_outputs_by_public_key(owner)
|
||||||
|
if spent is None:
|
||||||
|
return outputs
|
||||||
|
elif spent is True:
|
||||||
|
return self.fastquery.filter_unspent_outputs(outputs)
|
||||||
|
elif spent is False:
|
||||||
|
return self.fastquery.filter_spent_outputs(outputs)
|
||||||
|
|
||||||
def get_spent(self, txid, output, current_transactions=[]):
|
def get_spent(self, txid, output, current_transactions=[]):
|
||||||
transactions = backend.query.get_spent(self.connection, txid,
|
transactions = backend.query.get_spent(self.connection, txid,
|
||||||
output)
|
output)
|
||||||
@ -343,6 +412,51 @@ class BigchainDB(Bigchain):
|
|||||||
logger.warning('Invalid transaction (%s): %s', type(e).__name__, e)
|
logger.warning('Invalid transaction (%s): %s', type(e).__name__, e)
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
def text_search(self, search, *, limit=0, table='assets'):
|
||||||
|
"""Return an iterator of assets that match the text search
|
||||||
|
|
||||||
|
Args:
|
||||||
|
search (str): Text search string to query the text index
|
||||||
|
limit (int, optional): Limit the number of returned documents.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
iter: An iterator of assets that match the text search.
|
||||||
|
"""
|
||||||
|
objects = backend.query.text_search(self.connection, search, limit=limit,
|
||||||
|
table=table)
|
||||||
|
|
||||||
|
# TODO: This is not efficient. There may be a more efficient way to
|
||||||
|
# query by storing block ids with the assets and using fastquery.
|
||||||
|
# See https://github.com/bigchaindb/bigchaindb/issues/1496
|
||||||
|
for obj in objects:
|
||||||
|
tx, status = self.get_transaction(obj['id'], True)
|
||||||
|
if status == self.TX_VALID:
|
||||||
|
yield obj
|
||||||
|
|
||||||
|
def get_assets(self, asset_ids):
|
||||||
|
"""Return a list of assets that match the asset_ids
|
||||||
|
|
||||||
|
Args:
|
||||||
|
asset_ids (:obj:`list` of :obj:`str`): A list of asset_ids to
|
||||||
|
retrieve from the database.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
list: The list of assets returned from the database.
|
||||||
|
"""
|
||||||
|
return backend.query.get_assets(self.connection, asset_ids)
|
||||||
|
|
||||||
|
def get_metadata(self, txn_ids):
|
||||||
|
"""Return a list of metadata that match the transaction ids (txn_ids)
|
||||||
|
|
||||||
|
Args:
|
||||||
|
txn_ids (:obj:`list` of :obj:`str`): A list of txn_ids to
|
||||||
|
retrieve from the database.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
list: The list of metadata returned from the database.
|
||||||
|
"""
|
||||||
|
return backend.query.get_metadata(self.connection, txn_ids)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def fastquery(self):
|
def fastquery(self):
|
||||||
return fastquery.FastQuery(self.connection)
|
return fastquery.FastQuery(self.connection)
|
||||||
|
@ -11,7 +11,7 @@ from flask_cors import CORS
|
|||||||
import gunicorn.app.base
|
import gunicorn.app.base
|
||||||
|
|
||||||
from bigchaindb import utils
|
from bigchaindb import utils
|
||||||
from bigchaindb import Bigchain
|
from bigchaindb.tendermint import BigchainDB
|
||||||
from bigchaindb.web.routes import add_routes
|
from bigchaindb.web.routes import add_routes
|
||||||
from bigchaindb.web.strip_content_type_middleware import StripContentTypeMiddleware
|
from bigchaindb.web.strip_content_type_middleware import StripContentTypeMiddleware
|
||||||
|
|
||||||
@ -67,7 +67,7 @@ def create_app(*, debug=False, threads=1, bigchaindb_factory=None):
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
if not bigchaindb_factory:
|
if not bigchaindb_factory:
|
||||||
bigchaindb_factory = Bigchain
|
bigchaindb_factory = BigchainDB
|
||||||
|
|
||||||
app = Flask(__name__)
|
app = Flask(__name__)
|
||||||
app.wsgi_app = StripContentTypeMiddleware(app.wsgi_app)
|
app.wsgi_app = StripContentTypeMiddleware(app.wsgi_app)
|
||||||
|
@ -5,7 +5,7 @@ import os
|
|||||||
import os.path
|
import os.path
|
||||||
|
|
||||||
from bigchaindb.common.transaction import Transaction, Input, TransactionLink
|
from bigchaindb.common.transaction import Transaction, Input, TransactionLink
|
||||||
from bigchaindb.core import Bigchain
|
from bigchaindb.tendermint import BigchainDB
|
||||||
from bigchaindb.tendermint import lib
|
from bigchaindb.tendermint import lib
|
||||||
from bigchaindb.web import server
|
from bigchaindb.web import server
|
||||||
|
|
||||||
|
@ -8,6 +8,7 @@ Tendermint Integration
|
|||||||
|
|
||||||
.. automodule:: bigchaindb.tendermint.lib
|
.. automodule:: bigchaindb.tendermint.lib
|
||||||
:special-members: __init__
|
:special-members: __init__
|
||||||
|
:noindex:
|
||||||
|
|
||||||
.. automodule:: bigchaindb.tendermint.core
|
.. automodule:: bigchaindb.tendermint.core
|
||||||
:special-members: __init__
|
:special-members: __init__
|
||||||
|
@ -90,7 +90,7 @@ def test_bigchain_run_init_when_db_exists(mocker, capsys):
|
|||||||
def test__run_init(mocker):
|
def test__run_init(mocker):
|
||||||
from bigchaindb.commands.bigchaindb import _run_init
|
from bigchaindb.commands.bigchaindb import _run_init
|
||||||
bigchain_mock = mocker.patch(
|
bigchain_mock = mocker.patch(
|
||||||
'bigchaindb.commands.bigchaindb.bigchaindb.tendermint.lib.BigchainDB')
|
'bigchaindb.commands.bigchaindb.bigchaindb.tendermint.BigchainDB')
|
||||||
init_db_mock = mocker.patch(
|
init_db_mock = mocker.patch(
|
||||||
'bigchaindb.commands.bigchaindb.schema.init_database',
|
'bigchaindb.commands.bigchaindb.schema.init_database',
|
||||||
autospec=True,
|
autospec=True,
|
||||||
|
@ -280,7 +280,7 @@ class TestBigchainApi(object):
|
|||||||
|
|
||||||
@pytest.mark.usefixtures('inputs')
|
@pytest.mark.usefixtures('inputs')
|
||||||
def test_write_transaction(self, b, user_pk, user_sk):
|
def test_write_transaction(self, b, user_pk, user_sk):
|
||||||
from bigchaindb import Bigchain
|
from bigchaindb.tendermint import BigchainDB
|
||||||
from bigchaindb.models import Transaction
|
from bigchaindb.models import Transaction
|
||||||
|
|
||||||
input_tx = b.get_owned_ids(user_pk).pop()
|
input_tx = b.get_owned_ids(user_pk).pop()
|
||||||
@ -294,7 +294,7 @@ class TestBigchainApi(object):
|
|||||||
tx_from_db, status = b.get_transaction(tx.id, include_status=True)
|
tx_from_db, status = b.get_transaction(tx.id, include_status=True)
|
||||||
|
|
||||||
assert tx_from_db.to_dict() == tx.to_dict()
|
assert tx_from_db.to_dict() == tx.to_dict()
|
||||||
assert status == Bigchain.TX_IN_BACKLOG
|
assert status == BigchainDB.TX_IN_BACKLOG
|
||||||
|
|
||||||
@pytest.mark.usefixtures('inputs')
|
@pytest.mark.usefixtures('inputs')
|
||||||
def test_read_transaction(self, b, user_pk, user_sk):
|
def test_read_transaction(self, b, user_pk, user_sk):
|
||||||
@ -439,7 +439,7 @@ class TestBigchainApi(object):
|
|||||||
from bigchaindb.common.exceptions import InputDoesNotExist
|
from bigchaindb.common.exceptions import InputDoesNotExist
|
||||||
from bigchaindb.common.transaction import Input, TransactionLink
|
from bigchaindb.common.transaction import Input, TransactionLink
|
||||||
from bigchaindb.models import Transaction
|
from bigchaindb.models import Transaction
|
||||||
from bigchaindb import Bigchain
|
from bigchaindb.tendermint import BigchainDB
|
||||||
|
|
||||||
# Create an input for a non existing transaction
|
# Create an input for a non existing transaction
|
||||||
input = Input(Ed25519Sha256(public_key=b58decode(user_pk)),
|
input = Input(Ed25519Sha256(public_key=b58decode(user_pk)),
|
||||||
@ -449,7 +449,7 @@ class TestBigchainApi(object):
|
|||||||
asset_id='mock_asset_link')
|
asset_id='mock_asset_link')
|
||||||
|
|
||||||
with pytest.raises(InputDoesNotExist):
|
with pytest.raises(InputDoesNotExist):
|
||||||
tx.validate(Bigchain())
|
tx.validate(BigchainDB())
|
||||||
|
|
||||||
def test_count_backlog(self, b, user_pk, alice):
|
def test_count_backlog(self, b, user_pk, alice):
|
||||||
from bigchaindb.backend import query
|
from bigchaindb.backend import query
|
||||||
@ -970,9 +970,9 @@ class TestMultipleInputs(object):
|
|||||||
|
|
||||||
|
|
||||||
def test_get_owned_ids_calls_get_outputs_filtered():
|
def test_get_owned_ids_calls_get_outputs_filtered():
|
||||||
from bigchaindb.core import Bigchain
|
from bigchaindb.tendermint import BigchainDB
|
||||||
with patch('bigchaindb.core.Bigchain.get_outputs_filtered') as gof:
|
with patch('bigchaindb.tendermint.BigchainDB.get_outputs_filtered') as gof:
|
||||||
b = Bigchain()
|
b = BigchainDB()
|
||||||
res = b.get_owned_ids('abc')
|
res = b.get_owned_ids('abc')
|
||||||
gof.assert_called_once_with('abc', spent=False)
|
gof.assert_called_once_with('abc', spent=False)
|
||||||
assert res == gof()
|
assert res == gof()
|
||||||
|
@ -35,6 +35,7 @@ def test_bigchain_instance_raises_when_not_configured(request, monkeypatch):
|
|||||||
import bigchaindb
|
import bigchaindb
|
||||||
from bigchaindb import config_utils
|
from bigchaindb import config_utils
|
||||||
from bigchaindb.common import exceptions
|
from bigchaindb.common import exceptions
|
||||||
|
from bigchaindb.tendermint import BigchainDB
|
||||||
assert 'CONFIGURED' not in bigchaindb.config
|
assert 'CONFIGURED' not in bigchaindb.config
|
||||||
|
|
||||||
# We need to disable ``bigchaindb.config_utils.autoconfigure`` to avoid reading
|
# We need to disable ``bigchaindb.config_utils.autoconfigure`` to avoid reading
|
||||||
@ -42,7 +43,7 @@ def test_bigchain_instance_raises_when_not_configured(request, monkeypatch):
|
|||||||
monkeypatch.setattr(config_utils, 'autoconfigure', lambda: 0)
|
monkeypatch.setattr(config_utils, 'autoconfigure', lambda: 0)
|
||||||
|
|
||||||
with pytest.raises(exceptions.ConfigurationError):
|
with pytest.raises(exceptions.ConfigurationError):
|
||||||
bigchaindb.Bigchain()
|
BigchainDB()
|
||||||
|
|
||||||
|
|
||||||
def test_load_consensus_plugin_loads_default_rules_without_name():
|
def test_load_consensus_plugin_loads_default_rules_without_name():
|
||||||
|
@ -26,10 +26,10 @@ def config(request, monkeypatch):
|
|||||||
|
|
||||||
|
|
||||||
def test_bigchain_class_default_initialization(config):
|
def test_bigchain_class_default_initialization(config):
|
||||||
from bigchaindb.core import Bigchain
|
from bigchaindb.tendermint import BigchainDB
|
||||||
from bigchaindb.consensus import BaseConsensusRules
|
from bigchaindb.consensus import BaseConsensusRules
|
||||||
from bigchaindb.backend.connection import Connection
|
from bigchaindb.backend.connection import Connection
|
||||||
bigchain = Bigchain()
|
bigchain = BigchainDB()
|
||||||
assert isinstance(bigchain.connection, Connection)
|
assert isinstance(bigchain.connection, Connection)
|
||||||
assert bigchain.connection.host == config['database']['host']
|
assert bigchain.connection.host == config['database']['host']
|
||||||
assert bigchain.connection.port == config['database']['port']
|
assert bigchain.connection.port == config['database']['port']
|
||||||
@ -38,7 +38,7 @@ def test_bigchain_class_default_initialization(config):
|
|||||||
|
|
||||||
|
|
||||||
def test_bigchain_class_initialization_with_parameters(config):
|
def test_bigchain_class_initialization_with_parameters(config):
|
||||||
from bigchaindb.core import Bigchain
|
from bigchaindb.tendermint import BigchainDB
|
||||||
from bigchaindb.backend import connect
|
from bigchaindb.backend import connect
|
||||||
from bigchaindb.consensus import BaseConsensusRules
|
from bigchaindb.consensus import BaseConsensusRules
|
||||||
init_db_kwargs = {
|
init_db_kwargs = {
|
||||||
@ -48,7 +48,7 @@ def test_bigchain_class_initialization_with_parameters(config):
|
|||||||
'name': 'this_is_the_db_name',
|
'name': 'this_is_the_db_name',
|
||||||
}
|
}
|
||||||
connection = connect(**init_db_kwargs)
|
connection = connect(**init_db_kwargs)
|
||||||
bigchain = Bigchain(connection=connection, **init_db_kwargs)
|
bigchain = BigchainDB(connection=connection, **init_db_kwargs)
|
||||||
assert bigchain.connection == connection
|
assert bigchain.connection == connection
|
||||||
assert bigchain.connection.host == init_db_kwargs['host']
|
assert bigchain.connection.host == init_db_kwargs['host']
|
||||||
assert bigchain.connection.port == init_db_kwargs['port']
|
assert bigchain.connection.port == init_db_kwargs['port']
|
||||||
@ -58,13 +58,13 @@ def test_bigchain_class_initialization_with_parameters(config):
|
|||||||
|
|
||||||
def test_get_blocks_status_containing_tx(monkeypatch):
|
def test_get_blocks_status_containing_tx(monkeypatch):
|
||||||
from bigchaindb.backend import query as backend_query
|
from bigchaindb.backend import query as backend_query
|
||||||
from bigchaindb.core import Bigchain
|
from bigchaindb.tendermint import BigchainDB
|
||||||
blocks = [
|
blocks = [
|
||||||
{'id': 1}, {'id': 2}
|
{'id': 1}, {'id': 2}
|
||||||
]
|
]
|
||||||
monkeypatch.setattr(backend_query, 'get_blocks_status_from_transaction', lambda x: blocks)
|
monkeypatch.setattr(backend_query, 'get_blocks_status_from_transaction', lambda x: blocks)
|
||||||
monkeypatch.setattr(Bigchain, 'block_election_status', lambda x, y, z: Bigchain.BLOCK_VALID)
|
monkeypatch.setattr(BigchainDB, 'block_election_status', lambda x, y, z: BigchainDB.BLOCK_VALID)
|
||||||
bigchain = Bigchain(public_key='pubkey', private_key='privkey')
|
bigchain = BigchainDB(public_key='pubkey', private_key='privkey')
|
||||||
with pytest.raises(Exception):
|
with pytest.raises(Exception):
|
||||||
bigchain.get_blocks_status_containing_tx('txid')
|
bigchain.get_blocks_status_containing_tx('txid')
|
||||||
|
|
||||||
|
@ -372,7 +372,7 @@ def test_transactions_get_list_good(client):
|
|||||||
|
|
||||||
asset_id = '1' * 64
|
asset_id = '1' * 64
|
||||||
|
|
||||||
with patch('bigchaindb.core.Bigchain.get_transactions_filtered', get_txs_patched):
|
with patch('bigchaindb.tendermint.BigchainDB.get_transactions_filtered', get_txs_patched):
|
||||||
url = TX_ENDPOINT + '?asset_id=' + asset_id
|
url = TX_ENDPOINT + '?asset_id=' + asset_id
|
||||||
assert client.get(url).json == [
|
assert client.get(url).json == [
|
||||||
['asset_id', asset_id],
|
['asset_id', asset_id],
|
||||||
@ -389,7 +389,7 @@ def test_transactions_get_list_good(client):
|
|||||||
def test_transactions_get_list_bad(client):
|
def test_transactions_get_list_bad(client):
|
||||||
def should_not_be_called():
|
def should_not_be_called():
|
||||||
assert False
|
assert False
|
||||||
with patch('bigchaindb.core.Bigchain.get_transactions_filtered',
|
with patch('bigchaindb.tendermint.BigchainDB.get_transactions_filtered',
|
||||||
lambda *_, **__: should_not_be_called()):
|
lambda *_, **__: should_not_be_called()):
|
||||||
# Test asset id validated
|
# Test asset id validated
|
||||||
url = TX_ENDPOINT + '?asset_id=' + '1' * 63
|
url = TX_ENDPOINT + '?asset_id=' + '1' * 63
|
||||||
@ -404,7 +404,7 @@ def test_transactions_get_list_bad(client):
|
|||||||
|
|
||||||
@pytest.mark.tendermint
|
@pytest.mark.tendermint
|
||||||
def test_return_only_valid_transaction(client):
|
def test_return_only_valid_transaction(client):
|
||||||
from bigchaindb import Bigchain
|
from bigchaindb.tendermint import BigchainDB
|
||||||
|
|
||||||
def get_transaction_patched(status):
|
def get_transaction_patched(status):
|
||||||
def inner(self, tx_id, include_status):
|
def inner(self, tx_id, include_status):
|
||||||
@ -415,13 +415,13 @@ def test_return_only_valid_transaction(client):
|
|||||||
# UNDECIDED or VALID block, as well as transactions from the backlog.
|
# UNDECIDED or VALID block, as well as transactions from the backlog.
|
||||||
# As the endpoint uses `get_transaction`, we don't have to test
|
# As the endpoint uses `get_transaction`, we don't have to test
|
||||||
# against invalid transactions here.
|
# against invalid transactions here.
|
||||||
with patch('bigchaindb.core.Bigchain.get_transaction',
|
with patch('bigchaindb.tendermint.BigchainDB.get_transaction',
|
||||||
get_transaction_patched(Bigchain.TX_UNDECIDED)):
|
get_transaction_patched(BigchainDB.TX_UNDECIDED)):
|
||||||
url = '{}{}'.format(TX_ENDPOINT, '123')
|
url = '{}{}'.format(TX_ENDPOINT, '123')
|
||||||
assert client.get(url).status_code == 404
|
assert client.get(url).status_code == 404
|
||||||
|
|
||||||
with patch('bigchaindb.core.Bigchain.get_transaction',
|
with patch('bigchaindb.tendermint.BigchainDB.get_transaction',
|
||||||
get_transaction_patched(Bigchain.TX_IN_BACKLOG)):
|
get_transaction_patched(BigchainDB.TX_IN_BACKLOG)):
|
||||||
url = '{}{}'.format(TX_ENDPOINT, '123')
|
url = '{}{}'.format(TX_ENDPOINT, '123')
|
||||||
assert client.get(url).status_code == 404
|
assert client.get(url).status_code == 404
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user