Merge branch 'refactor-backend' of github.com:planetmint/planetmint into refactor-backend

This commit is contained in:
Lorenz Herzberger 2022-12-06 10:45:55 +01:00
commit 5902c15c99
No known key found for this signature in database
GPG Key ID: FA5EE906EB55316A
19 changed files with 342 additions and 215 deletions

View File

@ -16,17 +16,20 @@ class Block:
app_hash: str = None
height: int = None
@dataclass
class Script:
id: str = None
script = None
@dataclass
class UTXO:
id: str = None
output_index: int = None
utxo: dict = None
@dataclass
class Transaction:
id: str = None
@ -38,15 +41,16 @@ class Transaction:
outputs: list[Output] = None
script: str = None
@dataclass
class Validator:
id: str = None
height: int = None
validators = None
@dataclass
class ABCIChain:
height: str = None
is_synced: bool = None
chain_id: str = None

View File

@ -9,3 +9,5 @@ from .input import Input
from .metadata import MetaData
from .script import Script
from .output import Output
from .keys import Keys
from .dbtransaction import DbTransaction

View File

@ -7,12 +7,24 @@ from __future__ import annotations
import json
from dataclasses import dataclass
@dataclass
class Asset:
id: str = ""
tx_id: str = ""
data: str = ""
data: dict = ""
@staticmethod
def from_tuple(asset_tuple: tuple) -> Asset:
return Asset(asset_tuple[2], asset_tuple[1], json.loads(asset_tuple[0]))
return Asset(asset_tuple[2], asset_tuple[1], json.loads(asset_tuple[0])["data"])
def to_dict(self) -> dict:
return {
"id": self.id,
"tx_id": self.tx_id,
"data": self.data
}
@staticmethod
def list_to_dict(asset_list: list[Asset]) -> list[dict]:
return [asset.to_dict() for asset in asset_list]

View File

@ -0,0 +1,57 @@
# 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
from planetmint.backend.models import Asset, MetaData, Input, Output, Script
from planetmint.backend.models.keys import Keys
@dataclass
class DbTransaction:
id: str = ""
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) -> DbTransaction:
return DbTransaction(
id=transaction["id"],
operation=transaction["operation"],
version=transaction["version"],
inputs=transaction["inputs"],
raw_transaction=transaction["transaction"],
)
@staticmethod
def from_tuple(transaction: tuple) -> DbTransaction:
return DbTransaction(
id=transaction[0],
operation=transaction[1],
version=transaction[2],
raw_transaction=transaction[3],
)
def to_dict(self) -> dict:
return {
"id": self.id,
"operation": self.operation,
"version": self.version,
"inputs": Input.list_to_dict(self.inputs),
"assets": Asset.list_to_dict(self.assets),
"metadata": self.metadata.to_dict(),
"outputs": Output.list_to_dict(self.outputs),
"keys": self.keys.to_dict(),
"script": self.script.to_dict(),
"transaction": self.raw_transaction,
}

View File

@ -5,6 +5,7 @@
from dataclasses import dataclass
@dataclass
class Fulfills:
transaction_id: str = ""

View File

@ -9,6 +9,7 @@ from typing import Optional
from .fulfills import Fulfills
@dataclass
class Input:
tx_id: str = ""
@ -21,10 +22,7 @@ class Input:
fulfills = None
if input_dict["fulfills"]:
fulfills = Fulfills(
input_dict["fulfills"]["transaction_id"],
input_dict["fulfills"]["output_index"]
)
fulfills = Fulfills(input_dict["fulfills"]["transaction_id"], input_dict["fulfills"]["output_index"])
return Input(tx_id, fulfills, input_dict["owners_before"], input_dict["fulfillment"])
@ -42,14 +40,17 @@ class Input:
return Input(tx_id, fulfills, owners_before, fulfillment)
def to_input_dict(self) -> dict:
fulfills = {
"transaction_id": self.fulfills.transaction_id,
"output_index": self.fulfills.output_index
} if self.fulfills else None
def to_dict(self) -> dict:
fulfills = (
{"transaction_id": self.fulfills.transaction_id, "output_index": self.fulfills.output_index}
if self.fulfills
else None
)
return {"fulfills": fulfills, "fulfillment": self.fulfillment, "owners_before": self.owners_before}
@staticmethod
def list_to_dict(input_list: list[Input]) -> list[dict]:
return [input.to_dict() for input in input_list]
return {
"fulfills": fulfills,
"fulfillment": self.fulfillment,
"owners_before": self.owners_before
}

View File

@ -7,6 +7,7 @@ from __future__ import annotations
from dataclasses import dataclass, field
from typing import Optional
@dataclass
class Keys:
tx_id: str = ""
@ -20,7 +21,6 @@ class Keys:
public_keys=output["public_keys"],
)
@staticmethod
def from_tuple(output: tuple) -> Keys:
return Keys(

View File

@ -8,6 +8,7 @@ import json
from dataclasses import dataclass
from typing import Optional
@dataclass
class MetaData:
id: str = ""
@ -16,3 +17,9 @@ class MetaData:
@staticmethod
def from_tuple(meta_data_tuple: tuple) -> MetaData:
return MetaData(meta_data_tuple[0], json.loads(meta_data_tuple[1]))
def to_dict(self) -> dict:
return {
"id": self.id,
"metadata": self.metadata
}

View File

@ -37,8 +37,9 @@ class Condition:
@dataclass
class Output:
id: str = ""
tx_id: str = ""
amount: int = 0
amount: str = '0'
public_keys: List[str] = field(default_factory=list)
condition: Condition = field(default_factory=Condition)
@ -54,6 +55,7 @@ class Output:
@staticmethod
def from_tuple(output: tuple) -> Output:
return Output(
id=output[5],
tx_id=output[0],
amount=output[1],
condition=Condition(
@ -67,7 +69,7 @@ class Output:
),
)
def to_output_dict(self) -> dict:
def to_dict(self) -> dict:
return {
"id": self.tx_id,
"amount": self.amount,
@ -83,6 +85,10 @@ class Output:
},
}
@staticmethod
def list_to_dict(output_list: list[Output]) -> list[dict]:
return [output.to_dict() for output in output_list]
def output_with_public_key(output, tx_id) -> Output:
return Output(
@ -114,13 +120,8 @@ def output_with_sub_conditions(output, tx_id) -> Output:
type=sub_condition["type"],
public_key=sub_condition["public_key"],
)
for sub_condition in output["condition"]["details"][
"subconditions"
]
for sub_condition in output["condition"]["details"]["subconditions"]
],
),
),
)

View File

@ -7,6 +7,7 @@ from __future__ import annotations
from dataclasses import dataclass
from typing import Optional
@dataclass
class Script:
id: str = ""
@ -16,4 +17,8 @@ class Script:
def from_tuple(script_tuple: tuple) -> Script:
return Script(script_tuple[0], script_tuple[1])
def to_dict(self) -> dict:
return {
"id": self.id,
"script": self.script
}

View File

@ -1,38 +0,0 @@
# 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,
}

View File

@ -6,9 +6,13 @@
"""Query interfaces for backends."""
from functools import singledispatch
from planetmint.backend.models import Asset, MetaData, Output, Input, Script
from planetmint.backend.exceptions import OperationError
from planetmint.backend.interfaces import Asset, Block, MetaData, Input, Script, Output, Transaction
from planetmint.backend.models.keys import Keys
from planetmint.backend.interfaces import Block
from planetmint.backend.models.dbtransaction import DbTransaction
@singledispatch
@ -59,6 +63,7 @@ def store_transactions(connection, signed_transactions):
raise NotImplementedError
@singledispatch
def store_transaction(connection, transaction):
"""Store a single transaction."""
@ -67,14 +72,27 @@ def store_transaction(connection, transaction):
@singledispatch
def get_transaction(conn, 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_transactions(connection, transactions_ids) -> list[Transaction]:
def get_transaction_single(connection, transaction_id) -> DbTransaction:
"""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[DbTransaction]:
"""Get a transaction from the transactions table.
Args:
@ -101,6 +119,20 @@ def get_asset(connection, asset_id) -> Asset:
raise NotImplementedError
@singledispatch
def get_assets_by_tx_id(connection, tx_id: str) -> list[Asset]:
"""Get assets by transaction id.
Args:
tx_id (str): the id of the transaction.
Returns:
The result of the operation.
"""
raise NotImplementedError
@singledispatch
def get_spent(connection, transaction_id, condition_id):
"""Check if a `txid` was already used as an input.
@ -175,6 +207,7 @@ def get_block_with_transaction(connection, txid):
raise NotImplementedError
@singledispatch
def get_metadata_by_tx_id(connection, transaction_id: str) -> MetaData:
"""Get metadata from the metadata table containing `transaction_id`.
@ -188,6 +221,7 @@ def get_metadata_by_tx_id(connection, transaction_id: str) -> MetaData:
"""
raise NotImplementedError
@singledispatch
def store_transaction_outputs_and_keys(connection, output: Output, index: int):
"""Store the transaction outputs.
@ -209,6 +243,7 @@ def store_transaction_outputs(connection, output: Output, index: int):
"""
raise NotImplementedError
@singledispatch
def store_transaction_keys(connection, keys: [Keys], output_id: str, index: int):
"""Store the transaction keys.
@ -480,21 +515,25 @@ def get_latest_abci_chain(conn):
"""
raise NotImplementedError
@singledispatch
def get_inputs_by_tx_id(connection, tx_id) -> list[Input]:
"""Retrieve inputs for a transaction by its id"""
raise NotImplementedError
@singledispatch
def store_transaction_inputs(connection, inputs: list[Input]):
"""Store inputs for a transaction"""
raise NotImplementedError
@singledispatch
def _group_transaction_by_ids(txids: list, connection):
"""Returns the transactions object (JSON TYPE), from list of ids."""
raise NotImplementedError
@singledispatch
def get_script_by_tx_id(connection, tx_id: str) -> Script:
"""Retrieve script for a transaction by its id"""
@ -506,6 +545,7 @@ def get_outputs_by_tx_id(connection, tx_id: str) -> list[Output]:
"""Retrieve outputs for a transaction by its id"""
raise NotImplementedError
@singledispatch
def get_keys_by_tx_id(connection, tx_id: str) -> list[Keys]:
"""Retrieve keys for a transaction by its id"""

View File

@ -11,10 +11,18 @@ 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.models.dbtransaction import DbTransaction
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
@ -23,35 +31,29 @@ register_query = module_dispatch_registrar(query)
@register_query(TarantoolDBConnection)
def _group_transaction_by_ids(connection, txids: list):
def _group_transaction_by_ids(connection, txids: list) -> list[DbTransaction]:
_transactions = []
for txid in txids:
_txobject = connection.run(connection.space(TARANT_TABLE_TRANSACTION).get(txid, index=TARANT_ID_SEARCH))
if _txobject is None:
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(connection, [txid])
_txmeta = get_metadata_by_tx_id(connection, txid)
_txscript = get_script_by_tx_id(connection, txid)
tx.inputs = get_inputs_by_tx_id(connection, txid)
_output = get_outputs_by_tx_id(connection, txid)
_keys = get_keys_by_tx_id(connection, txid)
tx.outputs = [_enricht_output_with_public_keys(_keys, output) for output in _output]
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)
_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)
_transactions.append(tx)
return _transactions
def _enricht_output_with_public_keys(keys: list[Keys], output: Output) -> Output:
output.public_keys = [key.public_keys for key in keys if key.output_id == output.id]
return output
@register_query(TarantoolDBConnection)
def get_inputs_by_tx_id(connection, tx_id: str) -> list[Input]:
_inputs = connection.run(connection.space(TARANT_TABLE_INPUT).select(tx_id, index=TARANT_ID_SEARCH))
@ -73,9 +75,15 @@ 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) -> DbTransaction:
return NotImplemented
@register_query(TarantoolDBConnection)
def store_transaction_inputs(connection, input: Input, index: int):
connection.run(connection.space(TARANT_TABLE_INPUT).insert((
connection.run(
connection.space(TARANT_TABLE_INPUT).insert(
(
input.tx_id,
input.fulfillment,
input.owners_before,
@ -83,8 +91,10 @@ def store_transaction_inputs(connection, input: Input, index: int):
# TODO: the output_index should be an unsigned int
str(input.fulfills.output_index) if input.fulfills else "",
uuid4().hex,
index
)))
index,
)
)
)
@register_query(TarantoolDBConnection)
@ -120,34 +130,32 @@ def store_transaction_outputs(connection, output: Output, index: int) -> str:
index,
)
connection.run(connection.space(TARANT_TABLE_OUTPUT).insert((
tmp_output
)))
connection.run(connection.space(TARANT_TABLE_OUTPUT).insert((tmp_output)))
return output_id
@register_query(TarantoolDBConnection)
def store_transaction_keys(connection, keys: Keys, output_id: str, index: int):
for key in keys.public_keys:
connection.run(connection.space(TARANT_TABLE_KEYS).insert((
uuid4().hex,
keys.tx_id,
output_id,
key,
index
)))
connection.run(connection.space(TARANT_TABLE_KEYS).insert((uuid4().hex, keys.tx_id, output_id, key, index)))
@register_query(TarantoolDBConnection)
def store_transactions(connection, signed_transactions: list):
for transaction in signed_transactions:
store_transaction(connection, transaction)
[store_transaction_inputs(connection, Input.from_dict(input, transaction["id"]), index) for
index, input in enumerate(transaction[TARANT_TABLE_INPUT])]
[
store_transaction_inputs(connection, Input.from_dict(input, transaction["id"]), index)
for index, input in enumerate(transaction[TARANT_TABLE_INPUT])
]
[store_transaction_outputs_and_keys(connection, Output.outputs_and_keys_dict(output, transaction["id"]), index)
for index, output in
enumerate(transaction[TARANT_TABLE_OUTPUT])]
[
store_transaction_outputs_and_keys(
connection, Output.outputs_and_keys_dict(output, transaction["id"]), index
)
for index, output in enumerate(transaction[TARANT_TABLE_OUTPUT])
]
store_metadatas(connection, [MetaData(transaction["id"], transaction["metadata"])])
@ -160,39 +168,39 @@ def store_transactions(connection, signed_transactions: list):
if TARANT_TABLE_SCRIPT in transaction:
connection.run(
connection.space(TARANT_TABLE_SCRIPT).insert((transaction["id"], transaction[TARANT_TABLE_SCRIPT])),
only_data=False)
only_data=False,
)
@register_query(TarantoolDBConnection)
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)
tx = (transaction["id"], transaction["operation"], transaction["version"], [transaction])
connection.run(connection.space(TARANT_TABLE_TRANSACTION).insert(tx), only_data=False)
@register_query(TarantoolDBConnection)
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)))
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 DbTransaction.from_tuple(txs[0])
@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]
def get_transaction_single(connection, transaction_id) -> DbTransaction:
return _group_transaction_by_ids(txids=[transaction_id], connection=connection)[0]
@register_query(TarantoolDBConnection)
def get_transactions(connection, transactions_ids: list) -> list[DbTransaction]:
return _group_transaction_by_ids(txids=transactions_ids, connection=connection)
@register_query(TarantoolDBConnection)
def store_metadatas(connection, metadata: list[MetaData]):
for meta in metadata:
connection.run(
connection.space(TARANT_TABLE_META_DATA).insert(
(meta.id, json.dumps(meta.metadata))
) # noqa: E713
connection.space(TARANT_TABLE_META_DATA).insert((meta.id, json.dumps(meta.metadata))) # noqa: E713
)
@ -242,20 +250,36 @@ def get_assets(connection, assets_ids: list) -> list[Asset]:
_returned_data = []
for _id in list(set(assets_ids)):
res = connection.run(connection.space(TARANT_TABLE_ASSETS).select(_id, index=TARANT_TX_ID_SEARCH))
if len(res) is 0:
continue
_returned_data.append(res[0])
sorted_assets = sorted(_returned_data, key=lambda k: k[1], reverse=False)
return [Asset.from_tuple(asset) for asset in sorted_assets]
@register_query(TarantoolDBConnection)
def get_assets_by_tx_id(connection, tx_id: str) -> list[Asset]:
res = connection.run(connection.space(TARANT_TABLE_ASSETS).select(tx_id, index=TARANT_TX_ID_SEARCH))
if len(res) > 1:
return _from_tuple_list_to_asset_list(res)
sorted_assets = sorted(res, key=lambda k: k[1], reverse=False)
return _from_tuple_list_to_asset_list(sorted_assets)
def _from_tuple_list_to_asset_list(_data: list) -> list[Asset]:
return [Asset.from_tuple(asset) for asset in _data]
@register_query(TarantoolDBConnection)
def get_spent(connection, fullfil_transaction_id: str, fullfil_output_index: str):
_inputs = connection.run(
connection.space(TARANT_TABLE_INPUT).select([fullfil_transaction_id, str(fullfil_output_index)],
index="spent_search")
connection.space(TARANT_TABLE_INPUT).select(
[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)
@ -313,7 +337,9 @@ def get_txids_filtered(
_transactions.extend(_tmp_transactions)
else:
_tx_ids = connection.run(connection.space(TARANT_TABLE_TRANSACTION).select(asset_ids, index=TARANT_ID_SEARCH))
_assets_ids = connection.run(connection.space(TARANT_TABLE_ASSETS).select(asset_ids, index="only_asset_search"))
_assets_ids = connection.run(
connection.space(TARANT_TABLE_ASSETS).select(asset_ids, index="only_asset_search")
)
return tuple(set([sublist[1] for sublist in _assets_ids] + [sublist[0] for sublist in _tx_ids]))
if last_tx:
@ -347,8 +373,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)
@ -392,20 +417,27 @@ def delete_transactions(connection, txn_ids: list):
for _id in txn_ids:
connection.run(connection.space(TARANT_TABLE_TRANSACTION).delete(_id), only_data=False)
for _id in txn_ids:
_inputs = connection.run(connection.space(TARANT_TABLE_INPUT).select(_id, index=TARANT_ID_SEARCH),
only_data=False)
_outputs = connection.run(connection.space(TARANT_TABLE_OUTPUT).select(_id, index=TARANT_ID_SEARCH),
only_data=False)
_keys = connection.run(connection.space(TARANT_TABLE_KEYS).select(_id, index=TARANT_TX_ID_SEARCH),
only_data=False)
_inputs = connection.run(
connection.space(TARANT_TABLE_INPUT).select(_id, index=TARANT_ID_SEARCH), only_data=False
)
_outputs = connection.run(
connection.space(TARANT_TABLE_OUTPUT).select(_id, index=TARANT_ID_SEARCH), only_data=False
)
_keys = connection.run(
connection.space(TARANT_TABLE_KEYS).select(_id, index=TARANT_TX_ID_SEARCH), only_data=False
)
for _kID in _keys:
connection.run(connection.space(TARANT_TABLE_KEYS).delete(_kID[0], index=TARANT_ID_SEARCH), only_data=False)
connection.run(
connection.space(TARANT_TABLE_KEYS).delete(_kID[0], index=TARANT_ID_SEARCH), only_data=False
)
for _inpID in _inputs:
connection.run(connection.space(TARANT_TABLE_INPUT).delete(_inpID[5], index="delete_search"),
only_data=False)
connection.run(
connection.space(TARANT_TABLE_INPUT).delete(_inpID[5], index="delete_search"), only_data=False
)
for _outpID in _outputs:
connection.run(connection.space(TARANT_TABLE_OUTPUT).delete(_outpID[5], index="unique_search"),
only_data=False)
connection.run(
connection.space(TARANT_TABLE_OUTPUT).delete(_outpID[5], index="unique_search"), only_data=False
)
for _id in txn_ids:
connection.run(connection.space(TARANT_TABLE_META_DATA).delete(_id, index=TARANT_ID_SEARCH), only_data=False)
@ -548,8 +580,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)

View File

@ -1,7 +1,14 @@
from transactions.common.memoize import HDict
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
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,
)
def get_items(_list):

View File

@ -18,7 +18,7 @@ class FastQuery:
"""Get outputs for a public key"""
txs = list(query.get_owned_ids(self.connection, public_key))
return [
TransactionLink(tx["id"], index)
TransactionLink(tx["transactions"].id, index)
for tx in txs
for index, output in enumerate(tx["outputs"])
if condition_details_has_owner(output["condition"]["details"], public_key)

View File

@ -8,11 +8,8 @@ MongoDB.
"""
import logging
from collections import namedtuple
from uuid import uuid4
from planetmint.backend.connection import Connection
from hashlib import sha3_256
import json
import rapidjson
import requests
@ -40,6 +37,7 @@ from transactions.common.transaction import VALIDATOR_ELECTION, CHAIN_MIGRATION_
from transactions.common.transaction_mode_types import BROADCAST_TX_COMMIT, BROADCAST_TX_ASYNC, BROADCAST_TX_SYNC
from transactions.types.elections.election import Election
from transactions.types.elections.validator_utils import election_id_to_public_key
from planetmint.config import Config
from planetmint import backend, config_utils, fastquery
from planetmint.tendermint_utils import (
@ -226,12 +224,11 @@ class Planetmint(object):
return backend.query.delete_unspent_outputs(self.connection, *unspent_outputs)
def is_committed(self, transaction_id):
transaction = backend.query.get_transaction(self.connection, transaction_id)
transaction = backend.query.get_transaction_space_by_id(self.connection, transaction_id)
return bool(transaction)
def get_transaction(self, transaction_id):
transaction = backend.query.get_transaction(self.connection, transaction_id)
return Transaction.from_dict(transaction, False)
return backend.query.get_transaction_single(self.connection, transaction_id)
def get_transactions(self, txn_ids):
return backend.query.get_transactions(self.connection, txn_ids)
@ -265,7 +262,6 @@ class Planetmint(object):
def get_spent(self, txid, output, current_transactions=[]):
transactions = backend.query.get_spent(self.connection, txid, output)
transactions = list(transactions) if transactions else []
if len(transactions) > 1:
raise core_exceptions.CriticalDoubleSpend(
"`{}` was spent more than once. There is a problem" " with the chain".format(txid)
@ -281,10 +277,10 @@ class Planetmint(object):
if len(transactions) + len(current_spent_transactions) > 1:
raise DoubleSpend('tx "{}" spends inputs twice'.format(txid))
elif transactions:
transaction = backend.query.get_transaction(self.connection, transactions[0]["id"])
assets = backend.query.get_assets(self.connection, [transaction["id"]])
transaction["assets"] = [asset.data for asset in assets]
transaction = Transaction.from_dict(transaction, False)
tx_id = transactions[0]["transactions"].id
tx = backend.query.get_transaction_single(self.connection, tx_id)
tx.assets = backend.query.get_assets_by_tx_id(self.connection, tx_id)
transaction = tx.to_dict()
elif current_spent_transactions:
transaction = current_spent_transactions[0]
@ -697,7 +693,7 @@ class Planetmint(object):
return recipients
def show_election_status(self, transaction):
data = transaction.assets[0]["data"]
data = transaction.assets[0]
if "public_key" in data.keys():
data["public_key"] = public_key_to_base64(data["public_key"]["value"])
response = ""
@ -746,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)
txns = backend.query.get_asset_tokens_for_public_key(self.connection, transaction.id, election_pk)
return self.count_votes(election_pk, txns)
def _get_initiated_elections(self, height, txns): # TODO: move somewhere else
elections = []
@ -855,7 +851,7 @@ class Planetmint(object):
votes_committed = self.get_commited_votes(transaction, election_pk)
votes_current = self.count_votes(election_pk, current_votes)
total_votes = sum(output.amount for output in transaction.outputs)
total_votes = sum(int(output.amount) for output in transaction.outputs)
if (votes_committed < (2 / 3) * total_votes) and (votes_committed + votes_current >= (2 / 3) * total_votes):
return True
@ -913,7 +909,7 @@ class Planetmint(object):
if election.operation == CHAIN_MIGRATION_ELECTION:
self.migrate_abci_chain()
if election.operation == VALIDATOR_ELECTION:
validator_updates = [election.assets[0]["data"]]
validator_updates = [election.assets[0].data]
curr_validator_set = self.get_validators(new_height)
updated_validator_set = new_validator_set(curr_validator_set, validator_updates)
@ -921,7 +917,7 @@ class Planetmint(object):
# TODO change to `new_height + 2` when upgrading to Tendermint 0.24.0.
self.store_validator_set(new_height + 1, updated_validator_set)
return encode_validator(election.assets[0]["data"])
return encode_validator(election.assets[0].data)
Block = namedtuple("Block", ("app_hash", "height", "transactions"))

View File

@ -49,7 +49,7 @@ def test_write_assets(db_conn):
Asset("2", "2", "2"),
Asset("3", "3", "3"),
# Duplicated id. Should not be written to the database
Asset("1", "1", "1")
Asset("1", "1", "1"),
]
# write the assets
@ -186,7 +186,7 @@ def test_get_metadata(db_conn):
metadata = [
MetaData("dd86682db39e4b424df0eec1413cfad65488fd48712097c5d865ca8e8e059b64", None),
MetaData("55a2303e3bcd653e4b5bd7118d39c0e2d48ee2f18e22fbcf64e906439bdeb45d", {"key": "value"})
MetaData("55a2303e3bcd653e4b5bd7118d39c0e2d48ee2f18e22fbcf64e906439bdeb45d", {"key": "value"}),
]
# conn.db.metadata.insert_many(deepcopy(metadata), ordered=False)
@ -204,8 +204,8 @@ def test_get_owned_ids(signed_create_tx, user_pk, db_conn):
query.store_transactions(connection=db_conn, signed_transactions=[signed_create_tx.to_dict()])
txns = list(query.get_owned_ids(connection=db_conn, owner=user_pk))
tx_dict = signed_create_tx.to_dict()
founded = [tx for tx in txns if tx["id"] == tx_dict["id"]]
assert founded[0] == tx_dict
founded = [tx for tx in txns if tx["transactions"].id == tx_dict["id"]]
assert founded[0]["transactions"].raw_transaction == tx_dict
def test_get_spending_transactions(user_pk, user_sk, db_conn):
@ -225,7 +225,8 @@ def test_get_spending_transactions(user_pk, user_sk, db_conn):
txns = list(query.get_spending_transactions(connection=db_conn, inputs=links))
# tx3 not a member because input 1 not asked for
assert txns == [tx2.to_dict(), tx4.to_dict()]
assert txns[0]["transactions"].raw_transaction == tx2.to_dict()
assert txns[1]["transactions"].raw_transaction == tx4.to_dict()
def test_get_spending_transactions_multiple_inputs(db_conn):
@ -261,7 +262,7 @@ def test_get_spending_transactions_multiple_inputs(db_conn):
txns = list(query.get_spending_transactions(connection=db_conn, inputs=[li]))
assert len(txns) == num
if len(txns):
assert [tx["id"] for tx in txns] == match
assert [tx["transactions"].id for tx in txns] == match
def test_store_block(db_conn):

View File

@ -110,10 +110,10 @@ class TestBigchainApi(object):
before = tx.to_dict()
after = tx_from_db.to_dict()
assert before["assets"][0]["data"] == after["assets"][0]["data"]
assert before["assets"][0] == after["transaction"]["assets"][0]
before.pop("asset", None)
after.pop("asset", None)
assert before == after
after["transaction"].pop("asset", None)
assert before == after["transaction"]
class TestTransactionValidation(object):

View File

@ -67,8 +67,8 @@ def test_asset_is_separated_from_transaciton(b):
tx_dict = copy.deepcopy(tx.to_dict())
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 "asset" not in backend.query.get_transaction_single(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