Problem: API returns 404 for existing empty blocks (#2321)

* Problem: API returns 404 for existing empty blocks

Solution: Empty blocks are not store in MongoDB because Tendermint does
not notify BigchainDB about them. In case a user requests a block that
is not in our MongoDB, we check if the requested height is less than or
equal to latest_block_height. If that's the case, we return an empty
block. If the requested height is greater than latest_block_height, then
we return 404.

* Address Lev's comment

* address Lev and Vansh comment
This commit is contained in:
vrde 2018-05-31 17:15:17 +02:00 committed by Troy McConaghy
parent 10e55aa4e7
commit 357c3ee8eb
3 changed files with 22 additions and 29 deletions

View File

@ -88,10 +88,6 @@ class BigchainDB(Bigchain):
def _process_status_code(self, status_code, failure_msg):
return (202, '') if status_code == 0 else (500, failure_msg)
def get_latest_block_height_from_tendermint(self):
r = requests.get(ENDPOINT + 'status')
return r.json()['result']['latest_block_height']
def store_transaction(self, transaction):
"""Store a valid transaction to the transactions collection."""
@ -276,41 +272,31 @@ class BigchainDB(Bigchain):
return backend.query.get_latest_block(self.connection)
def get_block(self, block_id, include_status=False):
"""Get the block with the specified `block_id` (and optionally its status)
def get_block(self, block_id):
"""Get the block with the specified `block_id`.
Returns the block corresponding to `block_id` or None if no match is
found.
Args:
block_id (str): block id of the block to get
include_status (bool): also return the status of the block
the return value is then a tuple: (block, status)
block_id (int): block id of the block to get.
"""
# get block from database
if isinstance(block_id, str):
block_id = int(block_id)
block = backend.query.get_block(self.connection, block_id)
latest_block = self.get_latest_block()
latest_block_height = latest_block['height'] if latest_block else 0
if not block and block_id > latest_block_height:
return
result = {'height': block_id,
'transactions': []}
if block:
transactions = backend.query.get_transactions(self.connection, block['transactions'])
transactions = Transaction.from_db(self, transactions)
result['transactions'] = [t.to_dict() for t in Transaction.from_db(self, transactions)]
block = {'height': block['height'],
'transactions': []}
block_txns = block['transactions']
for txn in transactions:
block_txns.append(txn.to_dict())
status = None
if include_status:
# NOTE: (In Tendermint) a block is an abstract entity which
# exists only after it has been validated
if block:
status = self.BLOCK_VALID
return block, status
else:
return block
return result
def get_block_containing_tx(self, txid):
"""Retrieve the list of blocks (block ids) containing a

View File

@ -29,7 +29,7 @@ ROUTES_API_V1 = [
r('/', info.ApiV1Index),
r('assets/', assets.AssetListApi),
r('metadata/', metadata.MetadataApi),
r('blocks/<string:block_id>', blocks.BlockApi),
r('blocks/<int:block_id>', blocks.BlockApi),
r('blocks/', blocks.BlockListApi),
r('transactions/<string:tx_id>', tx.TransactionApi),
r('transactions', tx.TransactionListApi),

View File

@ -61,6 +61,13 @@ def test_get_latest_block(tb):
assert block['height'] == 9
@pytest.mark.bdb
@patch('bigchaindb.backend.query.get_block', return_value=None)
@patch('bigchaindb.tendermint.lib.BigchainDB.get_latest_block', return_value={'height': 10})
def test_get_empty_block(_0, _1, tb):
assert tb.get_block(5) == {'height': 5, 'transactions': []}
def test_validation_error(b):
from bigchaindb.models import Transaction
from bigchaindb.common.crypto import generate_key_pair