From 98084f6f4af92d2687d2bc812e792ce11d94430b Mon Sep 17 00:00:00 2001 From: Rodolphe Marques Date: Fri, 11 Nov 2016 17:36:27 +0100 Subject: [PATCH] get_transaction_by_metadata_id now ignores invalid transactions --- bigchaindb/core.py | 28 ++++++++++++++++++---------- bigchaindb/db/backends/rethinkdb.py | 22 +++++++++++++--------- tests/db/test_bigchain_api.py | 27 +++++++++++++++++++-------- 3 files changed, 50 insertions(+), 27 deletions(-) diff --git a/bigchaindb/core.py b/bigchaindb/core.py index 7711514a..d2d98502 100644 --- a/bigchaindb/core.py +++ b/bigchaindb/core.py @@ -329,24 +329,32 @@ class Bigchain(object): else: return None - def get_tx_by_metadata_id(self, metadata_id): - """Retrieves transactions related to a metadata. + def get_transaction_by_metadata_id(self, metadata_id): + """Retrieves valid or undecided transactions related to a particular + 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. + 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. - To make it easy to query the bigchain for that particular metadata we create a UUID for the metadata and - store it with the transaction. + To make it easy to query the bigchain for that particular metadata we + create a UUID for the metadata and store it with the transaction. Args: metadata_id (str): the id for this particular metadata. Returns: - A list of transactions containing that metadata. If no transaction exists with that metadata it - returns an empty list `[]` + A list of valid or undecided transactions containing that metadata. + If no transaction exists with that metadata it returns an empty + list `[]` """ - cursor = self.backend.get_transactions_by_metadata_id(metadata_id) - return [Transaction.from_dict(tx) for tx in cursor] + txids = self.backend.get_txids_by_metadata_id(metadata_id) + transactions = [] + for txid in txids: + tx = self.get_transaction(txid) + if tx: + transactions.append(tx) + return transactions def get_txs_by_asset_id(self, asset_id): """Retrieves transactions related to a particular asset. diff --git a/bigchaindb/db/backends/rethinkdb.py b/bigchaindb/db/backends/rethinkdb.py index 5b73cce6..3423abc6 100644 --- a/bigchaindb/db/backends/rethinkdb.py +++ b/bigchaindb/db/backends/rethinkdb.py @@ -138,27 +138,31 @@ class RethinkDBBackend: .get_all(transaction_id, index='transaction_id') .pluck('votes', 'id', {'block': ['voters']})) - def get_transactions_by_metadata_id(self, metadata_id): - """Retrieves transactions related to a metadata. + def get_txids_by_metadata_id(self, metadata_id): + """Retrieves transaction ids related to a particular 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. + 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. - To make it easy to query the bigchain for that particular metadata we create a UUID for the metadata and - store it with the transaction. + To make it easy to query the bigchain for that particular metadata we + create a UUID for the metadata and store it with the transaction. Args: metadata_id (str): the id for this particular metadata. Returns: - A list of transactions containing that metadata. If no transaction exists with that metadata it - returns an empty list `[]` + A list of transaction ids containing that metadata. If no + transaction exists with that metadata it returns an empty list `[]` """ return self.connection.run( r.table('bigchain', read_mode=self.read_mode) .get_all(metadata_id, index='metadata_id') .concat_map(lambda block: block['block']['transactions']) - .filter(lambda transaction: transaction['transaction']['metadata']['id'] == metadata_id)) + .filter(lambda transaction: + transaction['transaction']['metadata']['id'] == + metadata_id) + .get_field('id')) def get_transactions_by_asset_id(self, asset_id): """Retrieves transactions related to a particular asset. diff --git a/tests/db/test_bigchain_api.py b/tests/db/test_bigchain_api.py index 314286c6..341598b3 100644 --- a/tests/db/test_bigchain_api.py +++ b/tests/db/test_bigchain_api.py @@ -88,11 +88,6 @@ class TestBigchainApi(object): assert b.has_previous_vote(block.id, block.voters) is True - - def test_get_transactions_for_metadata_mismatch(self, b): - matches = b.get_tx_by_metadata_id('missing') - assert not matches - def test_get_spent_with_double_spend(self, b, monkeypatch): from bigchaindb.common.exceptions import DoubleSpend from bigchaindb.models import Transaction @@ -190,12 +185,28 @@ class TestBigchainApi(object): block = b.create_block([tx]) b.write_block(block, durability='hard') - matches = b.get_tx_by_payload_uuid(tx.metadata.data_id) + matches = b.get_transaction_by_metadata_id(tx.metadata.data_id) assert len(matches) == 1 assert matches[0].id == tx.id - def test_get_transactions_for_metadata(self, b, user_vk): - matches = b.get_tx_by_metadata_id('missing') + @pytest.mark.usefixtures('inputs') + def test_get_transactions_for_metadata_invalid_block(self, b, user_vk): + from bigchaindb.models import Transaction + + metadata = {'msg': 'Hello BigchainDB!'} + tx = Transaction.create([b.me], [user_vk], metadata=metadata) + + block = b.create_block([tx]) + b.write_block(block, durability='hard') + # vote block invalid + vote = b.vote(block.id, b.get_last_voted_block().id, False) + b.write_vote(vote) + + matches = b.get_transaction_by_metadata_id(tx.metadata.data_id) + assert len(matches) == 0 + + def test_get_transactions_for_metadata_mismatch(self, b): + matches = b.get_transaction_by_metadata_id('missing') assert not matches @pytest.mark.usefixtures('inputs')