diff --git a/bigchaindb/fastquery.py b/bigchaindb/fastquery.py deleted file mode 100644 index f2190cb4..00000000 --- a/bigchaindb/fastquery.py +++ /dev/null @@ -1,60 +0,0 @@ -from bigchaindb.utils import condition_details_has_owner -from bigchaindb.backend import query -from bigchaindb.common.transaction import TransactionLink - - -class FastQuery: - """Database queries that join on block results from a single node. - - * Votes are not validated for security (security is a replication concern) - * Votes come from only one node, and as such, non-byzantine fault tolerance - is reduced. - - Previously, to consider the status of a block, all votes for that block - were retrieved and the election results were counted. This meant that a - faulty node may still have been able to obtain a correct election result. - However, from the point of view of a client, it is still neccesary to - query multiple nodes to insure against getting an incorrect response from - a byzantine node. - """ - - def __init__(self, connection): - self.connection = connection - - def get_outputs_by_public_key(self, public_key): - """Get outputs for a public key""" - res = list(query.get_owned_ids(self.connection, public_key)) - txs = [tx for _, tx in self.filter_valid_items(res)] - return [TransactionLink(tx['id'], index) - for tx in txs - for index, output in enumerate(tx['outputs']) - if condition_details_has_owner(output['condition']['details'], - public_key)] - - def filter_spent_outputs(self, outputs): - """Remove outputs that have been spent - - Args: - outputs: list of TransactionLink - """ - links = [o.to_dict() for o in outputs] - res = query.get_spending_transactions(self.connection, links) - txs = [tx for _, tx in self.filter_valid_items(res)] - spends = {TransactionLink.from_dict(input_['fulfills']) - for tx in txs - for input_ in tx['inputs']} - return [ff for ff in outputs if ff not in spends] - - def filter_unspent_outputs(self, outputs): - """Remove outputs that have not been spent - - Args: - outputs: list of TransactionLink - """ - links = [o.to_dict() for o in outputs] - res = query.get_spending_transactions(self.connection, links) - txs = [tx for _, tx in self.filter_valid_items(res)] - spends = {TransactionLink.from_dict(input_['fulfills']) - for tx in txs - for input_ in tx['inputs']} - return [ff for ff in outputs if ff in spends] diff --git a/tests/db/test_bigchain_api.py b/tests/db/test_bigchain_api.py index 91d9cae6..b6c8a2ad 100644 --- a/tests/db/test_bigchain_api.py +++ b/tests/db/test_bigchain_api.py @@ -978,41 +978,51 @@ def test_get_owned_ids_calls_get_outputs_filtered(): assert res == gof() +@pytest.mark.tendermint def test_get_outputs_filtered_only_unspent(): from bigchaindb.common.transaction import TransactionLink - from bigchaindb.core import Bigchain - with patch('bigchaindb.fastquery.FastQuery.get_outputs_by_public_key') as get_outputs: + from bigchaindb.tendermint.lib import BigchainDB + + go = 'bigchaindb.tendermint.fastquery.FastQuery.get_outputs_by_public_key' + with patch(go) as get_outputs: get_outputs.return_value = [TransactionLink('a', 1), TransactionLink('b', 2)] - with patch('bigchaindb.fastquery.FastQuery.filter_spent_outputs') as filter_spent: + fs = 'bigchaindb.tendermint.fastquery.FastQuery.filter_spent_outputs' + with patch(fs) as filter_spent: filter_spent.return_value = [TransactionLink('b', 2)] - out = Bigchain().get_outputs_filtered('abc', spent=False) + out = BigchainDB().get_outputs_filtered('abc', spent=False) get_outputs.assert_called_once_with('abc') assert out == [TransactionLink('b', 2)] +@pytest.mark.tendermint def test_get_outputs_filtered_only_spent(): from bigchaindb.common.transaction import TransactionLink - from bigchaindb.core import Bigchain - with patch('bigchaindb.fastquery.FastQuery.get_outputs_by_public_key') as get_outputs: + from bigchaindb.tendermint.lib import BigchainDB + go = 'bigchaindb.tendermint.fastquery.FastQuery.get_outputs_by_public_key' + with patch(go) as get_outputs: get_outputs.return_value = [TransactionLink('a', 1), TransactionLink('b', 2)] - with patch('bigchaindb.fastquery.FastQuery.filter_unspent_outputs') as filter_spent: + fs = 'bigchaindb.tendermint.fastquery.FastQuery.filter_unspent_outputs' + with patch(fs) as filter_spent: filter_spent.return_value = [TransactionLink('b', 2)] - out = Bigchain().get_outputs_filtered('abc', spent=True) + out = BigchainDB().get_outputs_filtered('abc', spent=True) get_outputs.assert_called_once_with('abc') assert out == [TransactionLink('b', 2)] -@patch('bigchaindb.fastquery.FastQuery.filter_unspent_outputs') -@patch('bigchaindb.fastquery.FastQuery.filter_spent_outputs') +@pytest.mark.tendermint +@patch('bigchaindb.tendermint.fastquery.FastQuery.filter_unspent_outputs') +@patch('bigchaindb.tendermint.fastquery.FastQuery.filter_spent_outputs') def test_get_outputs_filtered(filter_spent, filter_unspent): from bigchaindb.common.transaction import TransactionLink - from bigchaindb.core import Bigchain - with patch('bigchaindb.fastquery.FastQuery.get_outputs_by_public_key') as get_outputs: + from bigchaindb.tendermint.lib import BigchainDB + + go = 'bigchaindb.tendermint.fastquery.FastQuery.get_outputs_by_public_key' + with patch(go) as get_outputs: get_outputs.return_value = [TransactionLink('a', 1), TransactionLink('b', 2)] - out = Bigchain().get_outputs_filtered('abc') + out = BigchainDB().get_outputs_filtered('abc') get_outputs.assert_called_once_with('abc') filter_spent.assert_not_called() filter_unspent.assert_not_called() diff --git a/tests/tendermint/test_fastquery.py b/tests/tendermint/test_fastquery.py index 8f807c9a..8689000b 100644 --- a/tests/tendermint/test_fastquery.py +++ b/tests/tendermint/test_fastquery.py @@ -3,6 +3,7 @@ import pytest from bigchaindb.common.transaction import TransactionLink from bigchaindb.models import Transaction + pytestmark = [pytest.mark.bdb, pytest.mark.tendermint] @@ -25,3 +26,46 @@ def test_get_outputs_by_public_key(b, user_pk, user2_pk, txns): TransactionLink(txns[0].id, 0), TransactionLink(txns[2].id, 1), ] + + +def test_filter_spent_outputs(b, user_pk, user_sk): + out = [([user_pk], 1)] + tx1 = Transaction.create([user_pk], out * 2) + tx1.sign([user_sk]) + + inputs = tx1.to_inputs() + + tx2 = Transaction.transfer([inputs[0]], out, tx1.id) + tx2.sign([user_sk]) + + # tx2 produces a new unspent. inputs[1] remains unspent. + b.store_bulk_transactions([tx1, tx2]) + + outputs = b.fastquery.get_outputs_by_public_key(user_pk) + unspents = b.fastquery.filter_spent_outputs(outputs) + + assert set(unsp for unsp in unspents) == { + inputs[1].fulfills, + tx2.to_inputs()[0].fulfills, + } + + +def test_filter_unspent_outputs(b, user_pk, user_sk): + out = [([user_pk], 1)] + tx1 = Transaction.create([user_pk], out * 2) + tx1.sign([user_sk]) + + inputs = tx1.to_inputs() + + tx2 = Transaction.transfer([inputs[0]], out, tx1.id) + tx2.sign([user_sk]) + + # tx2 produces a new unspent. input[1] remains unspent. + b.store_bulk_transactions([tx1, tx2]) + + outputs = b.fastquery.get_outputs_by_public_key(user_pk) + spents = b.fastquery.filter_unspent_outputs(outputs) + + assert set(sp for sp in spents) == { + inputs[0].fulfills, + } diff --git a/tests/test_fastquery.py b/tests/test_fastquery.py deleted file mode 100644 index e6c6dfbe..00000000 --- a/tests/test_fastquery.py +++ /dev/null @@ -1,21 +0,0 @@ -import pytest - -from bigchaindb.common.transaction import TransactionLink - -pytestmark = pytest.mark.bdb - - -def test_filter_valid_items(b, blockdata): - blocks, _ = blockdata - assert (b.fastquery.filter_valid_items(blocks, block_id_key=lambda b: b['id']) - == [blocks[0], blocks[1]]) - - -def test_get_outputs_by_public_key(b, user_pk, user2_pk, blockdata): - blocks, _ = blockdata - assert b.fastquery.get_outputs_by_public_key(user_pk) == [ - TransactionLink(blocks[1]['block']['transactions'][0]['id'], 0) - ] - assert b.fastquery.get_outputs_by_public_key(user2_pk) == [ - TransactionLink(blocks[0]['block']['transactions'][0]['id'], 0) - ]