diff --git a/planetmint/backend/models/keys.py b/planetmint/backend/models/keys.py index edbc066..063b032 100644 --- a/planetmint/backend/models/keys.py +++ b/planetmint/backend/models/keys.py @@ -24,12 +24,14 @@ class Keys: @staticmethod def from_tuple(output: tuple) -> Keys: return Keys( - tx_id=output[0], - public_keys=output[1], + tx_id=output[1], + output_id=output[2], + public_keys=output[3], ) - def to_output_dict(self) -> dict: + def to_dict(self) -> dict: return { "tx_id": self.tx_id, + "output_id": self.output_id, "public_keys": self.public_keys, } diff --git a/planetmint/backend/models/output.py b/planetmint/backend/models/output.py index 53f5b4b..4ea8c82 100644 --- a/planetmint/backend/models/output.py +++ b/planetmint/backend/models/output.py @@ -55,13 +55,14 @@ class Output: def from_tuple(output: tuple) -> Output: return Output( tx_id=output[0], + amount=output[1], condition=Condition( - uri=output[1], + uri=output[2], details=ConditionDetails( - type=output[2], - public_key=output[3], - threshold=output[4], - sub_conditions=output[5], + type=output[3], + public_key=output[4], + threshold=output[6], + sub_conditions=output[7], ), ), ) diff --git a/planetmint/backend/models/transaction.py b/planetmint/backend/models/transaction.py new file mode 100644 index 0000000..0db0ca4 --- /dev/null +++ b/planetmint/backend/models/transaction.py @@ -0,0 +1,38 @@ +# Copyright © 2020 Interplanetary Database Association e.V., +# Planetmint and IPDB software contributors. +# SPDX-License-Identifier: (Apache-2.0 AND CC-BY-4.0) +# Code is Apache-2.0 and docs are CC-BY-4.0 + +from __future__ import annotations +from dataclasses import dataclass, field +from typing import Optional + +@dataclass +class Transaction: + id: str = "" + operation: str = "" + version: str = "" + + @staticmethod + def from_dict(transaction: dict) -> Transaction: + return Transaction( + id=transaction["id"], + operation=transaction["operation"], + version=transaction["version"], + ) + + + @staticmethod + def from_tuple(transaction: tuple) -> Transaction: + return Transaction( + id=transaction[0], + operation=transaction[1], + version=transaction[2], + ) + + def to_dict(self) -> dict: + return { + "id": self.id, + "operation": self.operation, + "version": self.version, + } diff --git a/planetmint/backend/query.py b/planetmint/backend/query.py index c7afdd7..7d3abbd 100644 --- a/planetmint/backend/query.py +++ b/planetmint/backend/query.py @@ -7,7 +7,7 @@ from functools import singledispatch from planetmint.backend.exceptions import OperationError -from planetmint.backend.interfaces import Asset, Block, MetaData, Input, Script, Output +from planetmint.backend.interfaces import Asset, Block, MetaData, Input, Script, Output, Transaction from planetmint.backend.models.keys import Keys @@ -59,27 +59,26 @@ def store_transactions(connection, signed_transactions): raise NotImplementedError - @singledispatch -def get_transaction(connection, transaction_id): - """Get a transaction from the transactions table. - - Args: - transaction_id (str): the id of the transaction. - - Returns: - The result of the operation. - """ +def store_transaction(connection, transaction): + """Store a single transaction.""" raise NotImplementedError @singledispatch -def get_transactions(connection, transaction_ids): - """Get transactions from the transactions table. +def get_transaction(conn, transaction_id): + """Get a transaction from the database.""" + + raise NotImplementedError + + +@singledispatch +def get_transactions(connection, transactions_ids) -> list[Transaction]: + """Get a transaction from the transactions table. Args: - transaction_ids (list): list of transaction ids to fetch + transaction_id (str): the id of the transaction. Returns: The result of the operation. diff --git a/planetmint/backend/tarantool/query.py b/planetmint/backend/tarantool/query.py index 065bee0..9453295 100644 --- a/planetmint/backend/tarantool/query.py +++ b/planetmint/backend/tarantool/query.py @@ -11,13 +11,13 @@ from operator import itemgetter from tarantool.error import DatabaseError from planetmint.backend import query from planetmint.backend.models.keys import Keys +from planetmint.backend.models.transaction import Transaction from planetmint.backend.tarantool.const import TARANT_TABLE_META_DATA, TARANT_TABLE_ASSETS, TARANT_TABLE_KEYS, \ TARANT_TABLE_TRANSACTION, TARANT_TABLE_INPUT, TARANT_TABLE_OUTPUT, TARANT_TABLE_SCRIPT, TARANT_TX_ID_SEARCH, \ TARANT_ID_SEARCH from planetmint.backend.utils import module_dispatch_registrar from planetmint.backend.models import Asset, MetaData, Input, Script, Output from planetmint.backend.tarantool.connection import TarantoolDBConnection -from planetmint.backend.tarantool.transaction.tools import TransactionCompose, TransactionDecompose register_query = module_dispatch_registrar(query) @@ -26,10 +26,11 @@ register_query = module_dispatch_registrar(query) def _group_transaction_by_ids(connection, txids: list): _transactions = [] for txid in txids: - _txobject = connection.run(connection.space(TARANT_TABLE_TRANSACTION).select(txid, index=TARANT_ID_SEARCH)) - if len(_txobject) == 0: + _txobject = connection.run(connection.space(TARANT_TABLE_TRANSACTION).get(txid, index=TARANT_ID_SEARCH)) + + if _txobject is None: continue - _txobject = _txobject[0] + _txinputs = get_inputs_by_tx_id(connection, txid) _txoutputs = get_outputs_by_tx_id(connection, txid) _txkeys = get_keys_by_tx_id(connection, txid) @@ -37,17 +38,14 @@ def _group_transaction_by_ids(connection, txids: list): _txmeta = get_metadata_by_tx_id(connection, txid) _txscript = get_script_by_tx_id(connection, txid) - _txoutputs = sorted(_txoutputs, key=itemgetter(8), reverse=False) - result_map = { - TARANT_TABLE_TRANSACTION: _txobject, - TARANT_TABLE_OUTPUT: _txoutputs, - TARANT_TABLE_KEYS: _txkeys, - } - tx_compose = TransactionCompose(db_results=result_map) - _transaction = tx_compose.convert_to_dict() - _transaction[TARANT_TABLE_INPUT] = [input.to_input_dict() for input in _txinputs] + _transaction = get_transaction(connection, txid) + _transaction[TARANT_TABLE_TRANSACTION] = [tx.to_dict for tx in _transactions] + _transaction[TARANT_TABLE_INPUT] + [input.to_input_dict() for input in _txinputs] + _transaction[TARANT_TABLE_OUTPUT] = [output.to_output_dict() for output in _txoutputs] + _transaction[TARANT_TABLE_KEYS] = [key.to_dict() for key in _txkeys] _transaction["assets"] = [asset.data for asset in _txassets] _transaction["metadata"] = _txmeta.metadata + if _txscript.script: _transaction[TARANT_TABLE_SCRIPT] = _txscript.script _transactions.append(_transaction) @@ -64,14 +62,14 @@ def get_inputs_by_tx_id(connection, tx_id: str) -> list[Input]: @register_query(TarantoolDBConnection) def get_outputs_by_tx_id(connection, tx_id: str) -> list[Output]: _outputs = connection.run(connection.space(TARANT_TABLE_OUTPUT).select(tx_id, index=TARANT_ID_SEARCH)) - _sorted_inputs = sorted(_outputs, key=itemgetter(6)) - return [Output.from_tuple(output) for output in _sorted_inputs] + _sorted_outputs = sorted(_outputs, key=itemgetter(8)) + return [Output.from_tuple(output) for output in _sorted_outputs] @register_query(TarantoolDBConnection) def get_keys_by_tx_id(connection, tx_id: str) -> list[Keys]: - _keys = connection.run(connection.space(TARANT_TABLE_KEYS).select(tx_id, index=TARANT_ID_SEARCH)) - _sorted_keys = sorted(_keys, key=itemgetter(6)) + _keys = connection.run(connection.space(TARANT_TABLE_KEYS).select(tx_id, index=TARANT_TX_ID_SEARCH)) + _sorted_keys = sorted(_keys, key=itemgetter(4)) return [Keys.from_tuple(key) for key in _sorted_keys] @@ -166,15 +164,26 @@ def store_transactions(connection, signed_transactions: list): @register_query(TarantoolDBConnection) -def get_transaction(connection, transaction_id: str): - _transactions = _group_transaction_by_ids(txids=[transaction_id], connection=connection) - return next(iter(_transactions), None) +def store_transaction(connection, transaction): + tx = Transaction(id=transaction["id"], operation=transaction["operation"], version=transaction["version"]) + connection.run(connection.space(TARANT_TABLE_TRANSACTION).insert( + tx.id, + tx.operation, + tx.version, + ), + only_data=False) @register_query(TarantoolDBConnection) -def get_transactions(connection, transactions_ids: list): +def get_transaction(connection, transaction_id: str) -> Transaction: + return Transaction.from_tuple( + connection.run(connection.space(TARANT_TABLE_TRANSACTION).get(transaction_id, index=TARANT_ID_SEARCH))) + + +@register_query(TarantoolDBConnection) +def get_transactions(connection, transactions_ids: list) -> list[Transaction]: _transactions = _group_transaction_by_ids(txids=transactions_ids, connection=connection) - return _transactions + return [Transaction.from_tuple(_transaction) for _transaction in _transactions] @register_query(TarantoolDBConnection) diff --git a/planetmint/backend/tarantool/transaction/tools.py b/planetmint/backend/tarantool/transaction/tools.py index 7950065..19e82b7 100644 --- a/planetmint/backend/tarantool/transaction/tools.py +++ b/planetmint/backend/tarantool/transaction/tools.py @@ -1,7 +1,3 @@ -import copy -import json - -from secrets import token_hex from transactions.common.memoize import HDict from planetmint.backend.tarantool.const import TARANT_TABLE_META_DATA, TARANT_TABLE_ASSETS, TARANT_TABLE_KEYS, \ @@ -55,58 +51,12 @@ class TransactionDecompose: else _save_keys_order(dictionary=self._transaction) ) - def __create_hash(self, n: int): - return token_hex(n) - - def __prepare_outputs(self): - _outputs = [] - _keys = [] - output_index = 0 - for _output in self._transaction[TARANT_TABLE_OUTPUT]: - output_id = self.__create_hash(7) - if _output["condition"]["details"].get("subconditions") is None: - tmp_output = ( - self._transaction["id"], - _output["amount"], - _output["condition"]["uri"], - _output["condition"]["details"]["type"], - _output["condition"]["details"]["public_key"], - output_id, - None, - None, - output_index, - ) - else: - tmp_output = ( - self._transaction["id"], - _output["amount"], - _output["condition"]["uri"], - _output["condition"]["details"]["type"], - None, - output_id, - _output["condition"]["details"]["threshold"], - _output["condition"]["details"]["subconditions"], - output_index, - ) - - _outputs.append(tmp_output) - output_index = output_index + 1 - key_index = 0 - for _key in _output["public_keys"]: - key_id = self.__create_hash(7) - _keys.append((key_id, self._transaction["id"], output_id, _key, key_index)) - key_index = key_index + 1 - return _keys, _outputs - def __prepare_transaction(self): _map = self.get_map() return (self._transaction["id"], self._transaction["operation"], self._transaction["version"], _map) def convert_to_tuple(self): self._tuple_transaction[TARANT_TABLE_TRANSACTION] = self.__prepare_transaction() - keys, outputs = self.__prepare_outputs() - self._tuple_transaction[TARANT_TABLE_OUTPUT] = outputs - self._tuple_transaction[TARANT_TABLE_KEYS] = keys return self._tuple_transaction @@ -124,30 +74,9 @@ class TransactionCompose: def _get_transaction_id(self): return self.db_results[TARANT_TABLE_TRANSACTION][0] - def _get_outputs(self): - _outputs = [] - for _output in self.db_results[TARANT_TABLE_OUTPUT]: - _out = copy.deepcopy(self._map[TARANT_TABLE_OUTPUT][_output[-1]]) - _out["amount"] = _output[1] - _tmp_keys = [(_key[3], _key[4]) for _key in self.db_results[TARANT_TABLE_KEYS] if _key[2] == _output[5]] - _sorted_keys = sorted(_tmp_keys, key=lambda tup: (tup[1])) - _out["public_keys"] = [_key[0] for _key in _sorted_keys] - - _out["condition"]["uri"] = _output[2] - if _output[7] is None: - _out["condition"]["details"]["type"] = _output[3] - _out["condition"]["details"]["public_key"] = _output[4] - else: - _out["condition"]["details"]["subconditions"] = _output[7] - _out["condition"]["details"]["type"] = _output[3] - _out["condition"]["details"]["threshold"] = _output[6] - _outputs.append(_out) - return _outputs - def convert_to_dict(self): transaction = {k: None for k in list(self._map.keys())} transaction["id"] = self._get_transaction_id() transaction["version"] = self._get_transaction_version() transaction["operation"] = self._get_transaction_operation() - transaction[TARANT_TABLE_OUTPUT] = self._get_outputs() return transaction