mirror of
https://github.com/bigchaindb/bigchaindb.git
synced 2024-10-13 13:34:05 +00:00
Integrate output search api
This commit is contained in:
parent
1e104ad2c4
commit
2b3a9fa6f6
@ -111,3 +111,27 @@ def get_txids_filtered(conn, asset_id, operation=None):
|
||||
@register_query(LocalMongoDBConnection)
|
||||
def text_search(*args, **kwargs):
|
||||
return mongodb.query.text_search(*args, **kwargs)
|
||||
|
||||
|
||||
@register_query(LocalMongoDBConnection)
|
||||
def get_owned_ids(conn, owner):
|
||||
cursor = conn.run(
|
||||
conn.collection('transactions').aggregate([
|
||||
{'$match': {'outputs.public_keys': owner}},
|
||||
{'$project': {'_id': False}}
|
||||
]))
|
||||
return cursor
|
||||
|
||||
|
||||
@register_query(LocalMongoDBConnection)
|
||||
def get_spending_transactions(conn, inputs):
|
||||
cursor = conn.run(
|
||||
conn.collection('transactions').aggregate([
|
||||
{'$match': {
|
||||
'inputs.fulfills': {
|
||||
'$in': inputs,
|
||||
},
|
||||
}},
|
||||
{'$project': {'_id': False}}
|
||||
]))
|
||||
return cursor
|
||||
|
48
bigchaindb/tendermint/fastquery.py
Normal file
48
bigchaindb/tendermint/fastquery.py
Normal file
@ -0,0 +1,48 @@
|
||||
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.
|
||||
"""
|
||||
|
||||
def get_outputs_by_public_key(self, public_key):
|
||||
"""
|
||||
Get outputs for a public key
|
||||
"""
|
||||
txs = list(query.get_owned_ids(self.connection, public_key))
|
||||
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]
|
||||
txs = list(query.get_spending_transactions(self.connection, links))
|
||||
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]
|
||||
txs = list(query.get_spending_transactions(self.connection, links))
|
||||
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]
|
@ -11,6 +11,7 @@ from bigchaindb import Bigchain
|
||||
from bigchaindb.models import Transaction
|
||||
from bigchaindb.common.exceptions import SchemaValidationError, ValidationError
|
||||
from bigchaindb.tendermint.utils import encode_transaction
|
||||
from bigchaindb.tendermint import fastquery
|
||||
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
@ -117,5 +118,9 @@ class BigchainDB(Bigchain):
|
||||
return False
|
||||
return transaction
|
||||
|
||||
@property
|
||||
def fastquery(self):
|
||||
return fastquery.FastQuery(self.connection, self.me)
|
||||
|
||||
|
||||
Block = namedtuple('Block', ('app_hash', 'height'))
|
||||
|
@ -3,10 +3,9 @@ from copy import deepcopy
|
||||
import pytest
|
||||
import pymongo
|
||||
|
||||
pytestmark = [pytest.mark.tendermint, pytest.mark.localmongodb]
|
||||
pytestmark = [pytest.mark.tendermint, pytest.mark.localmongodb, pytest.mark.bdb]
|
||||
|
||||
|
||||
@pytest.mark.bdb
|
||||
def test_get_txids_filtered(signed_create_tx, signed_transfer_tx):
|
||||
from bigchaindb.backend import connect, query
|
||||
from bigchaindb.models import Transaction
|
||||
@ -32,7 +31,6 @@ def test_get_txids_filtered(signed_create_tx, signed_transfer_tx):
|
||||
assert txids == {signed_transfer_tx.id}
|
||||
|
||||
|
||||
@pytest.mark.bdb
|
||||
def test_write_assets():
|
||||
from bigchaindb.backend import connect, query
|
||||
conn = connect()
|
||||
@ -57,7 +55,6 @@ def test_write_assets():
|
||||
assert list(cursor) == assets[:-1]
|
||||
|
||||
|
||||
@pytest.mark.bdb
|
||||
def test_get_assets():
|
||||
from bigchaindb.backend import connect, query
|
||||
conn = connect()
|
||||
@ -74,8 +71,40 @@ def test_get_assets():
|
||||
assert query.get_asset(conn, asset['id'])
|
||||
|
||||
|
||||
@pytest.mark.bdb
|
||||
def test_text_search():
|
||||
from ..mongodb.test_queries import test_text_search
|
||||
|
||||
test_text_search('assets')
|
||||
|
||||
|
||||
def test_get_owned_ids(signed_create_tx, user_pk):
|
||||
from bigchaindb.backend import connect, query
|
||||
conn = connect()
|
||||
|
||||
# insert a transaction
|
||||
conn.db.transactions.insert_one(signed_create_tx.to_dict())
|
||||
|
||||
txns = list(query.get_owned_ids(conn, user_pk))
|
||||
|
||||
assert txns[0] == signed_create_tx.to_dict()
|
||||
|
||||
|
||||
def test_get_spending_transactions(user_pk):
|
||||
from bigchaindb.backend import connect, query
|
||||
from bigchaindb.models import Transaction
|
||||
conn = connect()
|
||||
|
||||
out = [([user_pk], 1)]
|
||||
tx1 = Transaction.create([user_pk], out * 3)
|
||||
inputs = tx1.to_inputs()
|
||||
tx2 = Transaction.transfer([inputs[0]], out, tx1.id)
|
||||
tx3 = Transaction.transfer([inputs[1]], out, tx1.id)
|
||||
tx4 = Transaction.transfer([inputs[2]], out, tx1.id)
|
||||
txns = [tx.to_dict() for tx in [tx1, tx2, tx3, tx4]]
|
||||
conn.db.transactions.insert_many(txns)
|
||||
|
||||
links = [inputs[0].fulfills.to_dict(), inputs[2].fulfills.to_dict()]
|
||||
txns = list(query.get_spending_transactions(conn, links))
|
||||
|
||||
# tx3 not a member because input 1 not asked for
|
||||
assert txns == [tx2.to_dict(), tx4.to_dict()]
|
||||
|
@ -92,7 +92,7 @@ def test_deliver_transfer_tx__double_spend_fails(b):
|
||||
carly = generate_key_pair()
|
||||
|
||||
asset = {
|
||||
"msg": "live long and prosper"
|
||||
'msg': 'live long and prosper'
|
||||
}
|
||||
|
||||
tx = Transaction.create([alice.public_key],
|
||||
|
@ -3,11 +3,10 @@ import pytest
|
||||
|
||||
@pytest.fixture
|
||||
def app(request):
|
||||
from bigchaindb import config
|
||||
from bigchaindb.web import server
|
||||
from bigchaindb.tendermint.lib import BigchainDB
|
||||
|
||||
if config['database']['backend'] == 'localmongodb':
|
||||
if request.config.getoption('--database-backend') == 'localmongodb':
|
||||
app = server.create_app(debug=True, bigchaindb_factory=BigchainDB)
|
||||
else:
|
||||
app = server.create_app(debug=True)
|
||||
|
@ -6,11 +6,12 @@ pytestmark = [pytest.mark.bdb, pytest.mark.usefixtures('inputs')]
|
||||
OUTPUTS_ENDPOINT = '/api/v1/outputs/'
|
||||
|
||||
|
||||
@pytest.mark.tendermint
|
||||
def test_get_outputs_endpoint(client, user_pk):
|
||||
m = MagicMock()
|
||||
m.txid = 'a'
|
||||
m.output = 0
|
||||
with patch('bigchaindb.core.Bigchain.get_outputs_filtered') as gof:
|
||||
with patch('bigchaindb.tendermint.lib.BigchainDB.get_outputs_filtered') as gof:
|
||||
gof.return_value = [m, m]
|
||||
res = client.get(OUTPUTS_ENDPOINT + '?public_key={}'.format(user_pk))
|
||||
assert res.json == [
|
||||
@ -21,11 +22,12 @@ def test_get_outputs_endpoint(client, user_pk):
|
||||
gof.assert_called_once_with(user_pk, None)
|
||||
|
||||
|
||||
@pytest.mark.tendermint
|
||||
def test_get_outputs_endpoint_unspent(client, user_pk):
|
||||
m = MagicMock()
|
||||
m.txid = 'a'
|
||||
m.output = 0
|
||||
with patch('bigchaindb.core.Bigchain.get_outputs_filtered') as gof:
|
||||
with patch('bigchaindb.tendermint.lib.BigchainDB.get_outputs_filtered') as gof:
|
||||
gof.return_value = [m]
|
||||
params = '?spent=False&public_key={}'.format(user_pk)
|
||||
res = client.get(OUTPUTS_ENDPOINT + params)
|
||||
@ -34,11 +36,12 @@ def test_get_outputs_endpoint_unspent(client, user_pk):
|
||||
gof.assert_called_once_with(user_pk, False)
|
||||
|
||||
|
||||
@pytest.mark.tendermint
|
||||
def test_get_outputs_endpoint_spent(client, user_pk):
|
||||
m = MagicMock()
|
||||
m.txid = 'a'
|
||||
m.output = 0
|
||||
with patch('bigchaindb.core.Bigchain.get_outputs_filtered') as gof:
|
||||
with patch('bigchaindb.tendermint.lib.BigchainDB.get_outputs_filtered') as gof:
|
||||
gof.return_value = [m]
|
||||
params = '?spent=true&public_key={}'.format(user_pk)
|
||||
res = client.get(OUTPUTS_ENDPOINT + params)
|
||||
@ -47,11 +50,13 @@ def test_get_outputs_endpoint_spent(client, user_pk):
|
||||
gof.assert_called_once_with(user_pk, True)
|
||||
|
||||
|
||||
@pytest.mark.tendermint
|
||||
def test_get_outputs_endpoint_without_public_key(client):
|
||||
res = client.get(OUTPUTS_ENDPOINT)
|
||||
assert res.status_code == 400
|
||||
|
||||
|
||||
@pytest.mark.tendermint
|
||||
def test_get_outputs_endpoint_with_invalid_public_key(client):
|
||||
expected = {'message': {'public_key': 'Invalid base58 ed25519 key'}}
|
||||
res = client.get(OUTPUTS_ENDPOINT + '?public_key=abc')
|
||||
@ -59,6 +64,7 @@ def test_get_outputs_endpoint_with_invalid_public_key(client):
|
||||
assert res.status_code == 400
|
||||
|
||||
|
||||
@pytest.mark.tendermint
|
||||
def test_get_outputs_endpoint_with_invalid_spent(client, user_pk):
|
||||
expected = {'message': {'spent': 'Boolean value must be "true" or "false" (lowercase)'}}
|
||||
params = '?spent=tru&public_key={}'.format(user_pk)
|
||||
|
Loading…
x
Reference in New Issue
Block a user