Integrate get block with transaction id api (#2021)
* Integrate api, get block with transaction id * Fixed docs and docstrings * Fix docs * Remove status from tendermint, fix mongo query
This commit is contained in:
parent
a7ed8cf4cb
commit
fa33fc26af
|
@ -191,3 +191,11 @@ def get_block(conn, block_id):
|
|||
conn.collection('blocks')
|
||||
.find_one({'height': block_id},
|
||||
projection={'_id': False}))
|
||||
|
||||
|
||||
@register_query(LocalMongoDBConnection)
|
||||
def get_block_with_transaction(conn, txid):
|
||||
return conn.run(
|
||||
conn.collection('blocks')
|
||||
.find({'transactions': txid},
|
||||
projection={'_id': False, 'height': True}))
|
||||
|
|
|
@ -339,6 +339,20 @@ def get_block(connection, block_id):
|
|||
raise NotImplementedError
|
||||
|
||||
|
||||
@singledispatch
|
||||
def get_block_with_transaction(connection, txid):
|
||||
"""Get a block containing transaction id `txid`
|
||||
|
||||
Args:
|
||||
txid (str): id of transaction to be searched.
|
||||
|
||||
Returns:
|
||||
block_id (int): the block id or `None`
|
||||
"""
|
||||
|
||||
raise NotImplementedError
|
||||
|
||||
|
||||
@singledispatch
|
||||
def write_assets(connection, assets):
|
||||
"""Write a list of assets to the assets table.
|
||||
|
|
|
@ -191,6 +191,22 @@ class BigchainDB(Bigchain):
|
|||
else:
|
||||
return block
|
||||
|
||||
def get_block_containing_tx(self, txid):
|
||||
"""Retrieve the list of blocks (block ids) containing a
|
||||
transaction with transaction id `txid`
|
||||
|
||||
Args:
|
||||
txid (str): transaction id of the transaction to query
|
||||
|
||||
Returns:
|
||||
Block id list (list(int))
|
||||
"""
|
||||
blocks = list(backend.query.get_block_with_transaction(self.connection, txid))
|
||||
if len(blocks) > 1:
|
||||
logger.critical('Transaction id %s exists in multiple blocks', txid)
|
||||
|
||||
return [block['height'] for block in blocks]
|
||||
|
||||
def validate_transaction(self, tx, current_transactions=[]):
|
||||
"""Validate a transaction against the current status of the database."""
|
||||
|
||||
|
|
|
@ -5,7 +5,6 @@ For more information please refer to the documentation: http://bigchaindb.com/ht
|
|||
from flask import current_app
|
||||
from flask_restful import Resource, reqparse
|
||||
|
||||
from bigchaindb import Bigchain
|
||||
from bigchaindb.web.views.base import make_error
|
||||
|
||||
|
||||
|
@ -42,18 +41,13 @@ class BlockListApi(Resource):
|
|||
"""
|
||||
parser = reqparse.RequestParser()
|
||||
parser.add_argument('transaction_id', type=str, required=True)
|
||||
parser.add_argument('status', type=str, case_sensitive=False,
|
||||
choices=[Bigchain.BLOCK_VALID, Bigchain.BLOCK_INVALID, Bigchain.BLOCK_UNDECIDED])
|
||||
|
||||
args = parser.parse_args(strict=True)
|
||||
tx_id = args['transaction_id']
|
||||
status = args['status']
|
||||
|
||||
pool = current_app.config['bigchain_pool']
|
||||
|
||||
with pool() as bigchain:
|
||||
block_statuses = bigchain.get_blocks_status_containing_tx(tx_id)
|
||||
blocks = [block_id for block_id, block_status in block_statuses.items()
|
||||
if not status or block_status == status]
|
||||
blocks = bigchain.get_block_containing_tx(tx_id)
|
||||
|
||||
return blocks
|
||||
|
|
|
@ -251,7 +251,14 @@ def main():
|
|||
ctx['block'] = pretty_json(block_dict)
|
||||
ctx['blockid'] = block.height
|
||||
|
||||
block = Block(transactions=[tx], node_pubkey=node_public, voters=[node_public], signature=signature)
|
||||
# block status
|
||||
block_list = [
|
||||
block.height
|
||||
]
|
||||
ctx['block_list'] = pretty_json(block_list)
|
||||
|
||||
|
||||
# block = Block(transactions=[tx], node_pubkey=node_public, voters=[node_public], signature=signature)
|
||||
block_transfer = Block(transactions=[tx_transfer], node_pubkey=node_public,
|
||||
voters=[node_public], signature=signature)
|
||||
ctx['block_transfer'] = pretty_json(block_transfer.to_dict())
|
||||
|
@ -263,13 +270,6 @@ def main():
|
|||
vote = b.vote(vblock.id, DUMMY_SHA3, True)
|
||||
ctx['vote'] = pretty_json(vote)
|
||||
|
||||
# block status
|
||||
block_list = [
|
||||
block_transfer.id,
|
||||
block.id
|
||||
]
|
||||
ctx['block_list'] = pretty_json(block_list)
|
||||
|
||||
base_path = os.path.join(os.path.dirname(__file__),
|
||||
'source/http-samples')
|
||||
if not os.path.exists(base_path):
|
||||
|
|
|
@ -645,19 +645,22 @@ Blocks
|
|||
|
||||
:statuscode 400: The request wasn't understood by the server, e.g. just requesting ``/blocks`` without the ``block_id``.
|
||||
|
||||
.. http:get:: /api/v1/blocks?transaction_id={transaction_id}&status={UNDECIDED|VALID|INVALID}
|
||||
.. http:get:: /api/v1/blocks?transaction_id={transaction_id}
|
||||
|
||||
Retrieve a list of ``block_id`` with their corresponding status that contain a transaction with the ID ``transaction_id``.
|
||||
Retrieve a list of block IDs (block heights), such that the blocks with those IDs contain a transaction with the ID ``transaction_id``. A correct response may consist of an empty list or a list with one block ID.
|
||||
|
||||
Any blocks, be they ``UNDECIDED``, ``VALID`` or ``INVALID`` will be
|
||||
returned if no status filter is provided.
|
||||
.. note::
|
||||
The query parameter ``status`` has been deprecated. It allowed
|
||||
users to filter blocks based on their status i.e. only blocks with the specified
|
||||
status were included in the response. Since then this behavior has changed
|
||||
and now block are created only after the transactions are accepted by the
|
||||
network i.e. blocks have only one status ``VALID``
|
||||
|
||||
.. note::
|
||||
In case no block was found, an empty list and an HTTP status code
|
||||
``200 OK`` is returned, as the request was still successful.
|
||||
|
||||
:query string transaction_id: transaction ID *(required)*
|
||||
:query string status: Filter blocks by their status. One of ``VALID``, ``UNDECIDED`` or ``INVALID``.
|
||||
|
||||
**Example request**:
|
||||
|
||||
|
@ -671,7 +674,7 @@ Blocks
|
|||
|
||||
:resheader Content-Type: ``application/json``
|
||||
|
||||
:statuscode 200: A list of blocks containing a transaction with ID ``transaction_id`` was found and returned.
|
||||
:statuscode 200: The request was properly formed and zero or more blocks were found containing the specified ``transaction_id``.
|
||||
:statuscode 400: The request wasn't understood by the server, e.g. just requesting ``/blocks``, without defining ``transaction_id``.
|
||||
|
||||
|
||||
|
|
|
@ -35,3 +35,58 @@ def test_get_block_returns_404_if_not_found(client):
|
|||
|
||||
res = client.get(BLOCKS_ENDPOINT + '123/')
|
||||
assert res.status_code == 404
|
||||
|
||||
|
||||
@pytest.mark.bdb
|
||||
def test_get_block_containing_transaction(tb, client):
|
||||
b = tb
|
||||
tx = Transaction.create([b.me], [([b.me], 1)], asset={'cycle': 'hero'})
|
||||
tx = tx.sign([b.me_private])
|
||||
b.store_transaction(tx)
|
||||
|
||||
block = Block(app_hash='random_utxo',
|
||||
height=13,
|
||||
transactions=[tx.id])
|
||||
b.store_block(block._asdict())
|
||||
|
||||
res = client.get('{}?transaction_id={}'.format(BLOCKS_ENDPOINT, tx.id))
|
||||
expected_response = [block.height]
|
||||
assert res.json == expected_response
|
||||
assert res.status_code == 200
|
||||
|
||||
|
||||
@pytest.mark.bdb
|
||||
def test_get_blocks_by_txid_endpoint_returns_empty_list_not_found(client):
|
||||
res = client.get(BLOCKS_ENDPOINT + '?transaction_id=')
|
||||
assert res.status_code == 200
|
||||
assert len(res.json) == 0
|
||||
|
||||
res = client.get(BLOCKS_ENDPOINT + '?transaction_id=123')
|
||||
assert res.status_code == 200
|
||||
assert len(res.json) == 0
|
||||
|
||||
|
||||
@pytest.mark.bdb
|
||||
def test_get_blocks_by_txid_endpoint_returns_400_bad_query_params(client):
|
||||
res = client.get(BLOCKS_ENDPOINT)
|
||||
assert res.status_code == 400
|
||||
|
||||
res = client.get(BLOCKS_ENDPOINT + '?ts_id=123')
|
||||
assert res.status_code == 400
|
||||
assert res.json == {
|
||||
'message': {
|
||||
'transaction_id': 'Missing required parameter in the JSON body or the post body or the query string'
|
||||
}
|
||||
}
|
||||
|
||||
res = client.get(BLOCKS_ENDPOINT + '?transaction_id=123&foo=123')
|
||||
assert res.status_code == 400
|
||||
assert res.json == {
|
||||
'message': 'Unknown arguments: foo'
|
||||
}
|
||||
|
||||
res = client.get(BLOCKS_ENDPOINT + '?transaction_id=123&status=123')
|
||||
assert res.status_code == 400
|
||||
assert res.json == {
|
||||
'message': 'Unknown arguments: status'
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue