mirror of
https://github.com/planetmint/planetmint.git
synced 2025-11-25 15:05:49 +00:00
Adapt models
Signed-off-by: cybnon <stefan.weber93@googlemail.com>
This commit is contained in:
parent
1832bf4814
commit
cd74ea578d
@ -10,21 +10,21 @@ from dataclasses import dataclass
|
|||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
class Asset:
|
class Asset:
|
||||||
id: str = ""
|
data: str = ""
|
||||||
tx_id: str = ""
|
|
||||||
data: dict = ""
|
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def from_tuple(asset_tuple: tuple) -> Asset:
|
def from_dict(asset_tuple: dict) -> Asset:
|
||||||
return Asset(asset_tuple[2], asset_tuple[1], json.loads(asset_tuple[0])["data"])
|
return Asset(asset_tuple["data"])
|
||||||
|
|
||||||
def to_dict(self) -> dict:
|
def to_dict(self) -> dict:
|
||||||
return {
|
return {
|
||||||
"id": self.id,
|
|
||||||
"tx_id": self.tx_id,
|
|
||||||
"data": self.data
|
"data": self.data
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def from_list_dict(asset_tuple_list: list[tuple]) -> list[Asset]:
|
||||||
|
return [Asset.from_dict(asset_tuple) for asset_tuple in asset_tuple_list]
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def list_to_dict(asset_list: list[Asset]) -> list[dict]:
|
def list_to_dict(asset_list: list[Asset]) -> list[dict]:
|
||||||
return [asset.to_dict() for asset in asset_list]
|
return [asset.to_dict() for asset in asset_list or []]
|
||||||
|
|||||||
@ -15,12 +15,9 @@ class DbTransaction:
|
|||||||
id: str = ""
|
id: str = ""
|
||||||
operation: str = ""
|
operation: str = ""
|
||||||
version: str = ""
|
version: str = ""
|
||||||
raw_transaction: dict = dict
|
|
||||||
assets: list[Asset] = None
|
|
||||||
metadata: MetaData = None
|
metadata: MetaData = None
|
||||||
|
assets: list[Asset] = None
|
||||||
inputs: list[Input] = None
|
inputs: list[Input] = None
|
||||||
outputs: list[Output] = None
|
|
||||||
keys: Keys = None
|
|
||||||
script: Script = None
|
script: Script = None
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
@ -29,8 +26,10 @@ class DbTransaction:
|
|||||||
id=transaction["id"],
|
id=transaction["id"],
|
||||||
operation=transaction["operation"],
|
operation=transaction["operation"],
|
||||||
version=transaction["version"],
|
version=transaction["version"],
|
||||||
inputs=transaction["inputs"],
|
inputs=Input.from_list_dict(transaction["inputs"]),
|
||||||
raw_transaction=transaction["transaction"],
|
assets=Asset.from_list_dict(transaction["assets"]),
|
||||||
|
metadata=MetaData.from_dict(transaction["metadata"]),
|
||||||
|
script=Script.from_dict(transaction["script"]),
|
||||||
)
|
)
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
@ -39,7 +38,10 @@ class DbTransaction:
|
|||||||
id=transaction[0],
|
id=transaction[0],
|
||||||
operation=transaction[1],
|
operation=transaction[1],
|
||||||
version=transaction[2],
|
version=transaction[2],
|
||||||
raw_transaction=transaction[3],
|
metadata=MetaData.from_dict(transaction[3]),
|
||||||
|
assets=Asset.from_list_dict(transaction[4]),
|
||||||
|
inputs=Input.from_list_dict(transaction[5]),
|
||||||
|
script=Script.from_dict(transaction[6]),
|
||||||
)
|
)
|
||||||
|
|
||||||
def to_dict(self) -> dict:
|
def to_dict(self) -> dict:
|
||||||
@ -49,9 +51,6 @@ class DbTransaction:
|
|||||||
"version": self.version,
|
"version": self.version,
|
||||||
"inputs": Input.list_to_dict(self.inputs),
|
"inputs": Input.list_to_dict(self.inputs),
|
||||||
"assets": Asset.list_to_dict(self.assets),
|
"assets": Asset.list_to_dict(self.assets),
|
||||||
"metadata": self.metadata.to_dict(),
|
"metadata": self.metadata.to_dict() if self.metadata is not None else None,
|
||||||
"outputs": Output.list_to_dict(self.outputs),
|
"script": self.script.to_dict() if self.script is not None else None,
|
||||||
"keys": self.keys.to_dict(),
|
|
||||||
"script": self.script.to_dict(),
|
|
||||||
"transaction": self.raw_transaction,
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -49,8 +49,12 @@ class Input:
|
|||||||
|
|
||||||
return {"fulfills": fulfills, "fulfillment": self.fulfillment, "owners_before": self.owners_before}
|
return {"fulfills": fulfills, "fulfillment": self.fulfillment, "owners_before": self.owners_before}
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def from_list_dict(input_tuple_list: list[dict]) -> list[Input]:
|
||||||
|
return [Input.from_dict(input_tuple) for input_tuple in input_tuple_list]
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def list_to_dict(input_list: list[Input]) -> list[dict]:
|
def list_to_dict(input_list: list[Input]) -> list[dict]:
|
||||||
return [input.to_dict() for input in input_list]
|
return [input.to_dict() for input in input_list or []]
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -11,15 +11,15 @@ from typing import Optional
|
|||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
class MetaData:
|
class MetaData:
|
||||||
id: str = ""
|
|
||||||
metadata: Optional[str] = None
|
metadata: Optional[str] = None
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def from_tuple(meta_data_tuple: tuple) -> MetaData:
|
def from_dict(meta_data_tuple: dict) -> MetaData:
|
||||||
return MetaData(meta_data_tuple[0], json.loads(meta_data_tuple[1]))
|
if meta_data_tuple is None:
|
||||||
|
return MetaData()
|
||||||
|
return MetaData(meta_data_tuple["meta_data"])
|
||||||
|
|
||||||
def to_dict(self) -> dict:
|
def to_dict(self) -> dict:
|
||||||
return {
|
return {
|
||||||
"id": self.id,
|
|
||||||
"metadata": self.metadata
|
"metadata": self.metadata
|
||||||
}
|
}
|
||||||
|
|||||||
@ -15,6 +15,12 @@ class SubCondition:
|
|||||||
type: str
|
type: str
|
||||||
public_key: str
|
public_key: str
|
||||||
|
|
||||||
|
def to_tuple(self) -> tuple:
|
||||||
|
return self.type, self.public_key
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def from_dict(subcondition_dict: dict) -> SubCondition:
|
||||||
|
return SubCondition(subcondition_dict["type"], subcondition_dict["public_key"])
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
class ConditionDetails:
|
class ConditionDetails:
|
||||||
@ -23,11 +29,17 @@ class ConditionDetails:
|
|||||||
threshold: int = 0
|
threshold: int = 0
|
||||||
sub_conditions: list[SubCondition] = None
|
sub_conditions: list[SubCondition] = None
|
||||||
|
|
||||||
def sub_conditions_to_list_dict(self):
|
@staticmethod
|
||||||
if self.sub_conditions is None:
|
def from_dict(data: dict) -> ConditionDetails:
|
||||||
return None
|
sub_conditions = None
|
||||||
return [sub_condition.__dict__ for sub_condition in self.sub_conditions]
|
if data["sub_conditions"] is not None:
|
||||||
|
sub_conditions = [SubCondition.from_dict(sub_condition) for sub_condition in data["sub_conditions"]]
|
||||||
|
return ConditionDetails(
|
||||||
|
type=data.get("type"),
|
||||||
|
public_key=data.get("public_key"),
|
||||||
|
threshold=data.get("threshold"),
|
||||||
|
sub_conditions=sub_conditions,
|
||||||
|
)
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
class Condition:
|
class Condition:
|
||||||
@ -35,43 +47,60 @@ class Condition:
|
|||||||
details: ConditionDetails = field(default_factory=ConditionDetails)
|
details: ConditionDetails = field(default_factory=ConditionDetails)
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
|
||||||
class Output:
|
|
||||||
id: str = ""
|
|
||||||
tx_id: str = ""
|
|
||||||
amount: str = '0'
|
|
||||||
public_keys: List[str] = field(default_factory=list)
|
|
||||||
condition: Condition = field(default_factory=Condition)
|
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def outputs_and_keys_dict(output: dict, tx_id: str = "") -> (Output, Keys):
|
def from_dict(data: dict) -> Condition:
|
||||||
out_dict: Output
|
return Condition(
|
||||||
if output["condition"]["details"].get("subconditions") is None:
|
uri=data.get("uri"),
|
||||||
out_dict = output_with_public_key(output, tx_id)
|
details=ConditionDetails.from_dict(data.get("details")),
|
||||||
else:
|
|
||||||
out_dict = output_with_sub_conditions(output, tx_id)
|
|
||||||
return out_dict, Keys.from_dict(output, tx_id)
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def from_tuple(output: tuple) -> Output:
|
|
||||||
return Output(
|
|
||||||
id=output[5],
|
|
||||||
tx_id=output[0],
|
|
||||||
amount=output[1],
|
|
||||||
condition=Condition(
|
|
||||||
uri=output[2],
|
|
||||||
details=ConditionDetails(
|
|
||||||
type=output[3],
|
|
||||||
public_key=output[4],
|
|
||||||
threshold=output[6],
|
|
||||||
sub_conditions=output[7],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
)
|
)
|
||||||
|
|
||||||
def to_dict(self) -> dict:
|
def to_dict(self) -> dict:
|
||||||
return {
|
return {
|
||||||
"id": self.tx_id,
|
"uri": self.uri,
|
||||||
|
"details": self.details.__dict__,
|
||||||
|
}
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def list_of_sub_conditions_to_tuple(sub_conditions: List[SubCondition]) -> tuple:
|
||||||
|
sub_con_tuple = None
|
||||||
|
if sub_conditions is not None:
|
||||||
|
sub_con_tuple = [sub_condition.to_tuple() for sub_condition in sub_conditions]
|
||||||
|
return sub_con_tuple
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class Output:
|
||||||
|
id: str = ""
|
||||||
|
amount: int = 0
|
||||||
|
transaction_id: str = ""
|
||||||
|
public_keys: List[str] = field(default_factory=list)
|
||||||
|
index: int = 0
|
||||||
|
condition: Condition = field(default_factory=Condition)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def outputs_dict(output: dict, transaction_id: str = "") -> Output:
|
||||||
|
out_dict: Output
|
||||||
|
if output["condition"]["details"].get("subconditions") is None:
|
||||||
|
out_dict = output_with_public_key(output, transaction_id)
|
||||||
|
else:
|
||||||
|
out_dict = output_with_sub_conditions(output, transaction_id)
|
||||||
|
return out_dict
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def from_tuple(output: tuple) -> Output:
|
||||||
|
return Output(
|
||||||
|
id=output[0],
|
||||||
|
amount=output[1],
|
||||||
|
public_keys=output[2],
|
||||||
|
condition=Condition.from_dict(
|
||||||
|
output[3],
|
||||||
|
),
|
||||||
|
index=output[4],
|
||||||
|
transaction_id=output[5],
|
||||||
|
)
|
||||||
|
|
||||||
|
def to_dict(self) -> dict:
|
||||||
|
return {
|
||||||
|
"id": self.transaction_id,
|
||||||
"amount": self.amount,
|
"amount": self.amount,
|
||||||
"public_keys": self.public_keys,
|
"public_keys": self.public_keys,
|
||||||
"condition": {
|
"condition": {
|
||||||
@ -85,14 +114,15 @@ class Output:
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def list_to_dict(output_list: list[Output]) -> list[dict]:
|
def list_to_dict(output_list: list[Output]) -> list[dict]:
|
||||||
return [output.to_dict() for output in output_list]
|
return [output.to_dict() for output in output_list or []]
|
||||||
|
|
||||||
|
|
||||||
def output_with_public_key(output, tx_id) -> Output:
|
def output_with_public_key(output, transaction_id) -> Output:
|
||||||
return Output(
|
return Output(
|
||||||
tx_id=tx_id,
|
transaction_id=transaction_id,
|
||||||
public_keys=output["public_keys"],
|
public_keys=output["public_keys"],
|
||||||
amount=output["amount"],
|
amount=output["amount"],
|
||||||
condition=Condition(
|
condition=Condition(
|
||||||
@ -105,9 +135,9 @@ def output_with_public_key(output, tx_id) -> Output:
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def output_with_sub_conditions(output, tx_id) -> Output:
|
def output_with_sub_conditions(output, transaction_id) -> Output:
|
||||||
return Output(
|
return Output(
|
||||||
tx_id=tx_id,
|
transaction_id=transaction_id,
|
||||||
public_keys=output["public_keys"],
|
public_keys=output["public_keys"],
|
||||||
amount=output["amount"],
|
amount=output["amount"],
|
||||||
condition=Condition(
|
condition=Condition(
|
||||||
|
|||||||
@ -10,15 +10,15 @@ from typing import Optional
|
|||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
class Script:
|
class Script:
|
||||||
id: str = ""
|
script: dict = None
|
||||||
script: Optional[str] = None
|
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def from_tuple(script_tuple: tuple) -> Script:
|
def from_dict(script_dict: dict) -> Script:
|
||||||
return Script(script_tuple[0], script_tuple[1])
|
if script_dict is None:
|
||||||
|
return Script()
|
||||||
|
return Script(script_dict["script"])
|
||||||
|
|
||||||
def to_dict(self) -> dict:
|
def to_dict(self) -> dict:
|
||||||
return {
|
return {
|
||||||
"id": self.id,
|
|
||||||
"script": self.script
|
"script": self.script
|
||||||
}
|
}
|
||||||
|
|||||||
@ -12,3 +12,6 @@ TARANT_TABLE_OUTPUT = "outputs"
|
|||||||
TARANT_TABLE_SCRIPT = "scripts"
|
TARANT_TABLE_SCRIPT = "scripts"
|
||||||
TARANT_TX_ID_SEARCH = "transaction_id"
|
TARANT_TX_ID_SEARCH = "transaction_id"
|
||||||
TARANT_ID_SEARCH = "id"
|
TARANT_ID_SEARCH = "id"
|
||||||
|
|
||||||
|
TARANT_INDEX_TX_BY_ASSET_ID = "transactions_by_asset"
|
||||||
|
TARANT_INDEX_SPENDING_BY_ID_AND_OUTPUT_INDEX = "spending_transaction_by_id_and_output_index"
|
||||||
|
|||||||
@ -8,10 +8,10 @@ import json
|
|||||||
from uuid import uuid4
|
from uuid import uuid4
|
||||||
from hashlib import sha256
|
from hashlib import sha256
|
||||||
from operator import itemgetter
|
from operator import itemgetter
|
||||||
from typing import Union
|
|
||||||
from tarantool.error import DatabaseError
|
from planetmint.backend.models.output import Condition
|
||||||
|
|
||||||
from planetmint.backend import query
|
from planetmint.backend import query
|
||||||
from planetmint.backend.models.keys import Keys
|
|
||||||
from planetmint.backend.models.dbtransaction import DbTransaction
|
from planetmint.backend.models.dbtransaction import DbTransaction
|
||||||
from planetmint.backend.tarantool.const import (
|
from planetmint.backend.tarantool.const import (
|
||||||
TARANT_TABLE_META_DATA,
|
TARANT_TABLE_META_DATA,
|
||||||
@ -22,7 +22,7 @@ from planetmint.backend.tarantool.const import (
|
|||||||
TARANT_TABLE_OUTPUT,
|
TARANT_TABLE_OUTPUT,
|
||||||
TARANT_TABLE_SCRIPT,
|
TARANT_TABLE_SCRIPT,
|
||||||
TARANT_TX_ID_SEARCH,
|
TARANT_TX_ID_SEARCH,
|
||||||
TARANT_ID_SEARCH,
|
TARANT_ID_SEARCH, TARANT_INDEX_TX_BY_ASSET_ID, TARANT_INDEX_SPENDING_BY_ID_AND_OUTPUT_INDEX,
|
||||||
)
|
)
|
||||||
from planetmint.backend.utils import module_dispatch_registrar
|
from planetmint.backend.utils import module_dispatch_registrar
|
||||||
from planetmint.backend.models import Asset, Block, MetaData, Input, Script, Output
|
from planetmint.backend.models import Asset, Block, MetaData, Input, Script, Output
|
||||||
@ -38,144 +38,61 @@ def _group_transaction_by_ids(connection, txids: list) -> list[DbTransaction]:
|
|||||||
tx = get_transaction_space_by_id(connection, txid)
|
tx = get_transaction_space_by_id(connection, txid)
|
||||||
if tx is None:
|
if tx is None:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
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)
|
|
||||||
|
|
||||||
_transactions.append(tx)
|
_transactions.append(tx)
|
||||||
return _transactions
|
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))
|
|
||||||
_sorted_inputs = sorted(_inputs, key=itemgetter(6))
|
|
||||||
return [Input.from_tuple(input) for input in _sorted_inputs]
|
|
||||||
|
|
||||||
|
|
||||||
@register_query(TarantoolDBConnection)
|
@register_query(TarantoolDBConnection)
|
||||||
def get_outputs_by_tx_id(connection, tx_id: str) -> list[Output]:
|
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))
|
_outputs = connection.run(connection.space(TARANT_TABLE_OUTPUT).select(tx_id, index=TARANT_TX_ID_SEARCH))
|
||||||
_sorted_outputs = sorted(_outputs, key=itemgetter(8))
|
_sorted_outputs = sorted(_outputs, key=itemgetter(4))
|
||||||
return [Output.from_tuple(output) for output in _sorted_outputs]
|
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_TX_ID_SEARCH))
|
|
||||||
_sorted_keys = sorted(_keys, key=itemgetter(4))
|
|
||||||
return [Keys.from_tuple(key) for key in _sorted_keys]
|
|
||||||
|
|
||||||
|
|
||||||
@register_query(TarantoolDBConnection)
|
@register_query(TarantoolDBConnection)
|
||||||
def get_transaction(connection, tx_id: str) -> DbTransaction:
|
def get_transaction(connection, tx_id: str) -> DbTransaction:
|
||||||
return NotImplemented
|
return NotImplemented
|
||||||
|
|
||||||
@register_query(TarantoolDBConnection)
|
|
||||||
def store_transaction_inputs(connection, input: Input, index: int):
|
|
||||||
connection.run(
|
|
||||||
connection.space(TARANT_TABLE_INPUT).insert(
|
|
||||||
(
|
|
||||||
input.tx_id,
|
|
||||||
input.fulfillment,
|
|
||||||
input.owners_before,
|
|
||||||
input.fulfills.transaction_id if input.fulfills else "",
|
|
||||||
# TODO: the output_index should be an unsigned int
|
|
||||||
str(input.fulfills.output_index) if input.fulfills else "",
|
|
||||||
uuid4().hex,
|
|
||||||
index,
|
|
||||||
)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
@register_query(TarantoolDBConnection)
|
|
||||||
def store_transaction_outputs_and_keys(connection, output_key: (Output, Keys), index: int):
|
|
||||||
output_id = store_transaction_outputs(connection, output_key[0], index)
|
|
||||||
store_transaction_keys(connection, output_key[1], output_id, index)
|
|
||||||
|
|
||||||
|
|
||||||
def store_transaction_outputs(connection, output: Output, index: int) -> str:
|
def store_transaction_outputs(connection, output: Output, index: int) -> str:
|
||||||
|
# TODO: store public keys as well
|
||||||
|
|
||||||
output_id = uuid4().hex
|
output_id = uuid4().hex
|
||||||
if output.condition.details.sub_conditions is None:
|
connection.run(connection.space(TARANT_TABLE_OUTPUT).insert((
|
||||||
tmp_output = (
|
output_id,
|
||||||
output.tx_id,
|
int(output.amount),
|
||||||
output.amount,
|
output.public_keys,
|
||||||
output.condition.uri if output.condition else "",
|
output.condition.to_dict(),
|
||||||
output.condition.details.type if output.condition.details else "",
|
index,
|
||||||
output.condition.details.public_key if output.condition.details else "",
|
output.transaction_id,
|
||||||
output_id,
|
)))
|
||||||
None,
|
|
||||||
None,
|
|
||||||
index,
|
|
||||||
)
|
|
||||||
else:
|
|
||||||
tmp_output = (
|
|
||||||
output.tx_id,
|
|
||||||
output.amount,
|
|
||||||
output.condition.uri if output.condition else "",
|
|
||||||
output.condition.details.type if output.condition.details else "",
|
|
||||||
None,
|
|
||||||
output_id,
|
|
||||||
output.condition.details.threshold if output.condition.details else "",
|
|
||||||
output.condition.details.sub_conditions_to_list_dict() if output.condition.details.sub_conditions else "",
|
|
||||||
index,
|
|
||||||
)
|
|
||||||
|
|
||||||
connection.run(connection.space(TARANT_TABLE_OUTPUT).insert((tmp_output)))
|
|
||||||
return output_id
|
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)))
|
|
||||||
|
|
||||||
|
|
||||||
@register_query(TarantoolDBConnection)
|
@register_query(TarantoolDBConnection)
|
||||||
def store_transactions(connection, signed_transactions: list):
|
def store_transactions(connection, signed_transactions: list):
|
||||||
for transaction in signed_transactions:
|
for transaction in signed_transactions:
|
||||||
store_transaction(connection, transaction)
|
store_transaction(connection, transaction)
|
||||||
|
|
||||||
[
|
[
|
||||||
store_transaction_inputs(connection, Input.from_dict(input, transaction["id"]), index)
|
store_transaction_outputs(connection, Output.outputs_dict(output, 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])
|
for index, output in enumerate(transaction[TARANT_TABLE_OUTPUT])
|
||||||
]
|
]
|
||||||
|
|
||||||
# store_metadatas(connection, [MetaData(transaction["id"], transaction["metadata"])])
|
|
||||||
|
|
||||||
# assets = []
|
|
||||||
# for asset in transaction[TARANT_TABLE_ASSETS]:
|
|
||||||
# id = transaction["id"] if "id" not in asset else asset["id"]
|
|
||||||
# assets.append(Asset(id, transaction["id"], asset))
|
|
||||||
# store_assets(connection, assets)
|
|
||||||
|
|
||||||
if TARANT_TABLE_SCRIPT in transaction:
|
|
||||||
connection.run(
|
|
||||||
connection.space(TARANT_TABLE_SCRIPT).insert((transaction["id"], transaction[TARANT_TABLE_SCRIPT])),
|
|
||||||
only_data=False,
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
@register_query(TarantoolDBConnection)
|
@register_query(TarantoolDBConnection)
|
||||||
def store_transaction(connection, transaction):
|
def store_transaction(connection, transaction):
|
||||||
tx = (transaction["id"], transaction["operation"], transaction["version"], [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_TRANSACTION).insert(tx), only_data=False)
|
connection.run(connection.space(TARANT_TABLE_TRANSACTION).insert(tx), only_data=False)
|
||||||
|
|
||||||
|
|
||||||
@ -197,87 +114,30 @@ def get_transactions(connection, transactions_ids: list) -> list[DbTransaction]:
|
|||||||
return _group_transaction_by_ids(txids=transactions_ids, connection=connection)
|
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
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
@register_query(TarantoolDBConnection)
|
|
||||||
def get_metadata(connection, transaction_ids: list) -> list[MetaData]:
|
|
||||||
_returned_data = []
|
|
||||||
for _id in transaction_ids:
|
|
||||||
metadata = connection.run(connection.space(TARANT_TABLE_META_DATA).select(_id, index=TARANT_ID_SEARCH))
|
|
||||||
if metadata is not None:
|
|
||||||
if len(metadata) > 0:
|
|
||||||
metadata[0] = list(metadata[0])
|
|
||||||
metadata[0][1] = json.loads(metadata[0][1])
|
|
||||||
metadata = MetaData(metadata[0][0], metadata[0][1])
|
|
||||||
_returned_data.append(metadata)
|
|
||||||
return _returned_data
|
|
||||||
|
|
||||||
|
|
||||||
@register_query(TarantoolDBConnection)
|
|
||||||
def get_metadata_by_tx_id(connection, transaction_id: str) -> MetaData:
|
|
||||||
metadata = connection.run(connection.space(TARANT_TABLE_META_DATA).select(transaction_id, index=TARANT_ID_SEARCH))
|
|
||||||
return MetaData.from_tuple(metadata[0]) if len(metadata) > 0 else MetaData(transaction_id)
|
|
||||||
|
|
||||||
|
|
||||||
@register_query(TarantoolDBConnection)
|
|
||||||
def store_asset(connection, asset: Asset):
|
|
||||||
tuple_asset = (json.dumps(asset.data), asset.tx_id, asset.id)
|
|
||||||
try:
|
|
||||||
return connection.run(connection.space(TARANT_TABLE_ASSETS).insert(tuple_asset), only_data=False)
|
|
||||||
except DatabaseError:
|
|
||||||
pass
|
|
||||||
|
|
||||||
|
|
||||||
@register_query(TarantoolDBConnection)
|
|
||||||
def store_assets(connection, assets: list):
|
|
||||||
for asset in assets:
|
|
||||||
store_asset(connection, asset)
|
|
||||||
|
|
||||||
|
|
||||||
@register_query(TarantoolDBConnection)
|
@register_query(TarantoolDBConnection)
|
||||||
def get_asset(connection, asset_id: str) -> Asset:
|
def get_asset(connection, asset_id: str) -> Asset:
|
||||||
_data = connection.run(connection.space(TARANT_TABLE_ASSETS).select(asset_id, index=TARANT_TX_ID_SEARCH))
|
_data = connection.run(connection.space(TARANT_TABLE_TRANSACTION).select(asset_id, index=TARANT_INDEX_TX_BY_ASSET_ID))
|
||||||
return Asset.from_tuple(_data[0])
|
return Asset.from_dict(_data[0])
|
||||||
|
|
||||||
|
|
||||||
@register_query(TarantoolDBConnection)
|
@register_query(TarantoolDBConnection)
|
||||||
def get_assets(connection, assets_ids: list) -> list[Asset]:
|
def get_assets(connection, assets_ids: list) -> list[Asset]:
|
||||||
_returned_data = []
|
_returned_data = []
|
||||||
for _id in list(set(assets_ids)):
|
for _id in list(set(assets_ids)):
|
||||||
res = connection.run(connection.space(TARANT_TABLE_ASSETS).select(_id, index=TARANT_TX_ID_SEARCH))
|
res = connection.run(connection.space(TARANT_TABLE_TRANSACTION).select(_id, index=TARANT_INDEX_TX_BY_ASSET_ID))
|
||||||
if len(res) is 0:
|
if len(res) is 0:
|
||||||
continue
|
continue
|
||||||
_returned_data.append(res[0])
|
_returned_data.append(res[0])
|
||||||
|
|
||||||
sorted_assets = sorted(_returned_data, key=lambda k: k[1], reverse=False)
|
sorted_assets = sorted(_returned_data, key=lambda k: k[1], reverse=False)
|
||||||
return [Asset.from_tuple(asset) for asset in sorted_assets]
|
return [Asset.from_dict(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)
|
@register_query(TarantoolDBConnection)
|
||||||
def get_spent(connection, fullfil_transaction_id: str, fullfil_output_index: str):
|
def get_spent(connection, fullfil_transaction_id: str, fullfil_output_index: str):
|
||||||
_inputs = connection.run(
|
_inputs = connection.run(
|
||||||
connection.space(TARANT_TABLE_INPUT).select(
|
connection.space(TARANT_TABLE_TRANSACTION).select(
|
||||||
[fullfil_transaction_id, str(fullfil_output_index)], index="spent_search"
|
[fullfil_transaction_id, fullfil_output_index], index=TARANT_INDEX_SPENDING_BY_ID_AND_OUTPUT_INDEX
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
return _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)
|
||||||
@ -301,7 +161,7 @@ def store_block(connection, block: dict):
|
|||||||
|
|
||||||
@register_query(TarantoolDBConnection)
|
@register_query(TarantoolDBConnection)
|
||||||
def get_txids_filtered(
|
def get_txids_filtered(
|
||||||
connection, asset_ids: list[str], operation: str = None, last_tx: any = None
|
connection, asset_ids: list[str], operation: str = None, last_tx: any = None
|
||||||
): # TODO here is used 'OR' operator
|
): # TODO here is used 'OR' operator
|
||||||
actions = {
|
actions = {
|
||||||
"CREATE": {"sets": ["CREATE", asset_ids], "index": "transaction_search"},
|
"CREATE": {"sets": ["CREATE", asset_ids], "index": "transaction_search"},
|
||||||
@ -555,7 +415,7 @@ def get_election(connection, election_id: str):
|
|||||||
|
|
||||||
@register_query(TarantoolDBConnection)
|
@register_query(TarantoolDBConnection)
|
||||||
def get_asset_tokens_for_public_key(
|
def get_asset_tokens_for_public_key(
|
||||||
connection, asset_id: str, public_key: str
|
connection, asset_id: str, public_key: str
|
||||||
): # FIXME Something can be wrong with this function ! (public_key) is not used # noqa: E501
|
): # FIXME Something can be wrong with this function ! (public_key) is not used # noqa: E501
|
||||||
# space = connection.space("keys")
|
# space = connection.space("keys")
|
||||||
# _keys = space.select([public_key], index="keys_search")
|
# _keys = space.select([public_key], index="keys_search")
|
||||||
@ -589,9 +449,3 @@ def get_latest_abci_chain(connection):
|
|||||||
return None
|
return None
|
||||||
_chain = sorted(_all_chains, key=itemgetter(1), reverse=True)[0]
|
_chain = sorted(_all_chains, key=itemgetter(1), reverse=True)[0]
|
||||||
return {"chain_id": _chain[0], "height": _chain[1], "is_synced": _chain[2]}
|
return {"chain_id": _chain[0], "height": _chain[1], "is_synced": _chain[2]}
|
||||||
|
|
||||||
|
|
||||||
@register_query(TarantoolDBConnection)
|
|
||||||
def get_script_by_tx_id(connection, tx_id: str) -> Script:
|
|
||||||
script = connection.run(connection.space(TARANT_TABLE_SCRIPT).select(tx_id, index=TARANT_TX_ID_SEARCH))
|
|
||||||
return Script.from_tuple(script[0]) if len(script) < 0 else Script(tx_id)
|
|
||||||
|
|||||||
@ -239,6 +239,9 @@ class Planetmint(object):
|
|||||||
for txid in txids:
|
for txid in txids:
|
||||||
yield self.get_transaction(txid)
|
yield self.get_transaction(txid)
|
||||||
|
|
||||||
|
def get_outputs_by_tx_id(self, txid):
|
||||||
|
return backend.query.get_outputs_by_tx_id(self.connection, txid)
|
||||||
|
|
||||||
def get_outputs_filtered(self, owner, spent=None):
|
def get_outputs_filtered(self, owner, spent=None):
|
||||||
"""Get a list of output links filtered on some criteria
|
"""Get a list of output links filtered on some criteria
|
||||||
|
|
||||||
@ -337,17 +340,15 @@ class Planetmint(object):
|
|||||||
|
|
||||||
return blocks
|
return blocks
|
||||||
|
|
||||||
def validate_transaction(self, tx, current_transactions=[]):
|
def validate_transaction(self, transaction, current_transactions=[]):
|
||||||
"""Validate a transaction against the current status of the database."""
|
"""Validate a transaction against the current status of the database."""
|
||||||
|
|
||||||
transaction = tx
|
|
||||||
|
|
||||||
# CLEANUP: The conditional below checks for transaction in dict format.
|
# CLEANUP: The conditional below checks for transaction in dict format.
|
||||||
# It would be better to only have a single format for the transaction
|
# It would be better to only have a single format for the transaction
|
||||||
# throught the code base.
|
# throught the code base.
|
||||||
if isinstance(transaction, dict):
|
if isinstance(transaction, dict):
|
||||||
try:
|
try:
|
||||||
transaction = Transaction.from_dict(tx, False)
|
transaction = Transaction.from_dict(transaction, False)
|
||||||
except SchemaValidationError as e:
|
except SchemaValidationError as e:
|
||||||
logger.warning("Invalid transaction schema: %s", e.__cause__.message)
|
logger.warning("Invalid transaction schema: %s", e.__cause__.message)
|
||||||
return False
|
return False
|
||||||
@ -371,6 +372,7 @@ class Planetmint(object):
|
|||||||
for input_ in tx.inputs:
|
for input_ in tx.inputs:
|
||||||
input_txid = input_.fulfills.txid
|
input_txid = input_.fulfills.txid
|
||||||
input_tx = self.get_transaction(input_txid)
|
input_tx = self.get_transaction(input_txid)
|
||||||
|
_output = self.get_outputs_by_tx_id(input_txid)
|
||||||
if input_tx is None:
|
if input_tx is None:
|
||||||
for ctxn in current_transactions:
|
for ctxn in current_transactions:
|
||||||
if ctxn.id == input_txid:
|
if ctxn.id == input_txid:
|
||||||
@ -383,9 +385,13 @@ class Planetmint(object):
|
|||||||
if spent:
|
if spent:
|
||||||
raise DoubleSpend("input `{}` was already spent".format(input_txid))
|
raise DoubleSpend("input `{}` was already spent".format(input_txid))
|
||||||
|
|
||||||
output = input_tx.outputs[input_.fulfills.output]
|
|
||||||
|
output = _output[input_.fulfills.output]
|
||||||
input_conditions.append(output)
|
input_conditions.append(output)
|
||||||
input_txs.append(input_tx)
|
tx_dict = input_tx.to_dict()
|
||||||
|
tx_dict["outputs"] = output.to_dict()
|
||||||
|
pm_transaction = Transaction.from_dict(tx_dict, False)
|
||||||
|
input_txs.append(pm_transaction)
|
||||||
|
|
||||||
# Validate that all inputs are distinct
|
# Validate that all inputs are distinct
|
||||||
links = [i.fulfills.to_uri() for i in tx.inputs]
|
links = [i.fulfills.to_uri() for i in tx.inputs]
|
||||||
|
|||||||
@ -208,63 +208,6 @@ def test_get_owned_ids(signed_create_tx, user_pk, db_conn):
|
|||||||
assert founded[0]["transactions"].raw_transaction == tx_dict
|
assert founded[0]["transactions"].raw_transaction == tx_dict
|
||||||
|
|
||||||
|
|
||||||
def test_get_spending_transactions(user_pk, user_sk, db_conn):
|
|
||||||
from planetmint.backend.tarantool import query
|
|
||||||
|
|
||||||
out = [([user_pk], 1)]
|
|
||||||
tx1 = Create.generate([user_pk], out * 3)
|
|
||||||
tx1.sign([user_sk])
|
|
||||||
inputs = tx1.to_inputs()
|
|
||||||
tx2 = Transfer.generate([inputs[0]], out, [tx1.id]).sign([user_sk])
|
|
||||||
tx3 = Transfer.generate([inputs[1]], out, [tx1.id]).sign([user_sk])
|
|
||||||
tx4 = Transfer.generate([inputs[2]], out, [tx1.id]).sign([user_sk])
|
|
||||||
txns = [deepcopy(tx.to_dict()) for tx in [tx1, tx2, tx3, tx4]]
|
|
||||||
query.store_transactions(signed_transactions=txns, connection=db_conn)
|
|
||||||
|
|
||||||
links = [inputs[0].fulfills.to_dict(), inputs[2].fulfills.to_dict()]
|
|
||||||
txns = list(query.get_spending_transactions(connection=db_conn, inputs=links))
|
|
||||||
|
|
||||||
# tx3 not a member because input 1 not asked for
|
|
||||||
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):
|
|
||||||
from transactions.common.crypto import generate_key_pair
|
|
||||||
from planetmint.backend.tarantool import query
|
|
||||||
|
|
||||||
(alice_sk, alice_pk) = generate_key_pair()
|
|
||||||
(bob_sk, bob_pk) = generate_key_pair()
|
|
||||||
(carol_sk, carol_pk) = generate_key_pair()
|
|
||||||
|
|
||||||
out = [([alice_pk], 9)]
|
|
||||||
tx1 = Create.generate([alice_pk], out).sign([alice_sk])
|
|
||||||
|
|
||||||
inputs1 = tx1.to_inputs()
|
|
||||||
tx2 = Transfer.generate([inputs1[0]], [([alice_pk], 6), ([bob_pk], 3)], [tx1.id]).sign([alice_sk])
|
|
||||||
|
|
||||||
inputs2 = tx2.to_inputs()
|
|
||||||
tx3 = Transfer.generate([inputs2[0]], [([bob_pk], 3), ([carol_pk], 3)], [tx1.id]).sign([alice_sk])
|
|
||||||
|
|
||||||
inputs3 = tx3.to_inputs()
|
|
||||||
tx4 = Transfer.generate([inputs2[1], inputs3[0]], [([carol_pk], 6)], [tx1.id]).sign([bob_sk])
|
|
||||||
|
|
||||||
txns = [deepcopy(tx.to_dict()) for tx in [tx1, tx2, tx3, tx4]]
|
|
||||||
query.store_transactions(signed_transactions=txns, connection=db_conn)
|
|
||||||
|
|
||||||
links = [
|
|
||||||
({"transaction_id": tx2.id, "output_index": 0}, 1, [tx3.id]),
|
|
||||||
({"transaction_id": tx2.id, "output_index": 1}, 1, [tx4.id]),
|
|
||||||
({"transaction_id": tx3.id, "output_index": 0}, 1, [tx4.id]),
|
|
||||||
({"transaction_id": tx3.id, "output_index": 1}, 0, None),
|
|
||||||
]
|
|
||||||
for li, num, match in links:
|
|
||||||
txns = list(query.get_spending_transactions(connection=db_conn, inputs=[li]))
|
|
||||||
assert len(txns) == num
|
|
||||||
if len(txns):
|
|
||||||
assert [tx["transactions"].id for tx in txns] == match
|
|
||||||
|
|
||||||
|
|
||||||
def test_store_block(db_conn):
|
def test_store_block(db_conn):
|
||||||
from planetmint.lib import Block
|
from planetmint.lib import Block
|
||||||
from planetmint.backend.tarantool import query
|
from planetmint.backend.tarantool import query
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user