From 3f65a13c46ae1cddd0eee7f94b67216326b3a969 Mon Sep 17 00:00:00 2001 From: Lorenz Herzberger <64837895+LaurentMontBlanc@users.noreply.github.com> Date: Tue, 31 Jan 2023 09:59:34 +0100 Subject: [PATCH] standardize blocks api (#306) * adjusted block API return format * blackified and updated version and changelog * added to error message if no block with id was found Signed-off-by: Lorenz Herzberger --- CHANGELOG.md | 3 +++ planetmint/backend/models/block.py | 2 +- planetmint/backend/tarantool/query.py | 7 ++++-- planetmint/lib.py | 18 ++++---------- planetmint/version.py | 4 +-- planetmint/web/views/blocks.py | 7 ++++-- tests/tendermint/test_core.py | 8 +++--- tests/tendermint/test_lib.py | 7 ------ tests/web/test_block_tendermint.py | 10 +++----- tests/web/test_blocks.py | 36 ++++++++++++++++++++++++--- 10 files changed, 61 insertions(+), 41 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 38b118f..1a30970 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -25,6 +25,9 @@ For reference, the possible headings are: * **Known Issues** * **Notes** +## [2.2.0] - 2023-31-01 +* **Changed** standardized blocks API + ## [2.1.0] - 2023-26-01 * **Added** validation for compose and decompose transaction types diff --git a/planetmint/backend/models/block.py b/planetmint/backend/models/block.py index 13d903e..7589f3b 100644 --- a/planetmint/backend/models/block.py +++ b/planetmint/backend/models/block.py @@ -20,4 +20,4 @@ class Block: return Block(block_tuple[0], block_tuple[1], block_tuple[2], block_tuple[3]) def to_dict(self) -> dict: - return {"app_hash": self.app_hash, "height": self.height, "transactions": self.transactions} + return {"app_hash": self.app_hash, "height": self.height, "transaction_ids": self.transactions} diff --git a/planetmint/backend/tarantool/query.py b/planetmint/backend/tarantool/query.py index 56279aa..f1aa189 100644 --- a/planetmint/backend/tarantool/query.py +++ b/planetmint/backend/tarantool/query.py @@ -311,9 +311,12 @@ def get_block(connection, block_id=None) -> Union[dict, None]: @register_query(TarantoolDBConnection) -def get_block_with_transaction(connection, txid: str) -> list[Block]: +def get_block_with_transaction(connection, txid: str) -> Union[dict, None]: _block = connection.run(connection.space(TARANT_TABLE_BLOCKS).select(txid, index="block_by_transaction_id")) - return _block if len(_block) > 0 else [] + if len(_block) == 0: + return + _block = Block.from_tuple(_block[0]) + return _block.to_dict() @register_query(TarantoolDBConnection) diff --git a/planetmint/lib.py b/planetmint/lib.py index 2bcb850..f51ef37 100644 --- a/planetmint/lib.py +++ b/planetmint/lib.py @@ -311,12 +311,12 @@ class Planetmint(object): return backend.query.store_block(self.connection, block) - def get_latest_block(self): + def get_latest_block(self) -> dict: """Get the block with largest height.""" return backend.query.get_latest_block(self.connection) - def get_block(self, block_id): + def get_block(self, block_id) -> dict: """Get the block with the specified `block_id`. Returns the block corresponding to `block_id` or None if no match is @@ -333,13 +333,7 @@ class Planetmint(object): 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"]) - result["transactions"] = [Transaction.from_dict(t.to_dict()).to_dict() for t in transactions] - - return result + return block def get_block_containing_tx(self, txid): """Retrieve the list of blocks (block ids) containing a @@ -351,11 +345,9 @@ class Planetmint(object): 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) + block = backend.query.get_block_with_transaction(self.connection, txid) - return blocks + return block def validate_transaction(self, transaction, current_transactions=[]): """Validate a transaction against the current status of the database.""" diff --git a/planetmint/version.py b/planetmint/version.py index 8100550..da6da1c 100644 --- a/planetmint/version.py +++ b/planetmint/version.py @@ -3,8 +3,8 @@ # SPDX-License-Identifier: (Apache-2.0 AND CC-BY-4.0) # Code is Apache-2.0 and docs are CC-BY-4.0 -__version__ = "2.1.0" -__short_version__ = "2.1" +__version__ = "2.2.0" +__short_version__ = "2.2" # Supported Tendermint versions __tm_supported_versions__ = ["0.34.15"] diff --git a/planetmint/web/views/blocks.py b/planetmint/web/views/blocks.py index 0b58514..176b7a3 100644 --- a/planetmint/web/views/blocks.py +++ b/planetmint/web/views/blocks.py @@ -71,6 +71,9 @@ class BlockListApi(Resource): pool = current_app.config["bigchain_pool"] with pool() as planet: - blocks = planet.get_block_containing_tx(tx_id) + block = planet.get_block_containing_tx(tx_id) - return blocks + if not block: + return make_error(404, "Block containing transaction with id: {} not found.".format(tx_id)) + + return block diff --git a/tests/tendermint/test_core.py b/tests/tendermint/test_core.py index 84d5fbd..92e31d8 100644 --- a/tests/tendermint/test_core.py +++ b/tests/tendermint/test_core.py @@ -57,7 +57,7 @@ def test_init_chain_successfully_registers_chain(b): assert query.get_latest_block(b.connection) == { "height": 0, "app_hash": "", - "transactions": [], + "transaction_ids": [], } @@ -87,7 +87,7 @@ def test_init_chain_ignores_invalid_init_chain_requests(b): assert query.get_latest_block(b.connection) == { "height": 0, "app_hash": "", - "transactions": [], + "transaction_ids": [], } @@ -134,7 +134,7 @@ def test_init_chain_recognizes_new_chain_after_migration(b): assert query.get_latest_block(b.connection) == { "height": 2, "app_hash": "", - "transactions": [], + "transaction_ids": [], } # requests with old chain ID and other requests are ignored @@ -156,7 +156,7 @@ def test_init_chain_recognizes_new_chain_after_migration(b): assert query.get_latest_block(b.connection) == { "height": 2, "app_hash": "", - "transactions": [], + "transaction_ids": [], } diff --git a/tests/tendermint/test_lib.py b/tests/tendermint/test_lib.py index dc04619..2bf2252 100644 --- a/tests/tendermint/test_lib.py +++ b/tests/tendermint/test_lib.py @@ -86,13 +86,6 @@ def test_get_latest_block(b): assert block["height"] == 9 -@pytest.mark.bdb -@patch("planetmint.backend.query.get_block", return_value=None) -@patch("planetmint.Planetmint.get_latest_block", return_value={"height": 10}) -def test_get_empty_block(_0, _1, b): - assert b.get_block(5) == {"height": 5, "transactions": []} - - def test_validation_error(b): from transactions.common.crypto import generate_key_pair diff --git a/tests/web/test_block_tendermint.py b/tests/web/test_block_tendermint.py index 68230e9..56a7fe4 100644 --- a/tests/web/test_block_tendermint.py +++ b/tests/web/test_block_tendermint.py @@ -33,7 +33,7 @@ def test_get_block_endpoint(b, client, alice): b.store_block(block._asdict()) res = client.get(BLOCKS_ENDPOINT + str(block.height)) - expected_response = {"height": block.height, "transactions": [tx_dict]} + expected_response = {"app_hash": "random_utxo", "height": block.height, "transaction_ids": [tx.id]} assert res.json == expected_response assert res.status_code == 200 @@ -60,16 +60,14 @@ def test_get_block_containing_transaction(b, client, alice): b.store_block(block._asdict()) res = client.get("{}?transaction_id={}".format(BLOCKS_ENDPOINT, tx.id)) expected_height = block.height - assert res.json[0][2] == expected_height + assert res.json["height"] == expected_height 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 + assert res.status_code == 404 res = client.get(BLOCKS_ENDPOINT + "?transaction_id=123") - assert res.status_code == 200 - assert len(res.json) == 0 + assert res.status_code == 404 diff --git a/tests/web/test_blocks.py b/tests/web/test_blocks.py index 2bcb8fe..e35e150 100644 --- a/tests/web/test_blocks.py +++ b/tests/web/test_blocks.py @@ -27,12 +27,10 @@ def test_get_block_returns_404_if_not_found(client): @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 + assert res.status_code == 404 res = client.get(BLOCKS_ENDPOINT + "?transaction_id=123") - assert res.status_code == 200 - assert len(res.json) == 0 + assert res.status_code == 404 @pytest.mark.bdb @@ -55,3 +53,33 @@ def test_get_blocks_by_txid_endpoint_returns_400_bad_query_params(client): res = client.get(BLOCKS_ENDPOINT + "?transaction_id=123&status=123") assert res.status_code == 400 assert res.json == {"message": "Unknown arguments: status"} + + +@pytest.mark.bdb +@pytest.mark.usefixtures("inputs") +def test_get_latest_block(client): + res = client.get(BLOCKS_ENDPOINT + "latest") + assert res.status_code == 200 + assert len(res.json["transaction_ids"]) == 10 + assert res.json["app_hash"] == "hash3" + assert res.json["height"] == 3 + + +@pytest.mark.bdb +@pytest.mark.usefixtures("inputs") +def test_get_block_by_height(client): + res = client.get(BLOCKS_ENDPOINT + "3") + assert res.status_code == 200 + assert len(res.json["transaction_ids"]) == 10 + assert res.json["app_hash"] == "hash3" + assert res.json["height"] == 3 + + +@pytest.mark.bdb +@pytest.mark.usefixtures("inputs") +def test_get_block_by_transaction_id(client): + block_res = client.get(BLOCKS_ENDPOINT + "3") + print(block_res.json) + tx_id = block_res.json["transaction_ids"][0] + res = client.get(BLOCKS_ENDPOINT + "?transaction_id=" + tx_id) + assert res.json["height"] == 3