Fix recursion error

This commit is contained in:
cybnon 2022-12-01 14:20:34 +01:00
parent 50ca7982ed
commit 3ebfed41c7
12 changed files with 74 additions and 56 deletions

View File

@ -7,6 +7,9 @@ from __future__ import annotations
from dataclasses import dataclass, field from dataclasses import dataclass, field
from typing import Optional from typing import Optional
from planetmint.backend.models import Asset, MetaData, Input, Output, Script
from planetmint.backend.models.keys import Keys
@dataclass @dataclass
class Transaction: class Transaction:
@ -14,6 +17,12 @@ class Transaction:
operation: str = "" operation: str = ""
version: str = "" version: str = ""
raw_transaction: dict = dict 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 @staticmethod
def from_dict(transaction: dict) -> Transaction: def from_dict(transaction: dict) -> Transaction:
@ -21,6 +30,7 @@ class Transaction:
id=transaction["id"], id=transaction["id"],
operation=transaction["operation"], operation=transaction["operation"],
version=transaction["version"], version=transaction["version"],
inputs=transaction["inputs"],
raw_transaction=transaction["transaction"], raw_transaction=transaction["transaction"],
) )

View File

@ -68,12 +68,25 @@ def store_transaction(connection, transaction):
@singledispatch @singledispatch
def get_transaction(connection, transaction_id): def get_transaction_space_by_id(connection, transaction_id):
"""Get a transaction from the database.""" """Get the transaction space by transaction id."""
raise NotImplementedError 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 @singledispatch
def get_transactions(connection, transactions_ids) -> list[Transaction]: def get_transactions(connection, transactions_ids) -> list[Transaction]:
"""Get a transaction from the transactions table. """Get a transaction from the transactions table.

View File

@ -34,26 +34,16 @@ register_query = module_dispatch_registrar(query)
def _group_transaction_by_ids(connection, txids: list): def _group_transaction_by_ids(connection, txids: list):
_transactions = [] _transactions = []
for txid in txids: for txid in txids:
tx = get_transaction(connection, txid) tx = get_transaction_space_by_id(connection, txid)
if tx is None: if tx is None:
continue continue
_txinputs = get_inputs_by_tx_id(connection, txid) tx.inputs = get_inputs_by_tx_id(connection, txid)
_txoutputs = get_outputs_by_tx_id(connection, txid) tx.outputs = get_outputs_by_tx_id(connection, txid)
_txkeys = get_keys_by_tx_id(connection, txid) tx.keys = get_keys_by_tx_id(connection, txid)
_txassets = get_assets_by_tx_id(connection, txid) tx.assets = get_assets_by_tx_id(connection, txid)
_txmeta = get_metadata_by_tx_id(connection, txid) tx.metadata = get_metadata_by_tx_id(connection, txid)
_txscript = get_script_by_tx_id(connection, txid) tx.script = 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,
}
_transactions.append(tx) _transactions.append(tx)
return _transactions 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] 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) @register_query(TarantoolDBConnection)
def store_transaction_inputs(connection, input: Input, index: int): def store_transaction_inputs(connection, input: Input, index: int):
connection.run( connection.run(
@ -180,17 +174,21 @@ def store_transaction(connection, transaction):
@register_query(TarantoolDBConnection) @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)) txs = connection.run(connection.space(TARANT_TABLE_TRANSACTION).select(transaction_id, index=TARANT_ID_SEARCH))
if len(txs) == 0: if len(txs) == 0:
return None return None
return Transaction.from_tuple(txs[0]) 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) @register_query(TarantoolDBConnection)
def get_transactions(connection, transactions_ids: list) -> list[Transaction]: def get_transactions(connection, transactions_ids: list) -> list[Transaction]:
_transactions = _group_transaction_by_ids(txids=transactions_ids, connection=connection) return _group_transaction_by_ids(txids=transactions_ids, connection=connection)
return [Transaction.from_tuple(_transaction) for _transaction in _transactions]
@register_query(TarantoolDBConnection) @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" [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 _group_transaction_by_ids(txids=[inp[0] for inp in _inputs], connection=connection)
return _transactions
@register_query(TarantoolDBConnection) @register_query(TarantoolDBConnection)
@ -371,8 +368,7 @@ def get_owned_ids(connection, owner: str):
if _keys is None or len(_keys) == 0: if _keys is None or len(_keys) == 0:
return [] return []
_transactionids = list(set([key[1] for key in _keys])) _transactionids = list(set([key[1] for key in _keys]))
_transactions = _group_transaction_by_ids(txids=_transactionids, connection=connection) return _group_transaction_by_ids(txids=_transactionids, connection=connection)
return _transactions
@register_query(TarantoolDBConnection) @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 = connection.run(connection.space(TARANT_TABLE_ASSETS).select([asset_id], index="assetid_search"))
# _transactions = _transactions # _transactions = _transactions
# _keys = _keys.data # _keys = _keys.data
_grouped_transactions = _group_transaction_by_ids(connection=connection, txids=[_tx[1] for _tx in _transactions]) return _group_transaction_by_ids(connection=connection, txids=[_tx[1] for _tx in _transactions])
return _grouped_transactions
@register_query(TarantoolDBConnection) @register_query(TarantoolDBConnection)

View File

@ -193,7 +193,7 @@ def run_election_approve(args, planet):
""" """
key = load_node_key(args.sk) 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] voting_powers = [v.amount for v in tx.outputs if key.public_key in v.public_keys]
if len(voting_powers) > 0: if len(voting_powers) > 0:
voting_power = voting_powers[0] voting_power = voting_powers[0]
@ -226,7 +226,7 @@ def run_election_show(args, planet):
:param planet: an instance of Planetmint :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: if not election:
logger.error(f"No election found with election_id {args.election_id}") logger.error(f"No election found with election_id {args.election_id}")
return return

View File

@ -742,23 +742,23 @@ class Planetmint(object):
# validators and their voting power in the network # validators and their voting power in the network
return current_topology == voters return current_topology == voters
def count_votes(self, election_pk, transactions, getter=getattr): def count_votes(self, election_pk, transactions):
votes = 0 votes = 0
for txn in transactions: for txn in transactions:
if getter(txn, "operation") == Vote.OPERATION: if txn.operation == Vote.OPERATION:
for output in getter(txn, "outputs"): for output in txn.outputs:
# NOTE: We enforce that a valid vote to election id will have only # 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 # election_pk in the output public keys, including any other public key
# along with election_pk will lead to vote being not considered valid. # 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"): if len(output.public_keys) == 1 and [election_pk] == output.public_keys:
votes = votes + int(getter(output, "amount")) votes = votes + output.amount
return votes return votes
def get_commited_votes(self, transaction, election_pk=None): # TODO: move somewhere else def get_commited_votes(self, transaction, election_pk=None): # TODO: move somewhere else
if election_pk is None: if election_pk is None:
election_pk = election_id_to_public_key(transaction.id) 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)) 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 def _get_initiated_elections(self, height, txns): # TODO: move somewhere else
elections = [] elections = []

View File

@ -37,7 +37,7 @@ class TransactionApi(Resource):
pool = current_app.config["bigchain_pool"] pool = current_app.config["bigchain_pool"]
with pool() as planet: with pool() as planet:
tx = planet.get_transaction(tx_id) tx = planet.get_transaction_space_by_id(tx_id)
if not tx: if not tx:
return make_error(404) return make_error(404)

View File

@ -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) 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 @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): with caplog.at_level(logging.INFO):
election_id = run_election_new_upsert_validator(args, b) election_id = run_election_new_upsert_validator(args, b)
assert caplog.records[0].msg == "[SUCCESS] Submitted proposal with id: " + election_id 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 @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) 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 @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): with caplog.at_level(logging.INFO):
election_id = run_election_new_chain_migration(args, b) election_id = run_election_new_chain_migration(args, b)
assert caplog.records[0].msg == "[SUCCESS] Submitted proposal with id: " + election_id 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 @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={}) args = Namespace(action="approve", election_id=election_id, sk=priv_validator_path, config={})
approve = run_election_approve(args, b) approve = run_election_approve(args, b)
assert b.get_transaction(approve) assert b.get_transaction_space_by_id(approve)
@pytest.mark.bdb @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): with caplog.at_level(logging.INFO):
approval_id = run_election_approve(args, b) approval_id = run_election_approve(args, b)
assert caplog.records[0].msg == "[SUCCESS] Your vote has been submitted" 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 @pytest.mark.bdb

View File

@ -105,7 +105,7 @@ class TestBigchainApi(object):
tx = Create.generate([alice.public_key], [([alice.public_key], 1)], assets=[asset1]).sign([alice.private_key]) tx = Create.generate([alice.public_key], [([alice.public_key], 1)], assets=[asset1]).sign([alice.private_key])
b.store_bulk_transactions([tx]) 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() before = tx.to_dict()
after = tx_from_db.to_dict() after = tx_from_db.to_dict()
@ -131,7 +131,7 @@ class TestTransactionValidation(object):
from transactions.common.exceptions import InvalidSignature from transactions.common.exceptions import InvalidSignature
input_tx = b.fastquery.get_outputs_by_public_key(user_pk).pop() 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() sk, pk = generate_key_pair()
tx = Create.generate([pk], [([user_pk], 1)]) tx = Create.generate([pk], [([user_pk], 1)])
tx.operation = "TRANSFER" tx.operation = "TRANSFER"
@ -158,7 +158,7 @@ class TestMultipleInputs(object):
user2_sk, user2_pk = crypto.generate_key_pair() user2_sk, user2_pk = crypto.generate_key_pair()
tx_link = b.fastquery.get_outputs_by_public_key(user_pk).pop() 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() inputs = input_tx.to_inputs()
tx = Transfer.generate(inputs, [([user2_pk], 1)], asset_ids=[input_tx.id]) tx = Transfer.generate(inputs, [([user2_pk], 1)], asset_ids=[input_tx.id])
tx = tx.sign([user_sk]) tx = tx.sign([user_sk])
@ -175,7 +175,7 @@ class TestMultipleInputs(object):
user3_sk, user3_pk = crypto.generate_key_pair() user3_sk, user3_pk = crypto.generate_key_pair()
tx_link = b.fastquery.get_outputs_by_public_key(user_pk).pop() 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 = Transfer.generate(input_tx.to_inputs(), [([user2_pk, user3_pk], 1)], asset_ids=[input_tx.id])
tx = tx.sign([user_sk]) tx = tx.sign([user_sk])
@ -195,7 +195,7 @@ class TestMultipleInputs(object):
b.store_bulk_transactions([tx]) b.store_bulk_transactions([tx])
owned_input = b.fastquery.get_outputs_by_public_key(user_pk).pop() 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() inputs = input_tx.to_inputs()
transfer_tx = Transfer.generate(inputs, [([user3_pk], 1)], asset_ids=[input_tx.id]) transfer_tx = Transfer.generate(inputs, [([user3_pk], 1)], asset_ids=[input_tx.id])
@ -220,7 +220,7 @@ class TestMultipleInputs(object):
# get input # get input
tx_link = b.fastquery.get_outputs_by_public_key(user_pk).pop() 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 = Transfer.generate(tx_input.to_inputs(), [([user3_pk, user4_pk], 1)], asset_ids=[tx_input.id])
tx = tx.sign([user_sk, user2_sk]) tx = tx.sign([user_sk, user2_sk])

View File

@ -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.end_block(types.RequestEndBlock(height=99))
app.commit() 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() block_event = events.get()
assert block_event.data["transactions"] == [tx] 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.end_block(types.RequestEndBlock(height=99))
app.commit() 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)) result = app.deliver_tx(encode_tx_to_bytes(tx))
assert result.code == CodeTypeError assert result.code == CodeTypeError
@ -410,7 +410,7 @@ def test_rollback_pre_commit_state_after_crash(b):
rollback(b) rollback(b)
for tx in txs: 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 b.get_latest_abci_chain()
assert len(b.get_validator_set()["validators"]) == 1 assert len(b.get_validator_set()["validators"]) == 1
assert b.get_election(migration_election.id) assert b.get_election(migration_election.id)
@ -421,7 +421,7 @@ def test_rollback_pre_commit_state_after_crash(b):
rollback(b) rollback(b)
for tx in txs: 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 not b.get_latest_abci_chain()
assert len(b.get_validator_set()["validators"]) == 4 assert len(b.get_validator_set()["validators"]) == 4
assert len(b.get_validator_set(2)["validators"]) == 4 assert len(b.get_validator_set(2)["validators"]) == 4

View File

@ -78,7 +78,7 @@ def test_app(b, eventqueue_fixture, init_chain_request):
data = p.process("commit", None) data = p.process("commit", None)
res = next(read_messages(BytesIO(data), types.Response)) res = next(read_messages(BytesIO(data), types.Response))
assert res.commit.data == new_block_hash.encode("utf-8") 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() block0 = b.get_latest_block()
assert block0 assert block0

View File

@ -69,7 +69,7 @@ def test_asset_is_separated_from_transaciton(b):
b.store_bulk_transactions([tx]) b.store_bulk_transactions([tx])
assert "asset" not in backend.query.get_transaction(b.connection, tx.id) 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 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 @pytest.mark.bdb

View File

@ -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) code, message = b.write_transaction(election, BROADCAST_TX_COMMIT)
assert code == 202 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) tx_vote = gen_vote(election, 0, ed25519_node_keys)
assert b.validate_transaction(tx_vote) assert b.validate_transaction(tx_vote)