From 3ebfed41c7134f0637e80d4f0b1835e6f1e6d593 Mon Sep 17 00:00:00 2001 From: cybnon Date: Thu, 1 Dec 2022 14:20:34 +0100 Subject: [PATCH] Fix recursion error --- planetmint/backend/models/transaction.py | 10 ++++ planetmint/backend/query.py | 17 ++++++- planetmint/backend/tarantool/query.py | 47 +++++++++---------- planetmint/commands/planetmint.py | 4 +- planetmint/lib.py | 12 ++--- planetmint/web/views/transactions.py | 2 +- tests/commands/test_commands.py | 12 ++--- tests/db/test_planetmint_api.py | 12 ++--- tests/tendermint/test_core.py | 8 ++-- tests/tendermint/test_integration.py | 2 +- tests/tendermint/test_lib.py | 2 +- .../test_upsert_validator_vote.py | 2 +- 12 files changed, 74 insertions(+), 56 deletions(-) diff --git a/planetmint/backend/models/transaction.py b/planetmint/backend/models/transaction.py index 0ba2e30..8fd3e9e 100644 --- a/planetmint/backend/models/transaction.py +++ b/planetmint/backend/models/transaction.py @@ -7,6 +7,9 @@ from __future__ import annotations from dataclasses import dataclass, field from typing import Optional +from planetmint.backend.models import Asset, MetaData, Input, Output, Script +from planetmint.backend.models.keys import Keys + @dataclass class Transaction: @@ -14,6 +17,12 @@ class Transaction: operation: str = "" version: str = "" raw_transaction: dict = dict + assets: list[Asset] = None + metadata: MetaData = None + inputs: list[Input] = None + outputs: list[Output] = None + keys: Keys = None + script: Script = None @staticmethod def from_dict(transaction: dict) -> Transaction: @@ -21,6 +30,7 @@ class Transaction: id=transaction["id"], operation=transaction["operation"], version=transaction["version"], + inputs=transaction["inputs"], raw_transaction=transaction["transaction"], ) diff --git a/planetmint/backend/query.py b/planetmint/backend/query.py index afb9ef2..1d445ef 100644 --- a/planetmint/backend/query.py +++ b/planetmint/backend/query.py @@ -68,12 +68,25 @@ def store_transaction(connection, transaction): @singledispatch -def get_transaction(connection, transaction_id): - """Get a transaction from the database.""" +def get_transaction_space_by_id(connection, transaction_id): + """Get the transaction space by transaction id.""" raise NotImplementedError +@singledispatch +def get_transaction_single(connection, transaction_id): + """Get a single transaction by id.""" + + raise NotImplementedError + + +@singledispatch +def get_transaction(connection, transaction_id): + """Get a transaction by id.""" + + raise NotImplementedError + @singledispatch def get_transactions(connection, transactions_ids) -> list[Transaction]: """Get a transaction from the transactions table. diff --git a/planetmint/backend/tarantool/query.py b/planetmint/backend/tarantool/query.py index 9bf1aae..7d34bf0 100644 --- a/planetmint/backend/tarantool/query.py +++ b/planetmint/backend/tarantool/query.py @@ -34,26 +34,16 @@ register_query = module_dispatch_registrar(query) def _group_transaction_by_ids(connection, txids: list): _transactions = [] for txid in txids: - tx = get_transaction(connection, txid) + tx = get_transaction_space_by_id(connection, txid) if tx is None: continue - _txinputs = get_inputs_by_tx_id(connection, txid) - _txoutputs = get_outputs_by_tx_id(connection, txid) - _txkeys = get_keys_by_tx_id(connection, txid) - _txassets = get_assets_by_tx_id(connection, txid) - _txmeta = get_metadata_by_tx_id(connection, txid) - _txscript = get_script_by_tx_id(connection, txid) - - tx = { - TARANT_TABLE_TRANSACTION: tx, - TARANT_TABLE_INPUT: [tx_input.to_dict() for tx_input in _txinputs], - TARANT_TABLE_OUTPUT: [output.to_dict() for output in _txoutputs], - TARANT_TABLE_KEYS: [key.to_dict() for key in _txkeys], - TARANT_TABLE_ASSETS: _txassets, - TARANT_TABLE_META_DATA: _txmeta, - TARANT_TABLE_SCRIPT: _txscript.script if _txscript else None, - } + tx.inputs = get_inputs_by_tx_id(connection, txid) + tx.outputs = get_outputs_by_tx_id(connection, txid) + tx.keys = get_keys_by_tx_id(connection, txid) + tx.assets = get_assets_by_tx_id(connection, txid) + tx.metadata = get_metadata_by_tx_id(connection, txid) + tx.script = get_script_by_tx_id(connection, txid) _transactions.append(tx) return _transactions @@ -80,6 +70,10 @@ def get_keys_by_tx_id(connection, tx_id: str) -> list[Keys]: return [Keys.from_tuple(key) for key in _sorted_keys] +@register_query(TarantoolDBConnection) +def get_transaction(connection, tx_id: str) -> Transaction: + return NotImplemented + @register_query(TarantoolDBConnection) def store_transaction_inputs(connection, input: Input, index: int): connection.run( @@ -180,17 +174,21 @@ def store_transaction(connection, transaction): @register_query(TarantoolDBConnection) -def get_transaction(connection, transaction_id): +def get_transaction_space_by_id(connection, transaction_id): txs = connection.run(connection.space(TARANT_TABLE_TRANSACTION).select(transaction_id, index=TARANT_ID_SEARCH)) if len(txs) == 0: return None return Transaction.from_tuple(txs[0]) +@register_query(TarantoolDBConnection) +def get_transaction_single(connection, transaction_id): + return _group_transaction_by_ids(txids=[transaction_id], connection=connection) + + @register_query(TarantoolDBConnection) def get_transactions(connection, transactions_ids: list) -> list[Transaction]: - _transactions = _group_transaction_by_ids(txids=transactions_ids, connection=connection) - return [Transaction.from_tuple(_transaction) for _transaction in _transactions] + return _group_transaction_by_ids(txids=transactions_ids, connection=connection) @register_query(TarantoolDBConnection) @@ -276,8 +274,7 @@ def get_spent(connection, fullfil_transaction_id: str, fullfil_output_index: str [fullfil_transaction_id, str(fullfil_output_index)], index="spent_search" ) ) - _transactions = _group_transaction_by_ids(txids=[inp[0] for inp in _inputs], connection=connection) - return _transactions + return _group_transaction_by_ids(txids=[inp[0] for inp in _inputs], connection=connection) @register_query(TarantoolDBConnection) @@ -371,8 +368,7 @@ def get_owned_ids(connection, owner: str): if _keys is None or len(_keys) == 0: return [] _transactionids = list(set([key[1] for key in _keys])) - _transactions = _group_transaction_by_ids(txids=_transactionids, connection=connection) - return _transactions + return _group_transaction_by_ids(txids=_transactionids, connection=connection) @register_query(TarantoolDBConnection) @@ -579,8 +575,7 @@ def get_asset_tokens_for_public_key( _transactions = connection.run(connection.space(TARANT_TABLE_ASSETS).select([asset_id], index="assetid_search")) # _transactions = _transactions # _keys = _keys.data - _grouped_transactions = _group_transaction_by_ids(connection=connection, txids=[_tx[1] for _tx in _transactions]) - return _grouped_transactions + return _group_transaction_by_ids(connection=connection, txids=[_tx[1] for _tx in _transactions]) @register_query(TarantoolDBConnection) diff --git a/planetmint/commands/planetmint.py b/planetmint/commands/planetmint.py index 5026d90..64585ff 100644 --- a/planetmint/commands/planetmint.py +++ b/planetmint/commands/planetmint.py @@ -193,7 +193,7 @@ def run_election_approve(args, planet): """ key = load_node_key(args.sk) - tx = planet.get_transaction(args.election_id) + tx = planet.get_transaction_space_by_id(args.election_id) voting_powers = [v.amount for v in tx.outputs if key.public_key in v.public_keys] if len(voting_powers) > 0: voting_power = voting_powers[0] @@ -226,7 +226,7 @@ def run_election_show(args, planet): :param planet: an instance of Planetmint """ - election = planet.get_transaction(args.election_id) + election = planet.get_transaction_space_by_id(args.election_id) if not election: logger.error(f"No election found with election_id {args.election_id}") return diff --git a/planetmint/lib.py b/planetmint/lib.py index 7b19b69..397ded1 100644 --- a/planetmint/lib.py +++ b/planetmint/lib.py @@ -742,23 +742,23 @@ class Planetmint(object): # validators and their voting power in the network return current_topology == voters - def count_votes(self, election_pk, transactions, getter=getattr): + def count_votes(self, election_pk, transactions): votes = 0 for txn in transactions: - if getter(txn, "operation") == Vote.OPERATION: - for output in getter(txn, "outputs"): + if txn.operation == Vote.OPERATION: + for output in txn.outputs: # NOTE: We enforce that a valid vote to election id will have only # election_pk in the output public keys, including any other public key # along with election_pk will lead to vote being not considered valid. - if len(getter(output, "public_keys")) == 1 and [election_pk] == getter(output, "public_keys"): - votes = votes + int(getter(output, "amount")) + if len(output.public_keys) == 1 and [election_pk] == output.public_keys: + votes = votes + output.amount return votes def get_commited_votes(self, transaction, election_pk=None): # TODO: move somewhere else if election_pk is None: election_pk = election_id_to_public_key(transaction.id) txns = list(backend.query.get_asset_tokens_for_public_key(self.connection, transaction.id, election_pk)) - return self.count_votes(election_pk, txns, dict.get) + return self.count_votes(election_pk, txns) def _get_initiated_elections(self, height, txns): # TODO: move somewhere else elections = [] diff --git a/planetmint/web/views/transactions.py b/planetmint/web/views/transactions.py index 2660588..236a9d6 100644 --- a/planetmint/web/views/transactions.py +++ b/planetmint/web/views/transactions.py @@ -37,7 +37,7 @@ class TransactionApi(Resource): pool = current_app.config["bigchain_pool"] with pool() as planet: - tx = planet.get_transaction(tx_id) + tx = planet.get_transaction_space_by_id(tx_id) if not tx: return make_error(404) diff --git a/tests/commands/test_commands.py b/tests/commands/test_commands.py index ab2762a..0b9186a 100644 --- a/tests/commands/test_commands.py +++ b/tests/commands/test_commands.py @@ -320,7 +320,7 @@ def test_election_new_upsert_validator_with_tendermint(b, priv_validator_path, u election_id = run_election_new_upsert_validator(new_args, b) - assert b.get_transaction(election_id) + assert b.get_transaction_space_by_id(election_id) @pytest.mark.bdb @@ -347,7 +347,7 @@ def test_election_new_upsert_validator_without_tendermint(caplog, b, priv_valida with caplog.at_level(logging.INFO): election_id = run_election_new_upsert_validator(args, b) assert caplog.records[0].msg == "[SUCCESS] Submitted proposal with id: " + election_id - assert b.get_transaction(election_id) + assert b.get_transaction_space_by_id(election_id) @pytest.mark.abci @@ -358,7 +358,7 @@ def test_election_new_chain_migration_with_tendermint(b, priv_validator_path, us election_id = run_election_new_chain_migration(new_args, b) - assert b.get_transaction(election_id) + assert b.get_transaction_space_by_id(election_id) @pytest.mark.bdb @@ -377,7 +377,7 @@ def test_election_new_chain_migration_without_tendermint(caplog, b, priv_validat with caplog.at_level(logging.INFO): election_id = run_election_new_chain_migration(args, b) assert caplog.records[0].msg == "[SUCCESS] Submitted proposal with id: " + election_id - assert b.get_transaction(election_id) + assert b.get_transaction_space_by_id(election_id) @pytest.mark.bdb @@ -446,7 +446,7 @@ def test_election_approve_with_tendermint(b, priv_validator_path, user_sk, valid args = Namespace(action="approve", election_id=election_id, sk=priv_validator_path, config={}) approve = run_election_approve(args, b) - assert b.get_transaction(approve) + assert b.get_transaction_space_by_id(approve) @pytest.mark.bdb @@ -463,7 +463,7 @@ def test_election_approve_without_tendermint(caplog, b, priv_validator_path, new with caplog.at_level(logging.INFO): approval_id = run_election_approve(args, b) assert caplog.records[0].msg == "[SUCCESS] Your vote has been submitted" - assert b.get_transaction(approval_id) + assert b.get_transaction_space_by_id(approval_id) @pytest.mark.bdb diff --git a/tests/db/test_planetmint_api.py b/tests/db/test_planetmint_api.py index 2c08ed3..301507e 100644 --- a/tests/db/test_planetmint_api.py +++ b/tests/db/test_planetmint_api.py @@ -105,7 +105,7 @@ class TestBigchainApi(object): tx = Create.generate([alice.public_key], [([alice.public_key], 1)], assets=[asset1]).sign([alice.private_key]) b.store_bulk_transactions([tx]) - tx_from_db = b.get_transaction(tx.id) + tx_from_db = b.get_transaction_space_by_id(tx.id) before = tx.to_dict() after = tx_from_db.to_dict() @@ -131,7 +131,7 @@ class TestTransactionValidation(object): from transactions.common.exceptions import InvalidSignature input_tx = b.fastquery.get_outputs_by_public_key(user_pk).pop() - input_transaction = b.get_transaction(input_tx.txid) + input_transaction = b.get_transaction_space_by_id(input_tx.txid) sk, pk = generate_key_pair() tx = Create.generate([pk], [([user_pk], 1)]) tx.operation = "TRANSFER" @@ -158,7 +158,7 @@ class TestMultipleInputs(object): user2_sk, user2_pk = crypto.generate_key_pair() tx_link = b.fastquery.get_outputs_by_public_key(user_pk).pop() - input_tx = b.get_transaction(tx_link.txid) + input_tx = b.get_transaction_space_by_id(tx_link.txid) inputs = input_tx.to_inputs() tx = Transfer.generate(inputs, [([user2_pk], 1)], asset_ids=[input_tx.id]) tx = tx.sign([user_sk]) @@ -175,7 +175,7 @@ class TestMultipleInputs(object): user3_sk, user3_pk = crypto.generate_key_pair() tx_link = b.fastquery.get_outputs_by_public_key(user_pk).pop() - input_tx = b.get_transaction(tx_link.txid) + input_tx = b.get_transaction_space_by_id(tx_link.txid) tx = Transfer.generate(input_tx.to_inputs(), [([user2_pk, user3_pk], 1)], asset_ids=[input_tx.id]) tx = tx.sign([user_sk]) @@ -195,7 +195,7 @@ class TestMultipleInputs(object): b.store_bulk_transactions([tx]) owned_input = b.fastquery.get_outputs_by_public_key(user_pk).pop() - input_tx = b.get_transaction(owned_input.txid) + input_tx = b.get_transaction_space_by_id(owned_input.txid) inputs = input_tx.to_inputs() transfer_tx = Transfer.generate(inputs, [([user3_pk], 1)], asset_ids=[input_tx.id]) @@ -220,7 +220,7 @@ class TestMultipleInputs(object): # get input tx_link = b.fastquery.get_outputs_by_public_key(user_pk).pop() - tx_input = b.get_transaction(tx_link.txid) + tx_input = b.get_transaction_space_by_id(tx_link.txid) tx = Transfer.generate(tx_input.to_inputs(), [([user3_pk, user4_pk], 1)], asset_ids=[tx_input.id]) tx = tx.sign([user_sk, user2_sk]) diff --git a/tests/tendermint/test_core.py b/tests/tendermint/test_core.py index d036a1b..44d4dc1 100644 --- a/tests/tendermint/test_core.py +++ b/tests/tendermint/test_core.py @@ -235,7 +235,7 @@ def test_deliver_tx__valid_create_updates_db_and_emits_event(b, init_chain_reque app.end_block(types.RequestEndBlock(height=99)) app.commit() - assert b.get_transaction(tx.id).id == tx.id + assert b.get_transaction_space_by_id(tx.id).id == tx.id block_event = events.get() assert block_event.data["transactions"] == [tx] @@ -264,7 +264,7 @@ def test_deliver_tx__double_spend_fails(b, init_chain_request): app.end_block(types.RequestEndBlock(height=99)) app.commit() - assert b.get_transaction(tx.id).id == tx.id + assert b.get_transaction_space_by_id(tx.id).id == tx.id result = app.deliver_tx(encode_tx_to_bytes(tx)) assert result.code == CodeTypeError @@ -410,7 +410,7 @@ def test_rollback_pre_commit_state_after_crash(b): rollback(b) for tx in txs: - assert b.get_transaction(tx.id) + assert b.get_transaction_space_by_id(tx.id) assert b.get_latest_abci_chain() assert len(b.get_validator_set()["validators"]) == 1 assert b.get_election(migration_election.id) @@ -421,7 +421,7 @@ def test_rollback_pre_commit_state_after_crash(b): rollback(b) for tx in txs: - assert not b.get_transaction(tx.id) + assert not b.get_transaction_space_by_id(tx.id) assert not b.get_latest_abci_chain() assert len(b.get_validator_set()["validators"]) == 4 assert len(b.get_validator_set(2)["validators"]) == 4 diff --git a/tests/tendermint/test_integration.py b/tests/tendermint/test_integration.py index 341ef09..6a36d74 100644 --- a/tests/tendermint/test_integration.py +++ b/tests/tendermint/test_integration.py @@ -78,7 +78,7 @@ def test_app(b, eventqueue_fixture, init_chain_request): data = p.process("commit", None) res = next(read_messages(BytesIO(data), types.Response)) assert res.commit.data == new_block_hash.encode("utf-8") - assert b.get_transaction(tx.id).id == tx.id + assert b.get_transaction_space_by_id(tx.id).id == tx.id block0 = b.get_latest_block() assert block0 diff --git a/tests/tendermint/test_lib.py b/tests/tendermint/test_lib.py index e942e3c..cd5b0b7 100644 --- a/tests/tendermint/test_lib.py +++ b/tests/tendermint/test_lib.py @@ -69,7 +69,7 @@ def test_asset_is_separated_from_transaciton(b): b.store_bulk_transactions([tx]) assert "asset" not in backend.query.get_transaction(b.connection, tx.id) assert backend.query.get_asset(b.connection, tx.id)["data"] == assets[0] - assert b.get_transaction(tx.id).to_dict() == tx_dict + assert b.get_transaction_space_by_id(tx.id).to_dict() == tx_dict @pytest.mark.bdb diff --git a/tests/upsert_validator/test_upsert_validator_vote.py b/tests/upsert_validator/test_upsert_validator_vote.py index b0e649e..86d045d 100644 --- a/tests/upsert_validator/test_upsert_validator_vote.py +++ b/tests/upsert_validator/test_upsert_validator_vote.py @@ -246,7 +246,7 @@ def test_upsert_validator(b, node_key, node_keys, ed25519_node_keys): ) code, message = b.write_transaction(election, BROADCAST_TX_COMMIT) assert code == 202 - assert b.get_transaction(election.id) + assert b.get_transaction_space_by_id(election.id) tx_vote = gen_vote(election, 0, ed25519_node_keys) assert b.validate_transaction(tx_vote)