From 4c55f576b914cf8b51ed29d2b1dc71d0881c5efa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=BCrgen=20Eckel?= Date: Wed, 24 May 2023 09:44:50 +0200 Subject: [PATCH] 392 abci rpc is not defined for election proposals (#397) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * fixed missing abci_rpc initialization * bumped versions and added changelog * sq fixes Signed-off-by: Jürgen Eckel --- CHANGELOG.md | 5 +++ codecov.yml | 1 + config/test_config_utils.py | 7 ++-- docker-compose-aio.yml | 4 +-- docker-compose.yml | 1 + .../generate_http_server_api_documentation.py | 1 - docs/root/source/conf.py | 1 - pkg/configuration/bigchaindb-start.yml | 1 + pkg/configuration/bigchaindb-stop.yml | 1 + .../roles/tendermint/defaults/main.yml | 1 + .../roles/tendermint/tasks/common.yml | 1 + planetmint/abci/application_logic.py | 8 ++--- planetmint/abci/utils.py | 1 - planetmint/application/validator.py | 15 ++++---- planetmint/backend/localmongodb/connection.py | 2 +- planetmint/backend/models/output.py | 36 +++++-------------- planetmint/commands/planetmint.py | 16 +++++---- planetmint/config.py | 12 +++---- planetmint/model/dataaccessor.py | 2 -- planetmint/start.py | 3 +- planetmint/version.py | 2 +- pyproject.toml | 2 +- tests/commands/test_commands.py | 15 ++++---- 23 files changed, 60 insertions(+), 78 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9475ba9..af4c5b5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -25,6 +25,11 @@ For reference, the possible headings are: * **Known Issues** * **Notes** +## [2.4.6] - 2023-2-05 +* **Fixed** Missing ABCI_RPC object initiailization for CLI voting commands. +* **Fixed** TypeError in EndBlock procedure that occured rarely within the network. +* **Security** moved to a more secure requests version + ## [2.4.5] - 2023-21-04 * **Fixed** Integration of DataAccessor Singleton class to reduce potentially multiple DB driver initializations. diff --git a/codecov.yml b/codecov.yml index c7101a1..9955714 100644 --- a/codecov.yml +++ b/codecov.yml @@ -1,3 +1,4 @@ +--- # Copyright © 2020 Interplanetary Database Association e.V., # Planetmint and IPDB software contributors. # SPDX-License-Identifier: (Apache-2.0 AND CC-BY-4.0) diff --git a/config/test_config_utils.py b/config/test_config_utils.py index 8ea0bce..c72fce6 100644 --- a/config/test_config_utils.py +++ b/config/test_config_utils.py @@ -120,11 +120,8 @@ def test_env_config(monkeypatch): assert result == expected -@pytest.mark.skip -def test_autoconfigure_read_both_from_file_and_env( - monkeypatch, request -): # TODO Disabled until we create a better config format - return +@pytest.mark.skip(reason="Disabled until we create a better config format") +def test_autoconfigure_read_both_from_file_and_env(monkeypatch, request): # constants DATABASE_HOST = "test-host" DATABASE_NAME = "test-dbname" diff --git a/docker-compose-aio.yml b/docker-compose-aio.yml index e1be07a..759664d 100644 --- a/docker-compose-aio.yml +++ b/docker-compose-aio.yml @@ -1,3 +1,4 @@ +--- # Copyright © 2020 Interplanetary Database Association e.V., # Planetmint and IPDB software contributors. # SPDX-License-Identifier: (Apache-2.0 AND CC-BY-4.0) @@ -35,6 +36,3 @@ services: - ./integration/scripts:/scripts - ./integration/cli:/tests - shared:/shared - -volumes: - shared: \ No newline at end of file diff --git a/docker-compose.yml b/docker-compose.yml index a030d4d..525e031 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,3 +1,4 @@ +--- # Copyright © 2020 Interplanetary Database Association e.V., # Planetmint and IPDB software contributors. # SPDX-License-Identifier: (Apache-2.0 AND CC-BY-4.0) diff --git a/docs/root/generate_http_server_api_documentation.py b/docs/root/generate_http_server_api_documentation.py index aa7abfe..79b5b15 100644 --- a/docs/root/generate_http_server_api_documentation.py +++ b/docs/root/generate_http_server_api_documentation.py @@ -189,7 +189,6 @@ def main(): ctx["public_keys_transfer"] = tx_transfer.outputs[0].public_keys[0] ctx["tx_transfer_id"] = tx_transfer.id - # privkey_transfer_last = 'sG3jWDtdTXUidBJK53ucSTrosktG616U3tQHBk81eQe' pubkey_transfer_last = "3Af3fhhjU6d9WecEM9Uw5hfom9kNEwE7YuDWdqAUssqm" cid = 0 diff --git a/docs/root/source/conf.py b/docs/root/source/conf.py index c072717..0db9219 100644 --- a/docs/root/source/conf.py +++ b/docs/root/source/conf.py @@ -198,7 +198,6 @@ todo_include_todos = False # a list of builtin themes. # html_theme = "press" -# html_theme = 'sphinx_documatt_theme' # Theme options are theme-specific and customize the look and feel of a theme # further. For a list of options available for each theme, see the diff --git a/pkg/configuration/bigchaindb-start.yml b/pkg/configuration/bigchaindb-start.yml index f38f37b..a26f9ad 100644 --- a/pkg/configuration/bigchaindb-start.yml +++ b/pkg/configuration/bigchaindb-start.yml @@ -1,3 +1,4 @@ +--- # Copyright © 2020 Interplanetary Database Association e.V., # Planetmint and IPDB software contributors. # SPDX-License-Identifier: (Apache-2.0 AND CC-BY-4.0) diff --git a/pkg/configuration/bigchaindb-stop.yml b/pkg/configuration/bigchaindb-stop.yml index 285d7e8..2f21b5c 100644 --- a/pkg/configuration/bigchaindb-stop.yml +++ b/pkg/configuration/bigchaindb-stop.yml @@ -1,3 +1,4 @@ +--- # Copyright © 2020 Interplanetary Database Association e.V., # Planetmint and IPDB software contributors. # SPDX-License-Identifier: (Apache-2.0 AND CC-BY-4.0) diff --git a/pkg/configuration/roles/tendermint/defaults/main.yml b/pkg/configuration/roles/tendermint/defaults/main.yml index 0859a19..3f6627b 100644 --- a/pkg/configuration/roles/tendermint/defaults/main.yml +++ b/pkg/configuration/roles/tendermint/defaults/main.yml @@ -1,3 +1,4 @@ +--- # Copyright © 2020 Interplanetary Database Association e.V., # Planetmint and IPDB software contributors. # SPDX-License-Identifier: (Apache-2.0 AND CC-BY-4.0) diff --git a/pkg/configuration/roles/tendermint/tasks/common.yml b/pkg/configuration/roles/tendermint/tasks/common.yml index abee2ea..861b070 100644 --- a/pkg/configuration/roles/tendermint/tasks/common.yml +++ b/pkg/configuration/roles/tendermint/tasks/common.yml @@ -1,3 +1,4 @@ +--- # Copyright © 2020 Interplanetary Database Association e.V., # Planetmint and IPDB software contributors. # SPDX-License-Identifier: (Apache-2.0 AND CC-BY-4.0) diff --git a/planetmint/abci/application_logic.py b/planetmint/abci/application_logic.py index 6a4f410..ea0795e 100644 --- a/planetmint/abci/application_logic.py +++ b/planetmint/abci/application_logic.py @@ -81,9 +81,7 @@ class ApplicationLogic(BaseApplication): chain_id = known_chain["chain_id"] if known_chain["is_synced"]: - msg = ( - f"Got invalid InitChain ABCI request ({genesis}) - " f"the chain {chain_id} is already synced." - ) + msg = f"Got invalid InitChain ABCI request ({genesis}) - the chain {chain_id} is already synced." logger.error(msg) sys.exit(1) if chain_id != genesis.chain_id: @@ -238,7 +236,7 @@ class ApplicationLogic(BaseApplication): block_txn_hash = calculate_hash(self.block_txn_ids) block = self.validator.models.get_latest_block() - logger.debug("BLOCK: ", block) + logger.debug(f"BLOCK: {block}") if self.block_txn_ids: self.block_txn_hash = calculate_hash([block["app_hash"], block_txn_hash]) else: @@ -279,7 +277,7 @@ class ApplicationLogic(BaseApplication): sys.exit(1) logger.debug( - "Commit-ing new block with hash: apphash=%s ," "height=%s, txn ids=%s", + "Commit-ing new block with hash: apphash=%s, height=%s, txn ids=%s", data, self.new_height, self.block_txn_ids, diff --git a/planetmint/abci/utils.py b/planetmint/abci/utils.py index 3ec4a6d..d8ddc3e 100644 --- a/planetmint/abci/utils.py +++ b/planetmint/abci/utils.py @@ -79,7 +79,6 @@ def new_validator_set(validators, updates): def get_public_key_decoder(pk): encoding = pk["type"] - decoder = base64.b64decode if encoding == "ed25519-base16": decoder = base64.b16decode diff --git a/planetmint/application/validator.py b/planetmint/application/validator.py index e55fced..3213d0b 100644 --- a/planetmint/application/validator.py +++ b/planetmint/application/validator.py @@ -61,9 +61,7 @@ class Validator: if tx.operation != Transaction.COMPOSE: asset_id = tx.get_asset_id(input_txs) if asset_id != Transaction.read_out_asset_id(tx): - raise AssetIdMismatch( - ("The asset id of the input does not" " match the asset id of the" " transaction") - ) + raise AssetIdMismatch(("The asset id of the input does not match the asset id of the transaction")) else: asset_ids = Transaction.get_asset_ids(input_txs) if Transaction.read_out_asset_id(tx) in asset_ids: @@ -105,9 +103,9 @@ class Validator: if output_amount != input_amount: raise AmountError( - ( - "The amount used in the inputs `{}`" " needs to be same as the amount used" " in the outputs `{}`" - ).format(input_amount, output_amount) + "The amount used in the inputs `{}` needs to be same as the amount used in the outputs `{}`".format( + input_amount, output_amount + ) ) return True @@ -202,7 +200,7 @@ class Validator: raise InvalidProposer("Public key is not a part of the validator set") # NOTE: Check if all validators have been assigned votes equal to their voting power - if not self.is_same_topology(current_validators, transaction.outputs): + if not Validator.is_same_topology(current_validators, transaction.outputs): raise UnequalValidatorSet("Validator set much be exactly same to the outputs of election") if transaction.operation == VALIDATOR_ELECTION: @@ -210,7 +208,8 @@ class Validator: return transaction - def is_same_topology(cls, current_topology, election_topology): + @staticmethod + def is_same_topology(current_topology, election_topology): voters = {} for voter in election_topology: if len(voter.public_keys) > 1: diff --git a/planetmint/backend/localmongodb/connection.py b/planetmint/backend/localmongodb/connection.py index 01b1447..95553cc 100644 --- a/planetmint/backend/localmongodb/connection.py +++ b/planetmint/backend/localmongodb/connection.py @@ -73,7 +73,7 @@ class LocalMongoDBConnection(DBConnection): try: return query.run(self.connect()) except pymongo.errors.AutoReconnect: - logger.warning("Lost connection to the database, " "retrying query.") + logger.warning("Lost connection to the database, retrying query.") return query.run(self.connect()) except pymongo.errors.AutoReconnect as exc: raise ConnectionError from exc diff --git a/planetmint/backend/models/output.py b/planetmint/backend/models/output.py index 0b824a6..1c3e194 100644 --- a/planetmint/backend/models/output.py +++ b/planetmint/backend/models/output.py @@ -68,12 +68,14 @@ class Output: @staticmethod def outputs_dict(output: dict, transaction_id: str = "") -> Output: - out_dict: Output - if output["condition"]["details"].get("subconditions") is None: - out_dict = Output.output_with_public_key(output, transaction_id) - else: - out_dict = Output.output_with_sub_conditions(output, transaction_id) - return out_dict + return Output( + transaction_id=transaction_id, + public_keys=output["public_keys"], + amount=output["amount"], + condition=Condition( + uri=output["condition"]["uri"], details=ConditionDetails.from_dict(output["condition"]["details"]) + ), + ) @staticmethod def from_tuple(output: tuple) -> Output: @@ -110,25 +112,3 @@ class Output: @staticmethod def list_to_dict(output_list: list[Output]) -> list[dict]: return [output.to_dict() for output in output_list or []] - - @staticmethod - def output_with_public_key(output, transaction_id) -> Output: - return Output( - transaction_id=transaction_id, - public_keys=output["public_keys"], - amount=output["amount"], - condition=Condition( - uri=output["condition"]["uri"], details=ConditionDetails.from_dict(output["condition"]["details"]) - ), - ) - - @staticmethod - def output_with_sub_conditions(output, transaction_id) -> Output: - return Output( - transaction_id=transaction_id, - public_keys=output["public_keys"], - amount=output["amount"], - condition=Condition( - uri=output["condition"]["uri"], details=ConditionDetails.from_dict(output["condition"]["details"]) - ), - ) diff --git a/planetmint/commands/planetmint.py b/planetmint/commands/planetmint.py index c751299..0d4f114 100644 --- a/planetmint/commands/planetmint.py +++ b/planetmint/commands/planetmint.py @@ -29,7 +29,7 @@ from planetmint.backend import schema from planetmint.commands import utils from planetmint.commands.utils import configure_planetmint, input_on_stderr from planetmint.config_utils import setup_logging -from planetmint.abci.rpc import MODE_COMMIT, MODE_LIST +from planetmint.abci.rpc import ABCI_RPC, MODE_COMMIT, MODE_LIST from planetmint.abci.utils import load_node_key, public_key_from_base64 from planetmint.commands.election_types import elections from planetmint.version import __tm_supported_versions__ @@ -111,14 +111,18 @@ def run_election(args): """Initiate and manage elections""" b = Validator() + abci_rpc = ABCI_RPC() - # Call the function specified by args.action, as defined above - globals()[f"run_election_{args.action}"](args, b) + if args.action == "show": + run_election_show(args, b) + else: + # Call the function specified by args.action, as defined above + globals()[f"run_election_{args.action}"](args, b, abci_rpc) -def run_election_new(args, planet): +def run_election_new(args, planet, abci_rpc): election_type = args.election_type.replace("-", "_") - globals()[f"run_election_new_{election_type}"](args, planet) + globals()[f"run_election_new_{election_type}"](args, planet, abci_rpc) def create_new_election(sk, planet, election_class, data, abci_rpc): @@ -186,7 +190,7 @@ def run_election_new_chain_migration(args, planet, abci_rpc): return create_new_election(args.sk, planet, ChainMigrationElection, [{"data": {}}], abci_rpc) -def run_election_approve(args, validator: Validator, abci_rpc): +def run_election_approve(args, validator: Validator, abci_rpc: ABCI_RPC): """Approve an election :param args: dict diff --git a/planetmint/config.py b/planetmint/config.py index 1a54658..c938e58 100644 --- a/planetmint/config.py +++ b/planetmint/config.py @@ -117,8 +117,8 @@ class Config(metaclass=Singleton): def set(self, config): self._private_real_config = config - def get_db_key_map(sefl, db): - return sefl.__private_database_keys_map[db] + def get_db_key_map(self, db): + return self.__private_database_keys_map[db] def get_db_map(sefl, db): return sefl.__private_database_map[db] @@ -131,16 +131,12 @@ DEFAULT_LOGGING_CONFIG = { "formatters": { "console": { "class": "logging.Formatter", - "format": ( - "[%(asctime)s] [%(levelname)s] (%(name)s) " "%(message)s (%(processName)-10s - pid: %(process)d)" - ), + "format": ("[%(asctime)s] [%(levelname)s] (%(name)s) %(message)s (%(processName)-10s - pid: %(process)d)"), "datefmt": "%Y-%m-%d %H:%M:%S", }, "file": { "class": "logging.Formatter", - "format": ( - "[%(asctime)s] [%(levelname)s] (%(name)s) " "%(message)s (%(processName)-10s - pid: %(process)d)" - ), + "format": ("[%(asctime)s] [%(levelname)s] (%(name)s) %(message)s (%(processName)-10s - pid: %(process)d)"), "datefmt": "%Y-%m-%d %H:%M:%S", }, }, diff --git a/planetmint/model/dataaccessor.py b/planetmint/model/dataaccessor.py index aa29d29..1ce8fe1 100644 --- a/planetmint/model/dataaccessor.py +++ b/planetmint/model/dataaccessor.py @@ -337,7 +337,6 @@ class DataAccessor(metaclass=Singleton): str: Merkle root in hexadecimal form. """ utxoset = backend.query.get_unspent_outputs(self.connection) - # TODO Once ready, use the already pre-computed utxo_hash field. # See common/transactions.py for details. hashes = [ @@ -346,5 +345,4 @@ class DataAccessor(metaclass=Singleton): print(sorted(hashes)) - # TODO Notice the sorted call! return merkleroot(sorted(hashes)) diff --git a/planetmint/start.py b/planetmint/start.py index 2bf702c..103cf04 100644 --- a/planetmint/start.py +++ b/planetmint/start.py @@ -3,6 +3,7 @@ # SPDX-License-Identifier: (Apache-2.0 AND CC-BY-4.0) # Code is Apache-2.0 and docs are CC-BY-4.0 +import sys import logging import setproctitle @@ -94,4 +95,4 @@ def start(args): if __name__ == "__main__": - start() + start(sys.argv) diff --git a/planetmint/version.py b/planetmint/version.py index afbb761..4b8091a 100644 --- a/planetmint/version.py +++ b/planetmint/version.py @@ -3,7 +3,7 @@ # 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.4.5" +__version__ = "2.4.6" __short_version__ = "2.4" # Supported Tendermint versions diff --git a/pyproject.toml b/pyproject.toml index 619f1bb..47869db 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "planetmint" -version = "2.4.5" +version = "2.4.6" description = "Planetmint: The Blockchain Database" authors = ["Planetmint contributors"] license = "AGPLv3" diff --git a/tests/commands/test_commands.py b/tests/commands/test_commands.py index d2a3d03..ee1cab5 100644 --- a/tests/commands/test_commands.py +++ b/tests/commands/test_commands.py @@ -26,6 +26,9 @@ from planetmint.backend.connection import Connection from tests.utils import generate_election, generate_validators +rpc_write_transaction_string = "planetmint.abci.rpc.ABCI_RPC.write_transaction" + + def mock_get_validators(self, height): return [ { @@ -57,7 +60,7 @@ def test_chain_migration_election_show_shows_inconclusive(b_flushed, test_abci_r b = b_flushed validators = generate_validators([1] * 4) - output = b.models.store_validator_set(1, [v["storage"] for v in validators]) + _ = b.models.store_validator_set(1, [v["storage"] for v in validators]) public_key = validators[0]["public_key"] private_key = validators[0]["private_key"] @@ -465,7 +468,7 @@ def test_election_new_upsert_validator_without_tendermint( from planetmint.model.dataaccessor import DataAccessor m.setattr(DataAccessor, "get_validators", mock_get_validators) - m.setattr("planetmint.abci.rpc.ABCI_RPC.write_transaction", mock_write) + m.setattr(rpc_write_transaction_string, mock_write) args = Namespace( action="new", @@ -505,7 +508,7 @@ def test_election_new_chain_migration_without_tendermint( from planetmint.model.dataaccessor import DataAccessor m.setattr(DataAccessor, "get_validators", mock_get_validators) - m.setattr("planetmint.abci.rpc.ABCI_RPC.write_transaction", mock_write) + m.setattr(rpc_write_transaction_string, mock_write) args = Namespace(action="new", election_type="migration", sk=priv_validator_path, config={}) @@ -546,7 +549,7 @@ def test_election_new_upsert_validator_invalid_power( from planetmint.model.dataaccessor import DataAccessor m.setattr(DataAccessor, "get_validators", mock_get_validators) - m.setattr("planetmint.abci.rpc.ABCI_RPC.write_transaction", mock_write) + m.setattr(rpc_write_transaction_string, mock_write) args = Namespace( action="new", @@ -600,7 +603,7 @@ def test_election_approve_without_tendermint( from planetmint.model.dataaccessor import DataAccessor m.setattr(DataAccessor, "get_validators", mock_get_validators) - m.setattr("planetmint.abci.rpc.ABCI_RPC.write_transaction", mock_write) + m.setattr(rpc_write_transaction_string, mock_write) b, election_id = call_election_internal(b, new_validator, node_key) @@ -674,7 +677,7 @@ def call_election(monkeypatch, b, new_validator, node_key, abci_rpc): from planetmint.model.dataaccessor import DataAccessor m.setattr(DataAccessor, "get_validators", mock_get_validators) - m.setattr("planetmint.abci.rpc.ABCI_RPC.write_transaction", mock_write) + m.setattr(rpc_write_transaction_string, mock_write) b, election_id = call_election_internal(b, new_validator, node_key) m.undo() return b, election_id