From b447a75a8dacd9ef186f1ad2aab3e2cd6bd6514a Mon Sep 17 00:00:00 2001 From: Rodolphe Marques Date: Wed, 24 Aug 2016 18:12:54 +0200 Subject: [PATCH] Added get_txs_by_asset_id Created secondary index for assets. Created tests --- bigchaindb/assets.py | 13 +++++++++++++ bigchaindb/core.py | 20 +++++++++++++++++-- bigchaindb/db/utils.py | 5 +++++ tests/assets/test_digital_assets.py | 30 +++++++++++++++++++++++++++++ tests/db/conftest.py | 5 +++++ 5 files changed, 71 insertions(+), 2 deletions(-) diff --git a/bigchaindb/assets.py b/bigchaindb/assets.py index e5fdd691..f30935b6 100644 --- a/bigchaindb/assets.py +++ b/bigchaindb/assets.py @@ -1,3 +1,5 @@ +import rethinkdb as r + from bigchaindb.exceptions import AssetIdMismatch, TransactionDoesNotExist, AmountError @@ -63,3 +65,14 @@ def validate_asset_creation(asset_data, divisible, updatable, refillable, amount if divisible or updatable or refillable or amount != 1: raise NotImplementedError("Divisible assets are not yet implemented!") + + +def get_transactions_by_asset_id(asset_id, bigchain, read_mode='majority'): + cursor = r.table('bigchain', read_mode=read_mode)\ + .get_all(asset_id, index='asset_id')\ + .concat_map(lambda block: block['block']['transactions'])\ + .filter(lambda transaction: transaction['transaction']['asset']['id'] == asset_id)\ + .run(bigchain.conn) + + transactions = list(cursor) + return transactions diff --git a/bigchaindb/core.py b/bigchaindb/core.py index 86ccfea8..9b07797e 100644 --- a/bigchaindb/core.py +++ b/bigchaindb/core.py @@ -11,8 +11,9 @@ from bigchaindb_common.transaction import TransactionLink import rethinkdb as r import bigchaindb + from bigchaindb.db.utils import Connection -from bigchaindb import config_utils, util +from bigchaindb import assets, config_utils, util from bigchaindb.consensus import BaseConsensusRules from bigchaindb.models import Block, Transaction @@ -326,7 +327,7 @@ class Bigchain(object): return None def get_tx_by_metadata_id(self, metadata_id): - """Retrieves transactions related to a payload. + """Retrieves transactions related to a metadata. When creating a transaction one of the optional arguments is the `metadata`. The metadata is a generic dict that contains extra information that can be appended to the transaction. @@ -350,6 +351,21 @@ class Bigchain(object): transactions = list(cursor) return [Transaction.from_dict(tx) for tx in transactions] + def get_txs_by_asset_id(self, asset_id): + """Retrieves transactions related to a particular asset. + + A digital asset in bigchaindb is identified by an uuid. This allows us to query all the transactions + related to a particular digital asset, knowing the id. + + Args: + asset_id (str): the id for this particular metadata. + + Returns: + A list of transactions containing related to the asset. If no transaction exists for that asset it + returns an empty list `[]` + """ + return assets.get_transactions_by_asset_id(asset_id, self, read_mode=self.read_mode) + def get_spent(self, txid, cid): """Check if a `txid` was already used as an input. diff --git a/bigchaindb/db/utils.py b/bigchaindb/db/utils.py index 73236dc1..0009b2c3 100644 --- a/bigchaindb/db/utils.py +++ b/bigchaindb/db/utils.py @@ -108,6 +108,11 @@ def create_bigchain_secondary_index(conn, dbname): .index_create('metadata_id', r.row['block']['transactions']['transaction']['metadata']['id'], multi=True)\ .run(conn) + # secondary index for asset uuid + r.db(dbname).table('bigchain')\ + .index_create('asset_id', + r.row['block']['transactions']['transaction']['asset']['id'], multi=True)\ + .run(conn) # wait for rethinkdb to finish creating secondary indexes r.db(dbname).table('bigchain').index_wait().run(conn) diff --git a/tests/assets/test_digital_assets.py b/tests/assets/test_digital_assets.py index e8007ddf..efe00ec8 100644 --- a/tests/assets/test_digital_assets.py +++ b/tests/assets/test_digital_assets.py @@ -160,3 +160,33 @@ def test_get_asset_id_transaction_does_not_exist(b, user_vk): with pytest.raises(TransactionDoesNotExist): b.create_transaction(user_vk, user_vk, {'txid': 'bored', 'cid': '0'}, 'TRANSFER') + + +@pytest.mark.usefixtures('inputs') +def test_get_txs_by_asset_id(b, user_vk, user_sk): + tx_input = b.get_owned_ids(user_vk).pop() + tx = b.get_transaction(tx_input['txid']) + asset_id = tx['transaction']['asset']['id'] + txs = b.get_txs_by_asset_id(asset_id) + + assert len(txs) == 1 + assert txs[0]['id'] == tx['id'] + assert txs[0]['transaction']['asset']['id'] == asset_id + + # create a transfer transaction + tx_transfer = b.create_transaction(user_vk, user_vk, tx_input, 'TRANSFER') + tx_transfer_signed = b.sign_transaction(tx_transfer, user_sk) + # create the block + block = b.create_block([tx_transfer_signed]) + b.write_block(block, durability='hard') + # vote the block valid + vote = b.vote(block['id'], b.get_last_voted_block()['id'], True) + b.write_vote(vote) + + txs = b.get_txs_by_asset_id(asset_id) + + assert len(txs) == 2 + assert tx['id'] in [t['id'] for t in txs] + assert tx_transfer['id'] in [t['id'] for t in txs] + assert asset_id == txs[0]['transaction']['asset']['id'] + assert asset_id == txs[1]['transaction']['asset']['id'] diff --git a/tests/db/conftest.py b/tests/db/conftest.py index 4268f51b..dbbe99ba 100644 --- a/tests/db/conftest.py +++ b/tests/db/conftest.py @@ -60,6 +60,11 @@ def setup_database(request, node_config): # compound index to order votes by block id and node r.db(db_name).table('votes').index_create('block_and_voter', [r.row['vote']['voting_for_block'], r.row['node_pubkey']]).run() + # secondary index for asset uuid + r.db(db_name).table('bigchain')\ + .index_create('asset_id', + r.row['block']['transactions']['transaction']['asset']['id'], multi=True)\ + .run() # order transactions by id r.db(db_name).table('bigchain').index_create('transaction_id', r.row['block']['transactions']['id'], multi=True).run()