mirror of
https://github.com/bigchaindb/bigchaindb.git
synced 2024-10-13 13:34:05 +00:00
Merge pull request #1065 from bigchaindb/1021/http_transactions_list
1021/http transactions list
This commit is contained in:
commit
ad2abcf723
@ -82,21 +82,6 @@ def get_blocks_status_from_transaction(conn, transaction_id):
|
|||||||
projection=['id', 'block.voters'])
|
projection=['id', 'block.voters'])
|
||||||
|
|
||||||
|
|
||||||
@register_query(MongoDBConnection)
|
|
||||||
def get_txids_by_asset_id(conn, asset_id):
|
|
||||||
cursor = conn.db['bigchain'].aggregate([
|
|
||||||
{'$match': {
|
|
||||||
'block.transactions.asset.id': asset_id
|
|
||||||
}},
|
|
||||||
{'$unwind': '$block.transactions'},
|
|
||||||
{'$match': {
|
|
||||||
'block.transactions.asset.id': asset_id
|
|
||||||
}},
|
|
||||||
{'$project': {'block.transactions.id': True}}
|
|
||||||
])
|
|
||||||
return (elem['block']['transactions']['id'] for elem in cursor)
|
|
||||||
|
|
||||||
|
|
||||||
@register_query(MongoDBConnection)
|
@register_query(MongoDBConnection)
|
||||||
def get_asset_by_id(conn, asset_id):
|
def get_asset_by_id(conn, asset_id):
|
||||||
cursor = conn.db['bigchain'].aggregate([
|
cursor = conn.db['bigchain'].aggregate([
|
||||||
@ -249,3 +234,19 @@ def get_unvoted_blocks(conn, node_pubkey):
|
|||||||
'votes': False, '_id': False
|
'votes': False, '_id': False
|
||||||
}}
|
}}
|
||||||
])
|
])
|
||||||
|
|
||||||
|
|
||||||
|
@register_query(MongoDBConnection)
|
||||||
|
def get_txids_filtered(conn, asset_id, operation=None):
|
||||||
|
match = {'block.transactions.asset.id': asset_id}
|
||||||
|
|
||||||
|
if operation:
|
||||||
|
match['block.transactions.operation'] = operation
|
||||||
|
|
||||||
|
cursor = conn.db['bigchain'].aggregate([
|
||||||
|
{'$match': match},
|
||||||
|
{'$unwind': '$block.transactions'},
|
||||||
|
{'$match': match},
|
||||||
|
{'$project': {'block.transactions.id': True}}
|
||||||
|
])
|
||||||
|
return (r['block']['transactions']['id'] for r in cursor)
|
||||||
|
@ -107,25 +107,6 @@ def get_blocks_status_from_transaction(connection, transaction_id):
|
|||||||
raise NotImplementedError
|
raise NotImplementedError
|
||||||
|
|
||||||
|
|
||||||
@singledispatch
|
|
||||||
def get_txids_by_asset_id(connection, asset_id):
|
|
||||||
"""Retrieves transactions ids related to a particular asset.
|
|
||||||
|
|
||||||
A digital asset in bigchaindb is identified by its ``CREATE``
|
|
||||||
transaction's ID. Knowing this ID allows us to query all the
|
|
||||||
transactions related to a particular digital asset.
|
|
||||||
|
|
||||||
Args:
|
|
||||||
asset_id (str): the ID of the asset.
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
A list of transactions ids related to the asset. If no transaction
|
|
||||||
exists for that asset it returns an empty list ``[]``
|
|
||||||
"""
|
|
||||||
|
|
||||||
raise NotImplementedError
|
|
||||||
|
|
||||||
|
|
||||||
@singledispatch
|
@singledispatch
|
||||||
def get_asset_by_id(conneciton, asset_id):
|
def get_asset_by_id(conneciton, asset_id):
|
||||||
"""Returns the asset associated with an asset_id.
|
"""Returns the asset associated with an asset_id.
|
||||||
@ -318,3 +299,16 @@ def get_unvoted_blocks(connection, node_pubkey):
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
raise NotImplementedError
|
raise NotImplementedError
|
||||||
|
|
||||||
|
|
||||||
|
@singledispatch
|
||||||
|
def get_txids_filtered(connection, asset_id, operation=None):
|
||||||
|
"""
|
||||||
|
Return all transactions for a particular asset id and optional operation.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
asset_id (str): ID of transaction that defined the asset
|
||||||
|
operation (str) (optional): Operation to filter on
|
||||||
|
"""
|
||||||
|
|
||||||
|
raise NotImplementedError
|
||||||
|
@ -71,22 +71,6 @@ def get_blocks_status_from_transaction(connection, transaction_id):
|
|||||||
.pluck('votes', 'id', {'block': ['voters']}))
|
.pluck('votes', 'id', {'block': ['voters']}))
|
||||||
|
|
||||||
|
|
||||||
@register_query(RethinkDBConnection)
|
|
||||||
def get_txids_by_asset_id(connection, asset_id):
|
|
||||||
# here we only want to return the transaction ids since later on when
|
|
||||||
# we are going to retrieve the transaction with status validation
|
|
||||||
|
|
||||||
# Then find any TRANSFER transactions related to the asset
|
|
||||||
tx_cursor = connection.run(
|
|
||||||
r.table('bigchain')
|
|
||||||
.get_all(asset_id, index='asset_id')
|
|
||||||
.concat_map(lambda block: block['block']['transactions'])
|
|
||||||
.filter(lambda transaction: transaction['asset']['id'] == asset_id)
|
|
||||||
.get_field('id'))
|
|
||||||
|
|
||||||
return tx_cursor
|
|
||||||
|
|
||||||
|
|
||||||
@register_query(RethinkDBConnection)
|
@register_query(RethinkDBConnection)
|
||||||
def get_asset_by_id(connection, asset_id):
|
def get_asset_by_id(connection, asset_id):
|
||||||
return connection.run(_get_asset_create_tx_query(asset_id).pluck('asset'))
|
return connection.run(_get_asset_create_tx_query(asset_id).pluck('asset'))
|
||||||
@ -249,3 +233,20 @@ def get_unvoted_blocks(connection, node_pubkey):
|
|||||||
# database level. Solving issue #444 can help untangling the situation
|
# database level. Solving issue #444 can help untangling the situation
|
||||||
unvoted_blocks = filter(lambda block: not utils.is_genesis_block(block), unvoted)
|
unvoted_blocks = filter(lambda block: not utils.is_genesis_block(block), unvoted)
|
||||||
return unvoted_blocks
|
return unvoted_blocks
|
||||||
|
|
||||||
|
|
||||||
|
@register_query(RethinkDBConnection)
|
||||||
|
def get_txids_filtered(connection, asset_id, operation=None):
|
||||||
|
# here we only want to return the transaction ids since later on when
|
||||||
|
# we are going to retrieve the transaction with status validation
|
||||||
|
|
||||||
|
tx_filter = r.row['asset']['id'] == asset_id
|
||||||
|
if operation:
|
||||||
|
tx_filter &= r.row['operation'] == operation
|
||||||
|
|
||||||
|
return connection.run(
|
||||||
|
r.table('bigchain')
|
||||||
|
.get_all(asset_id, index='asset_id')
|
||||||
|
.concat_map(lambda block: block['block']['transactions'])
|
||||||
|
.filter(tx_filter)
|
||||||
|
.get_field('id'))
|
||||||
|
@ -317,30 +317,6 @@ class Bigchain(object):
|
|||||||
else:
|
else:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
def get_transactions_by_asset_id(self, asset_id):
|
|
||||||
"""Retrieves valid or undecided 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 asset.
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
A list of valid or undecided transactions related to the asset.
|
|
||||||
If no transaction exists for that asset it returns an empty list
|
|
||||||
`[]`
|
|
||||||
"""
|
|
||||||
txids = backend.query.get_txids_by_asset_id(self.connection, asset_id)
|
|
||||||
transactions = []
|
|
||||||
for txid in txids:
|
|
||||||
tx = self.get_transaction(txid)
|
|
||||||
if tx:
|
|
||||||
transactions.append(tx)
|
|
||||||
return transactions
|
|
||||||
|
|
||||||
def get_asset_by_id(self, asset_id):
|
def get_asset_by_id(self, asset_id):
|
||||||
"""Returns the asset associated with an asset_id.
|
"""Returns the asset associated with an asset_id.
|
||||||
|
|
||||||
@ -441,6 +417,17 @@ class Bigchain(object):
|
|||||||
|
|
||||||
return owned
|
return owned
|
||||||
|
|
||||||
|
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 create_block(self, validated_transactions):
|
def create_block(self, validated_transactions):
|
||||||
"""Creates a block given a list of `validated_transactions`.
|
"""Creates a block given a list of `validated_transactions`.
|
||||||
|
|
||||||
|
30
bigchaindb/web/views/parameters.py
Normal file
30
bigchaindb/web/views/parameters.py
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
import re
|
||||||
|
|
||||||
|
|
||||||
|
def valid_txid(txid):
|
||||||
|
if re.match('^[a-fA-F0-9]{64}$', txid):
|
||||||
|
return txid.lower()
|
||||||
|
raise ValueError("Invalid hash")
|
||||||
|
|
||||||
|
|
||||||
|
def valid_bool(val):
|
||||||
|
if val == 'true':
|
||||||
|
return True
|
||||||
|
if val == 'false':
|
||||||
|
return False
|
||||||
|
raise ValueError('Boolean value must be "true" or "false" (lowercase)')
|
||||||
|
|
||||||
|
|
||||||
|
def valid_ed25519(key):
|
||||||
|
if (re.match('^[1-9a-zA-Z]{43,44}$', key) and not
|
||||||
|
re.match('.*[Il0O]', key)):
|
||||||
|
return key
|
||||||
|
raise ValueError("Invalid base58 ed25519 key")
|
||||||
|
|
||||||
|
|
||||||
|
def valid_operation(op):
|
||||||
|
if op == 'CREATE':
|
||||||
|
return 'CREATE'
|
||||||
|
if op == 'TRANSFER':
|
||||||
|
return 'TRANSFER'
|
||||||
|
raise ValueError('Operation must be "CREATE" or "TRANSFER')
|
@ -7,7 +7,8 @@ For more information please refer to the documentation on ReadTheDocs:
|
|||||||
import logging
|
import logging
|
||||||
|
|
||||||
from flask import current_app, request
|
from flask import current_app, request
|
||||||
from flask_restful import Resource
|
from flask_restful import Resource, reqparse
|
||||||
|
|
||||||
|
|
||||||
from bigchaindb.common.exceptions import (
|
from bigchaindb.common.exceptions import (
|
||||||
AmountError,
|
AmountError,
|
||||||
@ -25,6 +26,7 @@ from bigchaindb.common.exceptions import (
|
|||||||
import bigchaindb
|
import bigchaindb
|
||||||
from bigchaindb.models import Transaction
|
from bigchaindb.models import Transaction
|
||||||
from bigchaindb.web.views.base import make_error
|
from bigchaindb.web.views.base import make_error
|
||||||
|
from bigchaindb.web.views import parameters
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
@ -51,6 +53,18 @@ class TransactionApi(Resource):
|
|||||||
|
|
||||||
|
|
||||||
class TransactionListApi(Resource):
|
class TransactionListApi(Resource):
|
||||||
|
def get(self):
|
||||||
|
parser = reqparse.RequestParser()
|
||||||
|
parser.add_argument('operation', type=parameters.valid_operation)
|
||||||
|
parser.add_argument('asset_id', type=parameters.valid_txid,
|
||||||
|
required=True)
|
||||||
|
args = parser.parse_args()
|
||||||
|
|
||||||
|
with current_app.config['bigchain_pool']() as bigchain:
|
||||||
|
txs = bigchain.get_transactions_filtered(**args)
|
||||||
|
|
||||||
|
return [tx.to_dict() for tx in txs]
|
||||||
|
|
||||||
def post(self):
|
def post(self):
|
||||||
"""API endpoint to push transactions to the Federation.
|
"""API endpoint to push transactions to the Federation.
|
||||||
|
|
||||||
|
@ -90,95 +90,6 @@ def test_asset_id_mismatch(b, user_pk):
|
|||||||
Transaction.get_asset_id([tx1, tx2])
|
Transaction.get_asset_id([tx1, tx2])
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.bdb
|
|
||||||
@pytest.mark.usefixtures('inputs')
|
|
||||||
def test_get_transactions_by_asset_id(b, user_pk, user_sk):
|
|
||||||
from bigchaindb.models import Transaction
|
|
||||||
|
|
||||||
tx_create = b.get_owned_ids(user_pk).pop()
|
|
||||||
tx_create = b.get_transaction(tx_create.txid)
|
|
||||||
asset_id = tx_create.id
|
|
||||||
txs = b.get_transactions_by_asset_id(asset_id)
|
|
||||||
|
|
||||||
assert len(txs) == 1
|
|
||||||
assert txs[0].id == tx_create.id
|
|
||||||
assert txs[0].id == asset_id
|
|
||||||
|
|
||||||
# create a transfer transaction
|
|
||||||
tx_transfer = Transaction.transfer(tx_create.to_inputs(), [([user_pk], 1)],
|
|
||||||
tx_create.id)
|
|
||||||
tx_transfer_signed = tx_transfer.sign([user_sk])
|
|
||||||
# create the block
|
|
||||||
block = b.create_block([tx_transfer_signed])
|
|
||||||
b.write_block(block)
|
|
||||||
# vote the block valid
|
|
||||||
vote = b.vote(block.id, b.get_last_voted_block().id, True)
|
|
||||||
b.write_vote(vote)
|
|
||||||
|
|
||||||
txs = b.get_transactions_by_asset_id(asset_id)
|
|
||||||
|
|
||||||
assert len(txs) == 2
|
|
||||||
assert {tx_create.id, tx_transfer.id} == set(tx.id for tx in txs)
|
|
||||||
assert asset_id == Transaction.get_asset_id(txs)
|
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.bdb
|
|
||||||
@pytest.mark.usefixtures('inputs')
|
|
||||||
def test_get_transactions_by_asset_id_with_invalid_block(b, user_pk, user_sk):
|
|
||||||
from bigchaindb.models import Transaction
|
|
||||||
|
|
||||||
tx_create = b.get_owned_ids(user_pk).pop()
|
|
||||||
tx_create = b.get_transaction(tx_create.txid)
|
|
||||||
asset_id = tx_create.id
|
|
||||||
txs = b.get_transactions_by_asset_id(asset_id)
|
|
||||||
|
|
||||||
assert len(txs) == 1
|
|
||||||
assert txs[0].id == tx_create.id
|
|
||||||
assert txs[0].id == asset_id
|
|
||||||
|
|
||||||
# create a transfer transaction
|
|
||||||
tx_transfer = Transaction.transfer(tx_create.to_inputs(), [([user_pk], 1)],
|
|
||||||
tx_create.id)
|
|
||||||
tx_transfer_signed = tx_transfer.sign([user_sk])
|
|
||||||
# create the block
|
|
||||||
block = b.create_block([tx_transfer_signed])
|
|
||||||
b.write_block(block)
|
|
||||||
# vote the block invalid
|
|
||||||
vote = b.vote(block.id, b.get_last_voted_block().id, False)
|
|
||||||
b.write_vote(vote)
|
|
||||||
|
|
||||||
txs = b.get_transactions_by_asset_id(asset_id)
|
|
||||||
|
|
||||||
assert len(txs) == 1
|
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.bdb
|
|
||||||
@pytest.mark.usefixtures('inputs')
|
|
||||||
def test_get_asset_by_id(b, user_pk, user_sk):
|
|
||||||
from bigchaindb.models import Transaction
|
|
||||||
|
|
||||||
tx_create = b.get_owned_ids(user_pk).pop()
|
|
||||||
tx_create = b.get_transaction(tx_create.txid)
|
|
||||||
|
|
||||||
# create a transfer transaction
|
|
||||||
tx_transfer = Transaction.transfer(tx_create.to_inputs(), [([user_pk], 1)],
|
|
||||||
tx_create.id)
|
|
||||||
tx_transfer_signed = tx_transfer.sign([user_sk])
|
|
||||||
# create the block
|
|
||||||
block = b.create_block([tx_transfer_signed])
|
|
||||||
b.write_block(block)
|
|
||||||
# vote the block valid
|
|
||||||
vote = b.vote(block.id, b.get_last_voted_block().id, True)
|
|
||||||
b.write_vote(vote)
|
|
||||||
|
|
||||||
asset_id = Transaction.get_asset_id([tx_create, tx_transfer])
|
|
||||||
txs = b.get_transactions_by_asset_id(asset_id)
|
|
||||||
assert len(txs) == 2
|
|
||||||
|
|
||||||
asset = b.get_asset_by_id(asset_id)
|
|
||||||
assert asset == tx_create.asset
|
|
||||||
|
|
||||||
|
|
||||||
def test_create_invalid_divisible_asset(b, user_pk, user_sk):
|
def test_create_invalid_divisible_asset(b, user_pk, user_sk):
|
||||||
from bigchaindb.models import Transaction
|
from bigchaindb.models import Transaction
|
||||||
from bigchaindb.common.exceptions import AmountError
|
from bigchaindb.common.exceptions import AmountError
|
||||||
|
@ -125,24 +125,6 @@ def test_get_block_status_from_transaction(create_tx):
|
|||||||
assert block_db['block']['voters'] == block.voters
|
assert block_db['block']['voters'] == block.voters
|
||||||
|
|
||||||
|
|
||||||
def test_get_txids_by_asset_id(signed_create_tx, signed_transfer_tx):
|
|
||||||
from bigchaindb.backend import connect, query
|
|
||||||
from bigchaindb.models import Block
|
|
||||||
conn = connect()
|
|
||||||
|
|
||||||
# create and insert two blocks, one for the create and one for the
|
|
||||||
# transfer transaction
|
|
||||||
block = Block(transactions=[signed_create_tx])
|
|
||||||
conn.db.bigchain.insert_one(block.to_dict())
|
|
||||||
block = Block(transactions=[signed_transfer_tx])
|
|
||||||
conn.db.bigchain.insert_one(block.to_dict())
|
|
||||||
|
|
||||||
txids = list(query.get_txids_by_asset_id(conn, signed_create_tx.id))
|
|
||||||
|
|
||||||
assert len(txids) == 2
|
|
||||||
assert txids == [signed_create_tx.id, signed_transfer_tx.id]
|
|
||||||
|
|
||||||
|
|
||||||
def test_get_asset_by_id(create_tx):
|
def test_get_asset_by_id(create_tx):
|
||||||
from bigchaindb.backend import connect, query
|
from bigchaindb.backend import connect, query
|
||||||
from bigchaindb.models import Block
|
from bigchaindb.models import Block
|
||||||
@ -366,3 +348,30 @@ def test_get_unvoted_blocks(signed_create_tx):
|
|||||||
|
|
||||||
assert len(unvoted_blocks) == 1
|
assert len(unvoted_blocks) == 1
|
||||||
assert unvoted_blocks[0] == block.to_dict()
|
assert unvoted_blocks[0] == block.to_dict()
|
||||||
|
|
||||||
|
|
||||||
|
def test_get_txids_filtered(signed_create_tx, signed_transfer_tx):
|
||||||
|
from bigchaindb.backend import connect, query
|
||||||
|
from bigchaindb.models import Block, Transaction
|
||||||
|
conn = connect()
|
||||||
|
|
||||||
|
# create and insert two blocks, one for the create and one for the
|
||||||
|
# transfer transaction
|
||||||
|
block = Block(transactions=[signed_create_tx])
|
||||||
|
conn.db.bigchain.insert_one(block.to_dict())
|
||||||
|
block = Block(transactions=[signed_transfer_tx])
|
||||||
|
conn.db.bigchain.insert_one(block.to_dict())
|
||||||
|
|
||||||
|
asset_id = Transaction.get_asset_id([signed_create_tx, signed_transfer_tx])
|
||||||
|
|
||||||
|
# Test get by just asset id
|
||||||
|
txids = set(query.get_txids_filtered(conn, asset_id))
|
||||||
|
assert txids == {signed_create_tx.id, signed_transfer_tx.id}
|
||||||
|
|
||||||
|
# Test get by asset and CREATE
|
||||||
|
txids = set(query.get_txids_filtered(conn, asset_id, Transaction.CREATE))
|
||||||
|
assert txids == {signed_create_tx.id}
|
||||||
|
|
||||||
|
# Test get by asset and TRANSFER
|
||||||
|
txids = set(query.get_txids_filtered(conn, asset_id, Transaction.TRANSFER))
|
||||||
|
assert txids == {signed_transfer_tx.id}
|
||||||
|
@ -26,7 +26,7 @@ def test_schema(schema_func_name, args_qty):
|
|||||||
('get_stale_transactions', 1),
|
('get_stale_transactions', 1),
|
||||||
('get_blocks_status_from_transaction', 1),
|
('get_blocks_status_from_transaction', 1),
|
||||||
('get_transaction_from_backlog', 1),
|
('get_transaction_from_backlog', 1),
|
||||||
('get_txids_by_asset_id', 1),
|
('get_txids_filtered', 1),
|
||||||
('get_asset_by_id', 1),
|
('get_asset_by_id', 1),
|
||||||
('get_owned_ids', 1),
|
('get_owned_ids', 1),
|
||||||
('get_votes_by_block_id', 1),
|
('get_votes_by_block_id', 1),
|
||||||
|
65
tests/test_txlist.py
Normal file
65
tests/test_txlist.py
Normal file
@ -0,0 +1,65 @@
|
|||||||
|
"""
|
||||||
|
Test getting a list of transactions from the backend.
|
||||||
|
|
||||||
|
This test module defines it's own fixture which is used by all the tests.
|
||||||
|
"""
|
||||||
|
import pytest
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture
|
||||||
|
def txlist(b, user_pk, user2_pk, user_sk, user2_sk, genesis_block):
|
||||||
|
from bigchaindb.models import Transaction
|
||||||
|
prev_block_id = genesis_block.id
|
||||||
|
|
||||||
|
# Create first block with CREATE transactions
|
||||||
|
create1 = Transaction.create([user_pk], [([user2_pk], 6)]) \
|
||||||
|
.sign([user_sk])
|
||||||
|
create2 = Transaction.create([user2_pk],
|
||||||
|
[([user2_pk], 5), ([user_pk], 5)]) \
|
||||||
|
.sign([user2_sk])
|
||||||
|
block1 = b.create_block([create1, create2])
|
||||||
|
b.write_block(block1)
|
||||||
|
|
||||||
|
# Create second block with TRANSFER transactions
|
||||||
|
transfer1 = Transaction.transfer(create1.to_inputs(),
|
||||||
|
[([user_pk], 8)],
|
||||||
|
create1.id).sign([user2_sk])
|
||||||
|
block2 = b.create_block([transfer1])
|
||||||
|
b.write_block(block2)
|
||||||
|
|
||||||
|
# Create block with double spend
|
||||||
|
tx_doublespend = Transaction.transfer(create1.to_inputs(), [([user_pk], 9)],
|
||||||
|
create1.id).sign([user2_sk])
|
||||||
|
block_doublespend = b.create_block([tx_doublespend])
|
||||||
|
b.write_block(block_doublespend)
|
||||||
|
|
||||||
|
# Vote on all the blocks
|
||||||
|
prev_block_id = genesis_block.id
|
||||||
|
for bid in [block1.id, block2.id]:
|
||||||
|
vote = b.vote(bid, prev_block_id, True)
|
||||||
|
prev_block_id = bid
|
||||||
|
b.write_vote(vote)
|
||||||
|
|
||||||
|
# Create undecided block
|
||||||
|
untx = Transaction.create([user_pk], [([user2_pk], 7)]) \
|
||||||
|
.sign([user_sk])
|
||||||
|
block_undecided = b.create_block([untx])
|
||||||
|
b.write_block(block_undecided)
|
||||||
|
|
||||||
|
return type('', (), {
|
||||||
|
'create1': create1,
|
||||||
|
'transfer1': transfer1,
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.bdb
|
||||||
|
def test_get_txlist_by_asset(b, txlist):
|
||||||
|
res = b.get_transactions_filtered(txlist.create1.id)
|
||||||
|
assert set(tx.id for tx in res) == set([txlist.transfer1.id,
|
||||||
|
txlist.create1.id])
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.bdb
|
||||||
|
def test_get_txlist_by_operation(b, txlist):
|
||||||
|
res = b.get_transactions_filtered(txlist.create1.id, operation='CREATE')
|
||||||
|
assert set(tx.id for tx in res) == {txlist.create1.id}
|
79
tests/web/test_parameters.py
Normal file
79
tests/web/test_parameters.py
Normal file
@ -0,0 +1,79 @@
|
|||||||
|
import pytest
|
||||||
|
|
||||||
|
|
||||||
|
def test_valid_txid():
|
||||||
|
from bigchaindb.web.views.parameters import valid_txid
|
||||||
|
|
||||||
|
valid = ['18ac3e7343f016890c510e93f935261169d9e3f565436429830faf0934f4f8e4',
|
||||||
|
'18AC3E7343F016890C510E93F935261169D9E3F565436429830FAF0934F4F8E4']
|
||||||
|
for h in valid:
|
||||||
|
assert valid_txid(h) == h.lower()
|
||||||
|
|
||||||
|
non = ['18ac3e7343f016890c510e93f935261169d9e3f565436429830faf0934f4f8e',
|
||||||
|
'18ac3e7343f016890c510e93f935261169d9e3f565436429830faf0934f4f8e45',
|
||||||
|
'18ac3e7343f016890c510e93f935261169d9e3f565436429830faf0934f4f8eg',
|
||||||
|
'18ac3e7343f016890c510e93f935261169d9e3f565436429830faf0934f4f8e ',
|
||||||
|
'']
|
||||||
|
for h in non:
|
||||||
|
with pytest.raises(ValueError):
|
||||||
|
valid_txid(h)
|
||||||
|
|
||||||
|
|
||||||
|
def test_valid_bool():
|
||||||
|
from bigchaindb.web.views.parameters import valid_bool
|
||||||
|
|
||||||
|
assert valid_bool('true') is True
|
||||||
|
assert valid_bool('false') is False
|
||||||
|
|
||||||
|
with pytest.raises(ValueError):
|
||||||
|
valid_bool('TRUE')
|
||||||
|
with pytest.raises(ValueError):
|
||||||
|
valid_bool('FALSE')
|
||||||
|
with pytest.raises(ValueError):
|
||||||
|
valid_bool('0')
|
||||||
|
with pytest.raises(ValueError):
|
||||||
|
valid_bool('1')
|
||||||
|
with pytest.raises(ValueError):
|
||||||
|
valid_bool('yes')
|
||||||
|
with pytest.raises(ValueError):
|
||||||
|
valid_bool('no')
|
||||||
|
|
||||||
|
|
||||||
|
def test_valid_ed25519():
|
||||||
|
from bigchaindb.web.views.parameters import valid_ed25519
|
||||||
|
|
||||||
|
valid = ['123456789abcdefghijkmnopqrstuvwxyz1111111111',
|
||||||
|
'123456789ABCDEFGHJKLMNPQRSTUVWXYZ1111111111']
|
||||||
|
for h in valid:
|
||||||
|
assert valid_ed25519(h) == h
|
||||||
|
|
||||||
|
with pytest.raises(ValueError):
|
||||||
|
valid_ed25519('1234556789abcdefghijkmnopqrstuvwxyz1111111')
|
||||||
|
with pytest.raises(ValueError):
|
||||||
|
valid_ed25519('1234556789abcdefghijkmnopqrstuvwxyz1111111111')
|
||||||
|
with pytest.raises(ValueError):
|
||||||
|
valid_ed25519('123456789abcdefghijkmnopqrstuvwxyz111111111l')
|
||||||
|
with pytest.raises(ValueError):
|
||||||
|
valid_ed25519('123456789abcdefghijkmnopqrstuvwxyz111111111I')
|
||||||
|
with pytest.raises(ValueError):
|
||||||
|
valid_ed25519('1234556789abcdefghijkmnopqrstuvwxyz11111111O')
|
||||||
|
with pytest.raises(ValueError):
|
||||||
|
valid_ed25519('1234556789abcdefghijkmnopqrstuvwxyz111111110')
|
||||||
|
|
||||||
|
|
||||||
|
def test_valid_operation():
|
||||||
|
from bigchaindb.web.views.parameters import valid_operation
|
||||||
|
|
||||||
|
assert valid_operation('CREATE') == 'CREATE'
|
||||||
|
assert valid_operation('TRANSFER') == 'TRANSFER'
|
||||||
|
|
||||||
|
with pytest.raises(ValueError):
|
||||||
|
valid_operation('create')
|
||||||
|
with pytest.raises(ValueError):
|
||||||
|
valid_operation('transfer')
|
||||||
|
with pytest.raises(ValueError):
|
||||||
|
valid_operation('GENESIS')
|
||||||
|
with pytest.raises(ValueError):
|
||||||
|
valid_operation('blah')
|
||||||
|
with pytest.raises(ValueError):
|
||||||
|
valid_operation('')
|
@ -1,5 +1,6 @@
|
|||||||
import builtins
|
import builtins
|
||||||
import json
|
import json
|
||||||
|
from unittest.mock import patch
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
from bigchaindb.common import crypto
|
from bigchaindb.common import crypto
|
||||||
@ -180,3 +181,45 @@ def test_post_invalid_transfer_transaction_returns_400(b, client, user_pk):
|
|||||||
InvalidSignature.__name__, 'Transaction signature is invalid.')
|
InvalidSignature.__name__, 'Transaction signature is invalid.')
|
||||||
assert res.status_code == expected_status_code
|
assert res.status_code == expected_status_code
|
||||||
assert res.json['message'] == expected_error_message
|
assert res.json['message'] == expected_error_message
|
||||||
|
|
||||||
|
|
||||||
|
def test_transactions_get_list_good(client):
|
||||||
|
from functools import partial
|
||||||
|
|
||||||
|
def get_txs_patched(conn, **args):
|
||||||
|
""" Patch `get_transactions_filtered` so that rather than return an array
|
||||||
|
of transactions it returns an array of shims with a to_dict() method
|
||||||
|
that reports one of the arguments passed to `get_transactions_filtered`.
|
||||||
|
"""
|
||||||
|
return [type('', (), {'to_dict': partial(lambda a: a, arg)})
|
||||||
|
for arg in sorted(args.items())]
|
||||||
|
|
||||||
|
asset_id = '1' * 64
|
||||||
|
|
||||||
|
with patch('bigchaindb.core.Bigchain.get_transactions_filtered', get_txs_patched):
|
||||||
|
url = TX_ENDPOINT + "?asset_id=" + asset_id
|
||||||
|
assert client.get(url).json == [
|
||||||
|
['asset_id', asset_id],
|
||||||
|
['operation', None]
|
||||||
|
]
|
||||||
|
url = TX_ENDPOINT + "?asset_id=" + asset_id + "&operation=CREATE"
|
||||||
|
assert client.get(url).json == [
|
||||||
|
['asset_id', asset_id],
|
||||||
|
['operation', 'CREATE']
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
def test_transactions_get_list_bad(client):
|
||||||
|
def should_not_be_called():
|
||||||
|
assert False
|
||||||
|
with patch('bigchaindb.core.Bigchain.get_transactions_filtered',
|
||||||
|
lambda *_, **__: should_not_be_called()):
|
||||||
|
# Test asset id validated
|
||||||
|
url = TX_ENDPOINT + "?asset_id=" + '1' * 63
|
||||||
|
assert client.get(url).status_code == 400
|
||||||
|
# Test operation validated
|
||||||
|
url = TX_ENDPOINT + "?asset_id=" + '1' * 64 + "&operation=CEATE"
|
||||||
|
assert client.get(url).status_code == 400
|
||||||
|
# Test asset ID required
|
||||||
|
url = TX_ENDPOINT + "?operation=CREATE"
|
||||||
|
assert client.get(url).status_code == 400
|
||||||
|
Loading…
x
Reference in New Issue
Block a user