diff --git a/planetmint/backend/query.py b/planetmint/backend/query.py index 943feaa..11bd423 100644 --- a/planetmint/backend/query.py +++ b/planetmint/backend/query.py @@ -69,6 +69,23 @@ def store_transaction(connection, transaction): raise NotImplementedError +@singledispatch +def store_governance_transactions(connection, transactions): + """Store the list of governance transactions.""" + + raise NotImplementedError + +@singledispatch +def store_governance_transaction(connection, transaction): + """Store a single governance transaction.""" + + raise NotImplementedError + +@singledispatch +def get_governance_transaction_by_id(connection, transaction_id): + """Get the transaction by transaction id.""" + + raise NotImplementedError @singledispatch def get_transaction_by_id(connection, transaction_id): diff --git a/planetmint/backend/tarantool/const.py b/planetmint/backend/tarantool/const.py index 83fa856..0f724e7 100644 --- a/planetmint/backend/tarantool/const.py +++ b/planetmint/backend/tarantool/const.py @@ -7,6 +7,7 @@ TARANT_TABLE_META_DATA = "meta_data" TARANT_TABLE_ASSETS = "assets" TARANT_TABLE_KEYS = "keys" TARANT_TABLE_TRANSACTION = "transactions" +TARANT_TABLE_GOVERNANCE = "governance" TARANT_TABLE_INPUT = "inputs" TARANT_TABLE_OUTPUT = "outputs" TARANT_TABLE_SCRIPT = "scripts" diff --git a/planetmint/backend/tarantool/init.lua b/planetmint/backend/tarantool/init.lua index 52dd6ef..8e3daa0 100644 --- a/planetmint/backend/tarantool/init.lua +++ b/planetmint/backend/tarantool/init.lua @@ -83,6 +83,13 @@ function init() if_not_exists = true, parts = {{ field = 'id', type = 'string' }} }) + governance:create_index('governance_by_asset_id', { + if_not_exists = true, + unique = false, + parts = { + { field = 'assets[*].id', type = 'string', is_nullable = true } + } + }) -- Outputs outputs = box.schema.create_space('outputs', { if_not_exists = true }) @@ -218,7 +225,8 @@ function drop() box.space.utxos:drop() box.space.validator_sets:drop() box.space.transactions:drop() - box.space.outputs:drop() + box.space.outputs:drop() + box.space.governance:drop() end) then print("Error: specified space not found") end diff --git a/planetmint/backend/tarantool/query.py b/planetmint/backend/tarantool/query.py index b1be700..f111b34 100644 --- a/planetmint/backend/tarantool/query.py +++ b/planetmint/backend/tarantool/query.py @@ -22,6 +22,7 @@ from planetmint.backend.tarantool.const import ( TARANT_TABLE_SCRIPT, TARANT_TX_ID_SEARCH, TARANT_ID_SEARCH, TARANT_INDEX_TX_BY_ASSET_ID, TARANT_INDEX_SPENDING_BY_ID_AND_OUTPUT_INDEX, + TARANT_TABLE_GOVERNANCE, ) from planetmint.backend.utils import module_dispatch_registrar from planetmint.backend.models import Asset, Block, MetaData, Input, Script, Output @@ -31,10 +32,10 @@ register_query = module_dispatch_registrar(query) @register_query(TarantoolDBConnection) -def get_complete_transactions_by_ids(connection, txids: list) -> list[DbTransaction]: +def get_complete_transactions_by_ids(connection, txids: list, table = TARANT_TABLE_TRANSACTION) -> list[DbTransaction]: _transactions = [] for txid in txids: - tx = get_transaction_by_id(connection, txid) + tx = get_transaction_by_id(connection, txid, table) if tx is None: continue outputs = get_outputs_by_tx_id(connection, txid) @@ -109,18 +110,48 @@ def store_transaction(connection, transaction): scripts) connection.run(connection.space(TARANT_TABLE_TRANSACTION).insert(tx), only_data=False) +@register_query(TarantoolDBConnection) +def store_governance_transactions(connection, signed_transactions: list): + for transaction in signed_transactions: + store_governance_transaction(connection, transaction) + [ + store_transaction_outputs(connection, Output.outputs_dict(output, transaction["id"]), index) + for index, output in enumerate(transaction[TARANT_TABLE_OUTPUT]) + ] @register_query(TarantoolDBConnection) -def get_transaction_by_id(connection, transaction_id): - txs = connection.run(connection.space(TARANT_TABLE_TRANSACTION).select(transaction_id, index=TARANT_ID_SEARCH)) +def store_governance_transaction(connection, transaction): + scripts = None + if TARANT_TABLE_SCRIPT in transaction: + scripts = transaction[TARANT_TABLE_SCRIPT] + tx = ( + transaction["id"], + transaction["operation"], + transaction["version"], + transaction["metadata"], + transaction["assets"], + transaction["inputs"], + scripts) + connection.run(connection.space(TARANT_TABLE_GOVERNANCE).insert(tx), only_data=False) + +@register_query(TarantoolDBConnection) +def get_governance_transaction_by_id(connection, transaction_id): + txs = connection.run(connection.space(TARANT_TABLE_GOVERNANCE).select(transaction_id, index=TARANT_ID_SEARCH)) + if len(txs) == 0: + return None + return DbTransaction.from_tuple(txs[0]) + +@register_query(TarantoolDBConnection) +def get_transaction_by_id(connection, transaction_id, table = TARANT_TABLE_TRANSACTION): + txs = connection.run(connection.space(table).select(transaction_id, index=TARANT_ID_SEARCH)) if len(txs) == 0: return None return DbTransaction.from_tuple(txs[0]) @register_query(TarantoolDBConnection) -def get_transaction_single(connection, transaction_id) -> DbTransaction: - txs = get_complete_transactions_by_ids(txids=[transaction_id], connection=connection) +def get_transaction_single(connection, transaction_id, table = TARANT_TABLE_TRANSACTION) -> DbTransaction: + txs = get_complete_transactions_by_ids(txids=[transaction_id], connection=connection, table=table) return txs[0] if len(txs) == 1 else None @@ -422,15 +453,21 @@ def get_election(connection, election_id: str): @register_query(TarantoolDBConnection) -def get_asset_tokens_for_public_key( - connection, asset_id: str, public_key: str -): # FIXME Something can be wrong with this function ! (public_key) is not used # noqa: E501 +def get_asset_tokens_for_public_key(connection, asset_id: str, public_key: str) -> list[DbTransaction]: + # FIXME Something can be wrong with this function ! (public_key) is not used # noqa: E501 # space = connection.space("keys") # _keys = space.select([public_key], index="keys_search") - _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 # _keys = _keys.data - return get_complete_transactions_by_ids(connection=connection, txids=[_tx[1] for _tx in _transactions]) + id_transactions = connection.run(connection.space(TARANT_TABLE_GOVERNANCE).select([asset_id])) + asset_id_transactions = connection.run(connection.space(TARANT_TABLE_GOVERNANCE).select([asset_id], index="governance_by_asset_id")) + transactions = id_transactions + asset_id_transactions + + # TODO return transaction class + # return transactions + return get_complete_transactions_by_ids(connection, [_tx[0] for _tx in transactions], TARANT_TABLE_GOVERNANCE) + # return get_complete_transactions_by_ids(connection=connection, txids=[_tx[1] for _tx in transactions]) @register_query(TarantoolDBConnection) diff --git a/planetmint/const.py b/planetmint/const.py new file mode 100644 index 0000000..ea7282c --- /dev/null +++ b/planetmint/const.py @@ -0,0 +1,12 @@ +# 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 + +CHAIN_MIGRATION_ELECTION = "CHAIN_MIGRATION_ELECTION" +VALIDATOR_ELECTION = "VALIDATOR_ELECTION" + +GOVERNANCE_TRANSACTION_TYPES = [ + CHAIN_MIGRATION_ELECTION, + VALIDATOR_ELECTION +] diff --git a/planetmint/lib.py b/planetmint/lib.py index a3680e0..d72a20c 100644 --- a/planetmint/lib.py +++ b/planetmint/lib.py @@ -40,6 +40,7 @@ from transactions.types.elections.election import Election from transactions.types.elections.validator_utils import election_id_to_public_key from planetmint.backend.models import Output +from planetmint.backend.tarantool.const import TARANT_TABLE_GOVERNANCE, TARANT_TABLE_TRANSACTION from planetmint.config import Config from planetmint import backend, config_utils, fastquery from planetmint.tendermint_utils import ( @@ -53,6 +54,7 @@ from planetmint.tendermint_utils import ( from planetmint import exceptions as core_exceptions from planetmint.validation import BaseValidationRules from planetmint.backend.interfaces import Asset, MetaData +from planetmint.const import GOVERNANCE_TRANSACTION_TYPES logger = logging.getLogger(__name__) @@ -139,12 +141,18 @@ class Planetmint(object): def store_bulk_transactions(self, transactions): txns = [] + gov_txns = [] for t in transactions: transaction = t.tx_dict if t.tx_dict else rapidjson.loads(rapidjson.dumps(t.to_dict())) - txns.append(transaction) + print(transaction["operation"]) + if transaction["operation"] in GOVERNANCE_TRANSACTION_TYPES: + gov_txns.append(transaction) + else: + txns.append(transaction) - return backend.query.store_transactions(self.connection, txns) + backend.query.store_transactions(self.connection, txns) + backend.query.store_governance_transactions(self.connection, gov_txns) def delete_transactions(self, txs): return backend.query.delete_transactions(self.connection, txs) @@ -229,8 +237,8 @@ class Planetmint(object): transaction = backend.query.get_transaction_by_id(self.connection, transaction_id) return bool(transaction) - def get_transaction(self, transaction_id): - return backend.query.get_transaction_single(self.connection, transaction_id) + def get_transaction(self, transaction_id, table = TARANT_TABLE_TRANSACTION): + return backend.query.get_transaction_single(self.connection, transaction_id, table) def get_transactions(self, txn_ids): return backend.query.get_transactions(self.connection, txn_ids) @@ -241,6 +249,9 @@ class Planetmint(object): for txid in txids: yield self.get_transaction(txid) + def get_governance_transaction(self, transaction_id): + return backend.query.get_governance_transaction_by_id(self.connection, transaction_id) + def get_outputs_by_tx_id(self, txid): return backend.query.get_outputs_by_tx_id(self.connection, txid) @@ -817,7 +828,7 @@ class Planetmint(object): validator_update = None for election_id, votes in elections.items(): - election = self.get_transaction(election_id) + election = self.get_transaction(election_id, TARANT_TABLE_GOVERNANCE) if election is None: continue