Merge branch 'refactor-backend' into simplified_unit_tests

This commit is contained in:
Jürgen Eckel 2023-01-16 10:27:35 +01:00
commit 08b2924679
No known key found for this signature in database
43 changed files with 297 additions and 565 deletions

View File

@ -1,35 +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
name: Documentation
on: [push, pull_request]
jobs:
documentation:
runs-on: ubuntu-latest
steps:
- name: Check out repository code
uses: actions/checkout@v3
- name: Setup python
uses: actions/setup-python@v4
with:
python-version: 3.9
- name: Install tox
run: python -m pip install --upgrade tox tox-gh-actions
- name: Install dependencies
run: pip install .'[dev]'
- name: Run tox
run: tox -e docsroot

1
.gitignore vendored
View File

@ -53,7 +53,6 @@ pip-delete-this-directory.txt
# Unit test / coverage reports
htmlcov/
.tox/
.coverage
.coverage.*
.cache

View File

@ -25,6 +25,16 @@ For reference, the possible headings are:
* **Known Issues**
* **Notes**
## [2.0.0] - 2023-12-01
* **Changed** changed tarantool db schema
* **Removed** removed text_search routes
* **Added** metadata / asset cid route for fetching transactions
## [1.4.1] - 2022-21-12
* **fixed** inconsistent cryptocondition keyring tag handling. Using cryptoconditions > 1.1.0 from now on.
## [1.4.0] - 2022-12-12
* **Added** added upgrade compatibility to older nodes to support v2.0 TX validity for nodes supporting v3.0 transactions (planetmint-transactions >= 0.4.1)
## [1.3.2] - 2022-28-11
* **Changed** new zenroom 2.3.1 support

View File

@ -41,7 +41,6 @@ services:
- ./setup.py:/usr/src/app/setup.py
- ./setup.cfg:/usr/src/app/setup.cfg
- ./pytest.ini:/usr/src/app/pytest.ini
- ./tox.ini:/usr/src/app/tox.ini
environment:
PLANETMINT_DATABASE_BACKEND: tarantool_db
PLANETMINT_DATABASE_HOST: tarantool

View File

@ -1,7 +1,7 @@
aafigure==0.6
alabaster==0.7.12
Babel==2.10.1
certifi==2021.10.8
certifi==2022.12.7
charset-normalizer==2.0.12
commonmark==0.9.1
docutils==0.17.1

View File

@ -54,13 +54,13 @@ import sphinx_rtd_theme
extensions = [
"myst_parser",
"sphinx.ext.napoleon",
"sphinx.ext.autosectionlabel",
"sphinx.ext.autodoc",
"sphinx.ext.intersphinx",
"sphinx.ext.coverage",
"sphinx.ext.viewcode",
"sphinx.ext.todo",
"sphinx.ext.napoleon",
"sphinxcontrib.httpdomain",
"aafigure.sphinxext",
#'sphinx_toolbox.collapse',

View File

@ -4,7 +4,7 @@ Content-Type: application/json
{
"assets": "/assets/",
"blocks": "/blocks/",
"docs": "https://docs.planetmint.io/projects/server/en/v1.3.1/http-client-server-api.html",
"docs": "https://docs.planetmint.io/projects/server/en/v1.4.1/http-client-server-api.html",
"metadata": "/metadata/",
"outputs": "/outputs/",
"streamedblocks": "ws://localhost:9985/api/v1/streams/valid_blocks",

View File

@ -7,15 +7,13 @@ Content-Type: application/json
{
"assets": [
{
"data": {
"msg": "Hello Planetmint!"
}
"data": "QmQP5C3PmhH9oB84n7YqSY4WVqmYatdoo1BdwhH4zmcwqM"
}
],
"id": "61e1312b80705e0dabb948c9d78dae7f62d64832abda822b13d89c4a7305d4ac",
"id": "0fdeb547670bbea980389df53cf5a91e60159339084c6b0b5cc0b5494a679530",
"inputs": [
{
"fulfillment": "pGSAIDE5i63cn4X8T8N1sZ2mGkJD5lNRnBM4PZgI_zvzbr-cgUCWcUaLa2U-nkmZ6oYj14aeV6B4TJH2NvZ8k2ZTwcGiaiCGXDQT2dEPfMCFwM8lwSousafCu4c7EgVZ1GzUDjsN",
"fulfillment": "pGSAIDE5i63cn4X8T8N1sZ2mGkJD5lNRnBM4PZgI_zvzbr-cgUDklzRb5aUQz9slbaqSWap1AfC-cacTCN3CGtFy2LPK7JKEqKG2b0KQXnUcFksk_KH_v6ImFXHsclKSp1OJkIEI",
"fulfills": null,
"owners_before": [
"4K9sWUMFwTgaDGPfdynrbxWqWS6sWmKbZoTjxLtVUibD"
@ -39,7 +37,7 @@ Content-Type: application/json
]
}
],
"version": "2.0"
"version": "3.0"
}
]
}

View File

@ -1,3 +1,3 @@
GET /api/v1/blocks?transaction_id=61e1312b80705e0dabb948c9d78dae7f62d64832abda822b13d89c4a7305d4ac HTTP/1.1
GET /api/v1/blocks?transaction_id=0fdeb547670bbea980389df53cf5a91e60159339084c6b0b5cc0b5494a679530 HTTP/1.1
Host: example.com

View File

@ -1,3 +1,3 @@
GET /api/v1/transactions?operation=TRANSFER&asset_id=61e1312b80705e0dabb948c9d78dae7f62d64832abda822b13d89c4a7305d4ac HTTP/1.1
GET /api/v1/transactions?operation=TRANSFER&asset_id=0fdeb547670bbea980389df53cf5a91e60159339084c6b0b5cc0b5494a679530 HTTP/1.1
Host: example.com

View File

@ -4,16 +4,16 @@ Content-Type: application/json
[{
"assets": [
{
"id": "61e1312b80705e0dabb948c9d78dae7f62d64832abda822b13d89c4a7305d4ac"
"id": "0fdeb547670bbea980389df53cf5a91e60159339084c6b0b5cc0b5494a679530"
}
],
"id": "b6e1ab3d48bbbbb0e40b952e70ec5d439b2745e0ba0c44b4ee877657e9ac33f0",
"id": "8d11fe2bd91c4747a41e0c3dbe1400c511175be42f008d6cff92cbfa9e04f799",
"inputs": [
{
"fulfillment": "pGSAIDE5i63cn4X8T8N1sZ2mGkJD5lNRnBM4PZgI_zvzbr-cgUA4BB4fxDXK3CQTbKpH5gTAN76NG-iopNuuDEfBbZ1Fl-ipNU46t8VCvK9ghm9Q53aFRW6DDiW5wcWXxY0sS4EJ",
"fulfillment": "pGSAIDE5i63cn4X8T8N1sZ2mGkJD5lNRnBM4PZgI_zvzbr-cgUCh-rpO-xqDm2fngjzxnKc39G16FpFMo0y50sHT7_uo1Itzvh4jsxnSGco2HjG6ZF-lSiGsASZ4uIIHuPM57yUI",
"fulfills": {
"output_index": 0,
"transaction_id": "61e1312b80705e0dabb948c9d78dae7f62d64832abda822b13d89c4a7305d4ac"
"transaction_id": "0fdeb547670bbea980389df53cf5a91e60159339084c6b0b5cc0b5494a679530"
},
"owners_before": [
"4K9sWUMFwTgaDGPfdynrbxWqWS6sWmKbZoTjxLtVUibD"
@ -37,21 +37,21 @@ Content-Type: application/json
]
}
],
"version": "2.0"
"version": "3.0"
},
{
"assets": [
{
"id": "61e1312b80705e0dabb948c9d78dae7f62d64832abda822b13d89c4a7305d4ac"
"id": "0fdeb547670bbea980389df53cf5a91e60159339084c6b0b5cc0b5494a679530"
}
],
"id": "e43d3f93d90d22ef11c21607e3415bfcda4e0c7dd60412fbb55daf32978a3126",
"id": "45c929b66d1b10db6c3c3e6b1adddc0778b473fced4a1f403c2646b25f3fd983",
"inputs": [
{
"fulfillment": "pGSAICw7Ul-c2lG6NFbHp3FbKRC7fivQcNGO7GS4wV3A-1QggUBjj_XTjB3yJdG8JMNKnkkHvcX_BTOkl-YacRD4yKqxUCeL-VTgbrLgi5a3gGxNJcTkZP1gF0nsby8cgV4xmOcB",
"fulfillment": "pGSAICw7Ul-c2lG6NFbHp3FbKRC7fivQcNGO7GS4wV3A-1QggUAc6OAQcXppDxCazw0UK2nwghctKNiZYDDsSOkAn0eQE8QjZ7GLzJpVb92oGXw_4FF7cLE0gg3nNxu7taQ8xakE",
"fulfills": {
"output_index": 0,
"transaction_id": "b6e1ab3d48bbbbb0e40b952e70ec5d439b2745e0ba0c44b4ee877657e9ac33f0"
"transaction_id": "8d11fe2bd91c4747a41e0c3dbe1400c511175be42f008d6cff92cbfa9e04f799"
},
"owners_before": [
"3yfQPHeWAa1MxTX9Zf9176QqcpcnWcanVZZbaHb8B3h9"
@ -75,5 +75,5 @@ Content-Type: application/json
]
}
],
"version": "2.0"
"version": "3.0"
}]

View File

@ -1,3 +1,3 @@
GET /api/v1/transactions/61e1312b80705e0dabb948c9d78dae7f62d64832abda822b13d89c4a7305d4ac HTTP/1.1
GET /api/v1/transactions/0fdeb547670bbea980389df53cf5a91e60159339084c6b0b5cc0b5494a679530 HTTP/1.1
Host: example.com

View File

@ -4,15 +4,13 @@ Content-Type: application/json
{
"assets": [
{
"data": {
"msg": "Hello Planetmint!"
}
"data": "QmQP5C3PmhH9oB84n7YqSY4WVqmYatdoo1BdwhH4zmcwqM"
}
],
"id": "61e1312b80705e0dabb948c9d78dae7f62d64832abda822b13d89c4a7305d4ac",
"id": "0fdeb547670bbea980389df53cf5a91e60159339084c6b0b5cc0b5494a679530",
"inputs": [
{
"fulfillment": "pGSAIDE5i63cn4X8T8N1sZ2mGkJD5lNRnBM4PZgI_zvzbr-cgUCWcUaLa2U-nkmZ6oYj14aeV6B4TJH2NvZ8k2ZTwcGiaiCGXDQT2dEPfMCFwM8lwSousafCu4c7EgVZ1GzUDjsN",
"fulfillment": "pGSAIDE5i63cn4X8T8N1sZ2mGkJD5lNRnBM4PZgI_zvzbr-cgUDklzRb5aUQz9slbaqSWap1AfC-cacTCN3CGtFy2LPK7JKEqKG2b0KQXnUcFksk_KH_v6ImFXHsclKSp1OJkIEI",
"fulfills": null,
"owners_before": [
"4K9sWUMFwTgaDGPfdynrbxWqWS6sWmKbZoTjxLtVUibD"
@ -36,5 +34,5 @@ Content-Type: application/json
]
}
],
"version": "2.0"
"version": "3.0"
}

View File

@ -6,7 +6,7 @@ Content-Type: application/json
"v1": {
"assets": "/api/v1/assets/",
"blocks": "/api/v1/blocks/",
"docs": "https://docs.planetmint.io/projects/server/en/v1.2.2/http-client-server-api.html",
"docs": "https://docs.planetmint.io/projects/server/en/v1.4.1/http-client-server-api.html",
"metadata": "/api/v1/metadata/",
"outputs": "/api/v1/outputs/",
"streamedblocks": "ws://localhost:9985/api/v1/streams/valid_blocks",
@ -15,7 +15,7 @@ Content-Type: application/json
"validators": "/api/v1/validators"
}
},
"docs": "https://docs.planetmint.io/projects/server/en/v1.2.2/",
"docs": "https://docs.planetmint.io/projects/server/en/v1.4.1/",
"software": "Planetmint",
"version": "1.3.1"
"version": "1.4.1"
}

View File

@ -5,15 +5,13 @@ Content-Type: application/json
{
"assets": [
{
"data": {
"msg": "Hello Planetmint!"
}
"data": "QmQP5C3PmhH9oB84n7YqSY4WVqmYatdoo1BdwhH4zmcwqM"
}
],
"id": "61e1312b80705e0dabb948c9d78dae7f62d64832abda822b13d89c4a7305d4ac",
"id": "0fdeb547670bbea980389df53cf5a91e60159339084c6b0b5cc0b5494a679530",
"inputs": [
{
"fulfillment": "pGSAIDE5i63cn4X8T8N1sZ2mGkJD5lNRnBM4PZgI_zvzbr-cgUCWcUaLa2U-nkmZ6oYj14aeV6B4TJH2NvZ8k2ZTwcGiaiCGXDQT2dEPfMCFwM8lwSousafCu4c7EgVZ1GzUDjsN",
"fulfillment": "pGSAIDE5i63cn4X8T8N1sZ2mGkJD5lNRnBM4PZgI_zvzbr-cgUDklzRb5aUQz9slbaqSWap1AfC-cacTCN3CGtFy2LPK7JKEqKG2b0KQXnUcFksk_KH_v6ImFXHsclKSp1OJkIEI",
"fulfills": null,
"owners_before": [
"4K9sWUMFwTgaDGPfdynrbxWqWS6sWmKbZoTjxLtVUibD"
@ -37,5 +35,5 @@ Content-Type: application/json
]
}
],
"version": "2.0"
"version": "3.0"
}

View File

@ -4,15 +4,13 @@ Content-Type: application/json
{
"assets": [
{
"data": {
"msg": "Hello Planetmint!"
}
"data": "QmQP5C3PmhH9oB84n7YqSY4WVqmYatdoo1BdwhH4zmcwqM"
}
],
"id": "61e1312b80705e0dabb948c9d78dae7f62d64832abda822b13d89c4a7305d4ac",
"id": "0fdeb547670bbea980389df53cf5a91e60159339084c6b0b5cc0b5494a679530",
"inputs": [
{
"fulfillment": "pGSAIDE5i63cn4X8T8N1sZ2mGkJD5lNRnBM4PZgI_zvzbr-cgUCWcUaLa2U-nkmZ6oYj14aeV6B4TJH2NvZ8k2ZTwcGiaiCGXDQT2dEPfMCFwM8lwSousafCu4c7EgVZ1GzUDjsN",
"fulfillment": "pGSAIDE5i63cn4X8T8N1sZ2mGkJD5lNRnBM4PZgI_zvzbr-cgUDklzRb5aUQz9slbaqSWap1AfC-cacTCN3CGtFy2LPK7JKEqKG2b0KQXnUcFksk_KH_v6ImFXHsclKSp1OJkIEI",
"fulfills": null,
"owners_before": [
"4K9sWUMFwTgaDGPfdynrbxWqWS6sWmKbZoTjxLtVUibD"
@ -36,5 +34,5 @@ Content-Type: application/json
]
}
],
"version": "2.0"
"version": "3.0"
}

View File

@ -3,14 +3,12 @@
# SPDX-License-Identifier: (Apache-2.0 AND CC-BY-4.0)
# Code is Apache-2.0 and docs are CC-BY-4.0
import tarantool
import logging
from itertools import repeat
from importlib import import_module
from transactions.common.exceptions import ConfigurationError
from planetmint.config import Config
from planetmint.backend.exceptions import ConnectionError
BACKENDS = {
"tarantool_db": "planetmint.backend.tarantool.connection.TarantoolDBConnection",
@ -69,6 +67,7 @@ class DBConnection(metaclass=DBSingleton):
**kwargs
):
"""Create a new :class:`~.Connection` instance.
Args:
host (str): the host to connect to.
port (int): the port to connect to.

View File

@ -39,7 +39,9 @@ class DbTransaction:
operation=transaction[1],
version=transaction[2],
metadata=MetaData.from_dict(transaction[3]),
assets=Asset.from_list_dict(transaction[4]),
assets=Asset.from_list_dict(transaction[4])
if transaction[2] != "2.0"
else Asset.from_dict(transaction[4][0]),
inputs=Input.from_list_dict(transaction[5]),
script=Script.from_dict(transaction[6]),
)
@ -66,7 +68,7 @@ class DbTransaction:
"outputs": Output.list_to_dict(self.outputs),
"operation": self.operation,
"metadata": self.metadata.to_dict() if self.metadata is not None else None,
"assets": Asset.list_to_dict(self.assets),
"assets": Asset.list_to_dict(self.assets) if self.version != "2.0" else Asset.to_dict(self.assets),
"version": self.version,
"id": self.id,
"script": self.script.to_dict() if self.script is not None else None,

View File

@ -31,12 +31,12 @@ def store_asset(connection, asset: dict) -> Asset:
@singledispatch
def store_assets(connection, assets: list) -> list[Asset]:
"""Write a list of assets to the assets table.
backend
Args:
assets (list): a list of assets to write.
Returns:
The database response.
Args:
assets (list): a list of assets to write.
Returns:
The database response.
"""
raise NotImplementedError
@ -70,27 +70,6 @@ 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):
"""Get the transaction by transaction id."""
@ -243,6 +222,7 @@ def store_transaction_outputs(connection, output: Output, index: int):
@singledispatch
def get_assets(connection, asset_ids) -> list[Asset]:
"""Get a list of assets from the assets table.
Args:
asset_ids (list): a list of ids for the assets to be retrieved from
the database.

View File

@ -9,7 +9,6 @@ import logging
from functools import singledispatch
from planetmint.config import Config
from planetmint.backend.connection import Connection
from transactions.common.exceptions import ValidationError
from transactions.common.utils import (
validate_all_values_for_key_in_obj,

View File

@ -1,78 +0,0 @@
box.cfg{listen = 3303}
function indexed_pattern_search(space_name, field_no, pattern)
if (box.space[space_name] == nil) then
print("Error: Failed to find the specified space")
return nil
end
local index_no = -1
for i=0,box.schema.INDEX_MAX,1 do
if (box.space[space_name].index[i] == nil) then break end
if (box.space[space_name].index[i].type == "TREE"
and box.space[space_name].index[i].parts[1].fieldno == field_no
and (box.space[space_name].index[i].parts[1].type == "scalar"
or box.space[space_name].index[i].parts[1].type == "string")) then
index_no = i
break
end
end
if (index_no == -1) then
print("Error: Failed to find an appropriate index")
return nil
end
local index_search_key = ""
local index_search_key_length = 0
local last_character = ""
local c = ""
local c2 = ""
for i=1,string.len(pattern),1 do
c = string.sub(pattern, i, i)
if (last_character ~= "%") then
if (c == '^' or c == "$" or c == "(" or c == ")" or c == "."
or c == "[" or c == "]" or c == "*" or c == "+"
or c == "-" or c == "?") then
break
end
if (c == "%") then
c2 = string.sub(pattern, i + 1, i + 1)
if (string.match(c2, "%p") == nil) then break end
index_search_key = index_search_key .. c2
else
index_search_key = index_search_key .. c
end
end
last_character = c
end
index_search_key_length = string.len(index_search_key)
local result_set = {}
local number_of_tuples_in_result_set = 0
local previous_tuple_field = ""
while true do
local number_of_tuples_since_last_yield = 0
local is_time_for_a_yield = false
for _,tuple in box.space[space_name].index[index_no]:
pairs(index_search_key,{iterator = box.index.GE}) do
if (string.sub(tuple[field_no], 1, index_search_key_length)
> index_search_key) then
break
end
number_of_tuples_since_last_yield = number_of_tuples_since_last_yield + 1
if (number_of_tuples_since_last_yield >= 10
and tuple[field_no] ~= previous_tuple_field) then
index_search_key = tuple[field_no]
is_time_for_a_yield = true
break
end
previous_tuple_field = tuple[field_no]
if (string.match(tuple[field_no], pattern) ~= nil) then
number_of_tuples_in_result_set = number_of_tuples_in_result_set + 1
result_set[number_of_tuples_in_result_set] = tuple
end
end
if (is_time_for_a_yield ~= true) then
break
end
require('fiber').yield()
end
return result_set
end

View File

@ -9,7 +9,8 @@ import tarantool
from planetmint.config import Config
from transactions.common.exceptions import ConfigurationError
from planetmint.utils import Lazy
from planetmint.backend.connection import DBConnection, ConnectionError
from planetmint.backend.connection import DBConnection
from planetmint.backend.exceptions import ConnectionError
logger = logging.getLogger(__name__)

View File

@ -11,6 +11,13 @@ TARANT_TABLE_GOVERNANCE = "governance"
TARANT_TABLE_INPUT = "inputs"
TARANT_TABLE_OUTPUT = "outputs"
TARANT_TABLE_SCRIPT = "scripts"
TARANT_TABLE_BLOCKS = "blocks"
TARANT_TABLE_VALIDATOR_SETS = "validator_sets"
TARANT_TABLE_ABCI_CHAINS = "abci_chains"
TARANT_TABLE_UTXOS = "utxos"
TARANT_TABLE_PRE_COMMITS = "pre_commits"
TARANT_TABLE_ELECTIONS = "elections"
TARANT_TX_ID_SEARCH = "transaction_id"
TARANT_ID_SEARCH = "id"

View File

@ -1,8 +0,0 @@
box.space.abci_chains:drop()
box.space.blocks:drop()
box.space.elections:drop()
box.space.pre_commits:drop()
box.space.utxos:drop()
box.space.validators:drop()
box.space.transactions:drop()
box.space.outputs:drop()

View File

@ -7,8 +7,8 @@
import json
import logging
from uuid import uuid4
from hashlib import sha256
from operator import itemgetter
from typing import Union
from planetmint.backend import query
@ -18,9 +18,7 @@ from planetmint.exceptions import CriticalDoubleSpend
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,
@ -28,10 +26,17 @@ from planetmint.backend.tarantool.const import (
TARANT_INDEX_TX_BY_ASSET_ID,
TARANT_INDEX_SPENDING_BY_ID_AND_OUTPUT_INDEX,
TARANT_TABLE_GOVERNANCE,
TARANT_TABLE_ABCI_CHAINS,
TARANT_TABLE_BLOCKS,
TARANT_TABLE_VALIDATOR_SETS,
TARANT_TABLE_UTXOS,
TARANT_TABLE_PRE_COMMITS,
TARANT_TABLE_ELECTIONS,
)
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, Output
from planetmint.backend.tarantool.connection import TarantoolDBConnection
from transactions.common.transaction import Transaction
logger = logging.getLogger(__name__)
@ -39,7 +44,7 @@ register_query = module_dispatch_registrar(query)
@register_query(TarantoolDBConnection)
def get_complete_transactions_by_ids(connection, txids: list, table=TARANT_TABLE_TRANSACTION) -> list[DbTransaction]:
def get_complete_transactions_by_ids(connection, txids: list) -> list[DbTransaction]:
_transactions = []
for txid in txids:
tx = get_transaction_by_id(connection, txid, TARANT_TABLE_TRANSACTION)
@ -61,7 +66,7 @@ def get_outputs_by_tx_id(connection, tx_id: str) -> list[Output]:
@register_query(TarantoolDBConnection)
def get_transaction(connection, tx_id: str) -> DbTransaction:
def get_transaction(connection, tx_id: str) -> Union[DbTransaction, None]:
transactions = get_complete_transactions_by_ids(connection, (tx_id))
if len(transactions) > 1 or len(transactions) == 0:
return None
@ -109,9 +114,9 @@ def store_transaction_outputs(connection, output: Output, index: int) -> str:
@register_query(TarantoolDBConnection)
def store_transactions(connection, signed_transactions: list):
def store_transactions(connection, signed_transactions: list, table=TARANT_TABLE_TRANSACTION):
for transaction in signed_transactions:
store_transaction(connection, transaction)
store_transaction(connection, transaction, table)
[
store_transaction_outputs(connection, Output.outputs_dict(output, transaction["id"]), index)
for index, output in enumerate(transaction[TARANT_TABLE_OUTPUT])
@ -119,81 +124,45 @@ def store_transactions(connection, signed_transactions: list):
@register_query(TarantoolDBConnection)
def store_transaction(connection, transaction):
def store_transaction(connection, transaction, table=TARANT_TABLE_TRANSACTION):
scripts = None
if TARANT_TABLE_SCRIPT in transaction:
scripts = transaction[TARANT_TABLE_SCRIPT]
asset_obj = Transaction.get_assets_tag(transaction["version"])
if transaction["version"] == "2.0":
asset_array = [transaction[asset_obj]]
else:
asset_array = transaction[asset_obj]
tx = (
transaction["id"],
transaction["operation"],
transaction["version"],
transaction["metadata"],
transaction["assets"],
asset_array,
transaction["inputs"],
scripts,
)
try:
connection.run(connection.space(TARANT_TABLE_TRANSACTION).insert(tx), only_data=False)
connection.run(connection.space(table).insert(tx), only_data=False)
except Exception as e:
logger.info(f"Could not insert transactions: {e}")
if e.args[0] == 3 and e.args[1].startswith('Duplicate key exists in'):
if e.args[0] == 3 and e.args[1].startswith("Duplicate key exists in"):
raise CriticalDoubleSpend()
else:
raise OperationDataInsertionError()
@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 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,
)
try:
connection.run(connection.space(TARANT_TABLE_GOVERNANCE).insert(tx), only_data=False)
except Exception as e:
if e.args[0] == 3 and e.args[1].startswith('Duplicate key exists in'):
raise CriticalDoubleSpend()
else:
raise OperationDataInsertionError()
@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))
txs = connection.run(connection.space(table).select(transaction_id, index=TARANT_ID_SEARCH), only_data=False)
if len(txs) == 0:
return None
return DbTransaction.from_tuple(txs[0])
@register_query(TarantoolDBConnection)
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)
def get_transaction_single(connection, transaction_id) -> Union[DbTransaction, None]:
txs = get_complete_transactions_by_ids(txids=[transaction_id], connection=connection)
return txs[0] if len(txs) == 1 else None
@ -224,7 +193,7 @@ def get_assets(connection, assets_ids: list) -> list[Asset]:
@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) -> list[DbTransaction]:
_inputs = connection.run(
connection.space(TARANT_TABLE_TRANSACTION).select(
[fullfil_transaction_id, fullfil_output_index], index=TARANT_INDEX_SPENDING_BY_ID_AND_OUTPUT_INDEX
@ -234,8 +203,8 @@ def get_spent(connection, fullfil_transaction_id: str, fullfil_output_index: str
@register_query(TarantoolDBConnection)
def get_latest_block(connection):
blocks = connection.run(connection.space("blocks").select())
def get_latest_block(connection) -> Union[dict, None]:
blocks = connection.run(connection.space(TARANT_TABLE_BLOCKS).select())
if not blocks:
return None
@ -249,7 +218,7 @@ def store_block(connection, block: dict):
block_unique_id = uuid4().hex
try:
connection.run(
connection.space("blocks").insert(
connection.space(TARANT_TABLE_BLOCKS).insert(
(block_unique_id, block["app_hash"], block["height"], block[TARANT_TABLE_TRANSACTION])
),
only_data=False,
@ -260,7 +229,7 @@ def store_block(connection, block: dict):
@register_query(TarantoolDBConnection)
def get_txids_filtered(connection, asset_ids: list[str], operation: str = "", last_tx: bool = False):
def get_txids_filtered(connection, asset_ids: list[str], operation: str = "", last_tx: bool = False) -> list[str]:
transactions = []
if operation == "CREATE":
transactions = connection.run(
@ -308,7 +277,7 @@ def text_search(conn, search, table=TARANT_TABLE_ASSETS, limit=0):
@register_query(TarantoolDBConnection)
def get_owned_ids(connection, owner: str):
def get_owned_ids(connection, owner: str) -> list[DbTransaction]:
outputs = connection.run(connection.space(TARANT_TABLE_OUTPUT).select(owner, index="public_keys"))
if len(outputs) == 0:
return []
@ -333,8 +302,8 @@ def get_spending_transactions(connection, inputs):
@register_query(TarantoolDBConnection)
def get_block(connection, block_id=None):
_block = connection.run(connection.space("blocks").select(block_id, index="height", limit=1))
def get_block(connection, block_id=None) -> Union[dict, None]:
_block = connection.run(connection.space(TARANT_TABLE_BLOCKS).select(block_id, index="height", limit=1))
if len(_block) == 0:
return
_block = Block.from_tuple(_block[0])
@ -342,8 +311,8 @@ def get_block(connection, block_id=None):
@register_query(TarantoolDBConnection)
def get_block_with_transaction(connection, txid: str):
_block = connection.run(connection.space("blocks").select(txid, index="block_by_transaction_id"))
def get_block_with_transaction(connection, txid: str) -> list[Block]:
_block = connection.run(connection.space(TARANT_TABLE_BLOCKS).select(txid, index="block_by_transaction_id"))
return _block if len(_block) > 0 else []
@ -351,7 +320,7 @@ def get_block_with_transaction(connection, txid: str):
def delete_transactions(connection, txn_ids: list):
try:
for _id in txn_ids:
_outputs = get_outputs_by_tx_id( connection, _id)
_outputs = get_outputs_by_tx_id(connection, _id)
for x in range(len(_outputs)):
connection.connect().call("delete_output", (_outputs[x].id))
for _id in txn_ids:
@ -369,7 +338,9 @@ def store_unspent_outputs(connection, *unspent_outputs: list):
for utxo in unspent_outputs:
try:
output = connection.run(
connection.space("utxos").insert((uuid4().hex, utxo["transaction_id"], utxo["output_index"], utxo))
connection.space(TARANT_TABLE_UTXOS).insert(
(uuid4().hex, utxo["transaction_id"], utxo["output_index"], utxo)
)
)
result.append(output)
except Exception as e:
@ -384,7 +355,7 @@ def delete_unspent_outputs(connection, *unspent_outputs: list):
if unspent_outputs:
for utxo in unspent_outputs:
output = connection.run(
connection.space("utxos").delete(
connection.space(TARANT_TABLE_UTXOS).delete(
(utxo["transaction_id"], utxo["output_index"]), index="utxo_by_transaction_id_and_output_index"
)
)
@ -394,13 +365,13 @@ def delete_unspent_outputs(connection, *unspent_outputs: list):
@register_query(TarantoolDBConnection)
def get_unspent_outputs(connection, query=None): # for now we don't have implementation for 'query'.
_utxos = connection.run(connection.space("utxos").select([]))
_utxos = connection.run(connection.space(TARANT_TABLE_UTXOS).select([]))
return [utx[3] for utx in _utxos]
@register_query(TarantoolDBConnection)
def store_pre_commit_state(connection, state: dict):
_precommit = connection.run(connection.space("pre_commits").select([], limit=1))
_precommit = connection.run(connection.space(TARANT_TABLE_PRE_COMMITS).select([], limit=1))
_precommitTuple = (
(uuid4().hex, state["height"], state[TARANT_TABLE_TRANSACTION])
if _precommit is None or len(_precommit) == 0
@ -408,7 +379,7 @@ def store_pre_commit_state(connection, state: dict):
)
try:
connection.run(
connection.space("pre_commits").upsert(
connection.space(TARANT_TABLE_PRE_COMMITS).upsert(
_precommitTuple,
op_list=[("=", 1, state["height"]), ("=", 2, state[TARANT_TABLE_TRANSACTION])],
limit=1,
@ -421,8 +392,8 @@ def store_pre_commit_state(connection, state: dict):
@register_query(TarantoolDBConnection)
def get_pre_commit_state(connection):
_commit = connection.run(connection.space("pre_commits").select([], index=TARANT_ID_SEARCH))
def get_pre_commit_state(connection) -> dict:
_commit = connection.run(connection.space(TARANT_TABLE_PRE_COMMITS).select([], index=TARANT_ID_SEARCH))
if _commit is None or len(_commit) == 0:
return None
_commit = sorted(_commit, key=itemgetter(1), reverse=False)[0]
@ -431,11 +402,13 @@ def get_pre_commit_state(connection):
@register_query(TarantoolDBConnection)
def store_validator_set(conn, validators_update: dict):
_validator = conn.run(conn.space("validator_sets").select(validators_update["height"], index="height", limit=1))
_validator = conn.run(
conn.space(TARANT_TABLE_VALIDATOR_SETS).select(validators_update["height"], index="height", limit=1)
)
unique_id = uuid4().hex if _validator is None or len(_validator) == 0 else _validator[0][0]
try:
conn.run(
conn.space("validator_sets").upsert(
conn.space(TARANT_TABLE_VALIDATOR_SETS).upsert(
(unique_id, validators_update["height"], validators_update["validators"]),
op_list=[("=", 1, validators_update["height"]), ("=", 2, validators_update["validators"])],
limit=1,
@ -449,16 +422,16 @@ def store_validator_set(conn, validators_update: dict):
@register_query(TarantoolDBConnection)
def delete_validator_set(connection, height: int):
_validators = connection.run(connection.space("validator_sets").select(height, index="height"))
_validators = connection.run(connection.space(TARANT_TABLE_VALIDATOR_SETS).select(height, index="height"))
for _valid in _validators:
connection.run(connection.space("validator_sets").delete(_valid[0]), only_data=False)
connection.run(connection.space(TARANT_TABLE_VALIDATOR_SETS).delete(_valid[0]), only_data=False)
@register_query(TarantoolDBConnection)
def store_election(connection, election_id: str, height: int, is_concluded: bool):
try:
connection.run(
connection.space("elections").upsert(
connection.space(TARANT_TABLE_ELECTIONS).upsert(
(election_id, height, is_concluded), op_list=[("=", 1, height), ("=", 2, is_concluded)], limit=1
),
only_data=False,
@ -473,7 +446,7 @@ def store_elections(connection, elections: list):
try:
for election in elections:
_election = connection.run( # noqa: F841
connection.space("elections").insert(
connection.space(TARANT_TABLE_ELECTIONS).insert(
(election["election_id"], election["height"], election["is_concluded"])
),
only_data=False,
@ -485,14 +458,14 @@ def store_elections(connection, elections: list):
@register_query(TarantoolDBConnection)
def delete_elections(connection, height: int):
_elections = connection.run(connection.space("elections").select(height, index="height"))
_elections = connection.run(connection.space(TARANT_TABLE_ELECTIONS).select(height, index="height"))
for _elec in _elections:
connection.run(connection.space("elections").delete(_elec[0]), only_data=False)
connection.run(connection.space(TARANT_TABLE_ELECTIONS).delete(_elec[0]), only_data=False)
@register_query(TarantoolDBConnection)
def get_validator_set(connection, height: int = None):
_validators = connection.run(connection.space("validator_sets").select())
_validators = connection.run(connection.space(TARANT_TABLE_VALIDATOR_SETS).select())
if height is not None and _validators is not None:
_validators = [
{"height": validator[1], "validators": validator[2]} for validator in _validators if validator[1] <= height
@ -505,8 +478,8 @@ def get_validator_set(connection, height: int = None):
@register_query(TarantoolDBConnection)
def get_election(connection, election_id: str):
_elections = connection.run(connection.space("elections").select(election_id, index=TARANT_ID_SEARCH))
def get_election(connection, election_id: str) -> dict:
_elections = connection.run(connection.space(TARANT_TABLE_ELECTIONS).select(election_id, index=TARANT_ID_SEARCH))
if _elections is None or len(_elections) == 0:
return None
_election = sorted(_elections, key=itemgetter(0), reverse=True)[0]
@ -515,29 +488,19 @@ def get_election(connection, election_id: str):
@register_query(TarantoolDBConnection)
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 = _transactions
# _keys = _keys.data
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])
return get_complete_transactions_by_ids(connection, [_tx[0] for _tx in transactions])
@register_query(TarantoolDBConnection)
def store_abci_chain(connection, height: int, chain_id: str, is_synced: bool = True):
try:
connection.run(
connection.space("abci_chains").upsert(
connection.space(TARANT_TABLE_ABCI_CHAINS).upsert(
(chain_id, height, is_synced),
op_list=[("=", 0, chain_id), ("=", 1, height), ("=", 2, is_synced)],
),
@ -550,15 +513,13 @@ def store_abci_chain(connection, height: int, chain_id: str, is_synced: bool = T
@register_query(TarantoolDBConnection)
def delete_abci_chain(connection, height: int):
hash_id_primarykey = sha256(json.dumps(obj={"height": height}).encode()).hexdigest()
# connection.run(connection.space("abci_chains").delete(hash_id_primarykey), only_data=False)
chains = connection.run(connection.space("abci_chains").select(height, index="height"), only_data=False)
connection.run(connection.space("abci_chains").delete(chains[0][0], index="id"), only_data=False)
chains = connection.run(connection.space(TARANT_TABLE_ABCI_CHAINS).select(height, index="height"), only_data=False)
connection.run(connection.space(TARANT_TABLE_ABCI_CHAINS).delete(chains[0][0], index="id"), only_data=False)
@register_query(TarantoolDBConnection)
def get_latest_abci_chain(connection):
_all_chains = connection.run(connection.space("abci_chains").select())
def get_latest_abci_chain(connection) -> Union[dict, None]:
_all_chains = connection.run(connection.space(TARANT_TABLE_ABCI_CHAINS).select())
if _all_chains is None or len(_all_chains) == 0:
return None
_chain = sorted(_all_chains, key=itemgetter(1), reverse=True)[0]

View File

@ -8,142 +8,6 @@ from planetmint.backend.tarantool.connection import TarantoolDBConnection
logger = logging.getLogger(__name__)
register_schema = module_dispatch_registrar(backend.schema)
SPACE_NAMES = (
"abci_chains",
"assets",
"blocks",
"blocks_tx",
"elections",
"meta_data",
"pre_commits",
"validators",
"transactions",
"inputs",
"outputs",
"keys",
"utxos",
"scripts",
)
SPACE_COMMANDS = {
"abci_chains": "abci_chains = box.schema.space.create('abci_chains', {engine='memtx', is_sync = false})",
"assets": "assets = box.schema.space.create('assets' , {engine='memtx' , is_sync=false})",
"blocks": "blocks = box.schema.space.create('blocks' , {engine='memtx' , is_sync=false})",
"blocks_tx": "blocks_tx = box.schema.space.create('blocks_tx')",
"elections": "elections = box.schema.space.create('elections',{engine = 'memtx' , is_sync = false})",
"meta_data": "meta_datas = box.schema.space.create('meta_data',{engine = 'memtx' , is_sync = false})",
"pre_commits": "pre_commits = box.schema.space.create('pre_commits' , {engine='memtx' , is_sync=false})",
"validators": "validators = box.schema.space.create('validators' , {engine = 'memtx' , is_sync = false})",
"transactions": "transactions = box.schema.space.create('transactions',{engine='memtx' , is_sync=false})",
"inputs": "inputs = box.schema.space.create('inputs')",
"outputs": "outputs = box.schema.space.create('outputs')",
"keys": "keys = box.schema.space.create('keys')",
"utxos": "utxos = box.schema.space.create('utxos', {engine = 'memtx' , is_sync = false})",
"scripts": "scripts = box.schema.space.create('scripts', {engine = 'memtx' , is_sync = false})",
}
INDEX_COMMANDS = {
"abci_chains": {
"id_search": "abci_chains:create_index('id_search' ,{type='tree', parts={'id'}})",
"height_search": "abci_chains:create_index('height_search' ,{type='tree', unique=false, parts={'height'}})",
},
"assets": {
"txid_search": "assets:create_index('txid_search', {type='tree', parts={'tx_id'}})",
"assetid_search": "assets:create_index('assetid_search', {type='tree',unique=false, parts={'asset_id', 'tx_id'}})", # noqa: E501
"only_asset_search": "assets:create_index('only_asset_search', {type='tree', unique=false, parts={'asset_id'}})", # noqa: E501
"text_search": "assets:create_index('secondary', {unique=false,parts={1,'string'}})",
},
"blocks": {
"id_search": "blocks:create_index('id_search' , {type='tree' , parts={'block_id'}})",
"block_search": "blocks:create_index('block_search' , {type='tree', unique = false, parts={'height'}})",
"block_id_search": "blocks:create_index('block_id_search', {type = 'hash', parts ={'block_id'}})",
},
"blocks_tx": {
"id_search": "blocks_tx:create_index('id_search',{ type = 'tree', parts={'transaction_id'}})",
"block_search": "blocks_tx:create_index('block_search', {type = 'tree',unique=false, parts={'block_id'}})",
},
"elections": {
"id_search": "elections:create_index('id_search' , {type='tree', parts={'election_id'}})",
"height_search": "elections:create_index('height_search' , {type='tree',unique=false, parts={'height'}})",
"update_search": "elections:create_index('update_search', {type='tree', unique=false, parts={'election_id', 'height'}})", # noqa: E501
},
"meta_data": {
"id_search": "meta_datas:create_index('id_search', { type='tree' , parts={'transaction_id'}})",
"text_search": "meta_datas:create_index('secondary', {unique=false,parts={2,'string'}})",
},
"pre_commits": {
"id_search": "pre_commits:create_index('id_search', {type ='tree' , parts={'commit_id'}})",
"height_search": "pre_commits:create_index('height_search', {type ='tree',unique=true, parts={'height'}})",
},
"validators": {
"id_search": "validators:create_index('id_search' , {type='tree' , parts={'validator_id'}})",
"height_search": "validators:create_index('height_search' , {type='tree', unique=true, parts={'height'}})",
},
"transactions": {
"id_search": "transactions:create_index('id_search' , {type = 'tree' , parts={'transaction_id'}})",
"transaction_search": "transactions:create_index('transaction_search' , {type = 'tree',unique=false, parts={'operation', 'transaction_id'}})", # noqa: E501
},
"inputs": {
"delete_search": "inputs:create_index('delete_search' , {type = 'tree', parts={'input_id'}})",
"spent_search": "inputs:create_index('spent_search' , {type = 'tree', unique=false, parts={'fulfills_transaction_id', 'fulfills_output_index'}})", # noqa: E501
"id_search": "inputs:create_index('id_search', {type = 'tree', unique=false, parts = {'transaction_id'}})",
},
"outputs": {
"unique_search": "outputs:create_index('unique_search' ,{type='tree', parts={'output_id'}})",
"id_search": "outputs:create_index('id_search' ,{type='tree', unique=false, parts={'transaction_id'}})",
},
"keys": {
"id_search": "keys:create_index('id_search', {type = 'tree', parts={'id'}})",
"keys_search": "keys:create_index('keys_search', {type = 'tree', unique=false, parts={'public_key'}})",
"txid_search": "keys:create_index('txid_search', {type = 'tree', unique=false, parts={'transaction_id'}})",
"output_search": "keys:create_index('output_search', {type = 'tree', unique=false, parts={'output_id'}})",
},
"utxos": {
"id_search": "utxos:create_index('id_search', {type='tree' , parts={'transaction_id', 'output_index'}})",
"transaction_search": "utxos:create_index('transaction_search', {type='tree', unique=false, parts={'transaction_id'}})", # noqa: E501
"index_Search": "utxos:create_index('index_search', {type='tree', unique=false, parts={'output_index'}})",
},
"scripts": {
"txid_search": "scripts:create_index('txid_search', {type='tree', parts={'transaction_id'}})",
},
}
SCHEMA_COMMANDS = {
"abci_chains": "abci_chains:format({{name='height' , type='integer'},{name='is_synched' , type='boolean'},{name='chain_id',type='string'}, {name='id', type='string'}})", # noqa: E501
"assets": "assets:format({{name='data' , type='string'}, {name='tx_id', type='string'}, {name='asset_id', type='string'}})", # noqa: E501
"blocks": "blocks:format{{name='app_hash',type='string'},{name='height' , type='integer'},{name='block_id' , type='string'}}", # noqa: E501
"blocks_tx": "blocks_tx:format{{name='transaction_id', type = 'string'}, {name = 'block_id', type = 'string'}}",
"elections": "elections:format({{name='election_id' , type='string'},{name='height' , type='integer'}, {name='is_concluded' , type='boolean'}})", # noqa: E501
"meta_data": "meta_datas:format({{name='transaction_id' , type='string'}, {name='meta_data' , type='string'}})", # noqa: E501
"pre_commits": "pre_commits:format({{name='commit_id', type='string'}, {name='height',type='integer'}, {name='transactions',type=any}})", # noqa: E501
"validators": "validators:format({{name='validator_id' , type='string'},{name='height',type='integer'},{name='validators' , type='any'}})", # noqa: E501
"transactions": "transactions:format({{name='transaction_id' , type='string'}, {name='operation' , type='string'}, {name='version' ,type='string'}, {name='dict_map', type='any'}})", # noqa: E501
"inputs": "inputs:format({{name='transaction_id' , type='string'}, {name='fulfillment' , type='any'}, {name='owners_before' , type='array'}, {name='fulfills_transaction_id', type = 'string'}, {name='fulfills_output_index', type = 'string'}, {name='input_id', type='string'}, {name='input_index', type='number'}})", # noqa: E501
"outputs": "outputs:format({{name='transaction_id' , type='string'}, {name='amount' , type='string'}, {name='uri', type='string'}, {name='details_type', type='string'}, {name='details_public_key', type='any'}, {name = 'output_id', type = 'string'}, {name='treshold', type='any'}, {name='subconditions', type='any'}, {name='output_index', type='number'}})", # noqa: E501
"keys": "keys:format({{name = 'id', type='string'}, {name = 'transaction_id', type = 'string'} ,{name = 'output_id', type = 'string'}, {name = 'public_key', type = 'string'}, {name = 'key_index', type = 'integer'}})", # noqa: E501
"utxos": "utxos:format({{name='transaction_id' , type='string'}, {name='output_index' , type='integer'}, {name='utxo_dict', type='string'}})", # noqa: E501
"scripts": "scripts:format({{name='transaction_id', type='string'},{name='script' , type='any'}})", # noqa: E501
}
SCHEMA_DROP_COMMANDS = {
"abci_chains": "box.space.abci_chains:drop()",
"assets": "box.space.assets:drop()",
"blocks": "box.space.blocks:drop()",
"blocks_tx": "box.space.blocks_tx:drop()",
"elections": "box.space.elections:drop()",
"meta_data": "box.space.meta_data:drop()",
"pre_commits": "box.space.pre_commits:drop()",
"validators": "box.space.validators:drop()",
"transactions": "box.space.transactions:drop()",
"inputs": "box.space.inputs:drop()",
"outputs": "box.space.outputs:drop()",
"keys": "box.space.keys:drop()",
"utxos": "box.space.utxos:drop()",
"scripts": "box.space.scripts:drop()",
}
@register_schema(TarantoolDBConnection)
def init_database(connection, db_name=None):

View File

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

View File

@ -163,8 +163,8 @@ class Planetmint(object):
else:
txns.append(transaction)
backend.query.store_transactions(self.connection, txns)
backend.query.store_governance_transactions(self.connection, gov_txns)
backend.query.store_transactions(self.connection, txns, TARANT_TABLE_TRANSACTION)
backend.query.store_transactions(self.connection, gov_txns, TARANT_TABLE_GOVERNANCE)
def delete_transactions(self, txs):
return backend.query.delete_transactions(self.connection, txs)
@ -245,12 +245,12 @@ class Planetmint(object):
if unspent_outputs:
return backend.query.delete_unspent_outputs(self.connection, *unspent_outputs)
def is_committed(self, transaction_id, table=TARANT_TABLE_TRANSACTION):
transaction = backend.query.get_transaction_by_id(self.connection, transaction_id, table)
def is_committed(self, transaction_id):
transaction = backend.query.get_transaction_single(self.connection, transaction_id)
return bool(transaction)
def get_transaction(self, transaction_id, table=TARANT_TABLE_TRANSACTION):
return backend.query.get_transaction_single(self.connection, transaction_id, table)
def get_transaction(self, transaction_id):
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)
@ -261,9 +261,6 @@ 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)
@ -390,13 +387,9 @@ class Planetmint(object):
input_txs = []
input_conditions = []
table = TARANT_TABLE_TRANSACTION
if tx.operation in GOVERNANCE_TRANSACTION_TYPES:
table = TARANT_TABLE_GOVERNANCE
for input_ in tx.inputs:
input_txid = input_.fulfills.txid
input_tx = self.get_transaction(input_txid, table)
input_tx = self.get_transaction(input_txid)
_output = self.get_outputs_by_tx_id(input_txid)
if input_tx is None:
for ctxn in current_transactions:
@ -430,7 +423,7 @@ class Planetmint(object):
# validate asset id
asset_id = tx.get_asset_id(input_txs)
if asset_id != tx.assets[0]["id"]:
if asset_id != Transaction.read_out_asset_id(tx):
raise AssetIdMismatch(("The asset id of the input does not" " match the asset id of the" " transaction"))
# convert planetmint.Output objects to transactions.common.Output objects
@ -614,7 +607,7 @@ class Planetmint(object):
"""
duplicates = any(txn for txn in current_transactions if txn.id == transaction.id)
if self.is_committed(transaction.id, TARANT_TABLE_GOVERNANCE) or duplicates:
if self.is_committed(transaction.id) or duplicates:
raise DuplicateTransaction("transaction `{}` already exists".format(transaction.id))
current_validators = self.get_validators_dict()
@ -823,7 +816,7 @@ class Planetmint(object):
validator_update = None
for election_id, votes in elections.items():
election = self.get_transaction(election_id, TARANT_TABLE_GOVERNANCE)
election = self.get_transaction(election_id)
if election is None:
continue

View File

@ -3,8 +3,8 @@
# SPDX-License-Identifier: (Apache-2.0 AND CC-BY-4.0)
# Code is Apache-2.0 and docs are CC-BY-4.0
__version__ = "1.3.2"
__short_version__ = "1.3"
__version__ = "1.4.1"
__short_version__ = "1.4"
# Supported Tendermint versions
__tm_supported_versions__ = ["0.34.15"]

View File

@ -92,6 +92,13 @@ class TransactionListApi(Resource):
except ValidationError as e:
return make_error(400, "Invalid transaction ({}): {}".format(type(e).__name__, e))
else:
if tx_obj.version != Transaction.VERSION:
return make_error(
401,
"Invalid transaction version: The transaction is valid, \
but this node only accepts transaction with higher \
schema version number.",
)
status_code, message = planet.write_transaction(tx_obj, mode)
if status_code == 202:

View File

@ -103,7 +103,6 @@ tests_require = [
"pytest-flask",
"pytest-aiohttp",
"pytest-asyncio",
"tox",
] + docs_require
install_requires = [
@ -130,7 +129,7 @@ install_requires = [
"planetmint-ipld>=0.0.3",
"pyasn1>=0.4.8",
"python-decouple",
# "planetmint-transactions>=0.2.2",
"planetmint-transactions>=0.5.0",
]
setup(

View File

@ -9,7 +9,7 @@ from transactions.types.assets.create import Create
from transactions.types.assets.transfer import Transfer
def test_asset_transfer(b, signed_create_tx, user_pk, user_sk):
def test_asset_transfer(b, signed_create_tx, user_pk, user_sk, _bdb):
tx_transfer = Transfer.generate(signed_create_tx.to_inputs(), [([user_pk], 1)], [signed_create_tx.id])
tx_transfer_signed = tx_transfer.sign([user_sk])
@ -24,7 +24,7 @@ def test_asset_transfer(b, signed_create_tx, user_pk, user_sk):
# from planetmint.transactions.common.exceptions import AssetIdMismatch
def test_validate_transfer_asset_id_mismatch(b, signed_create_tx, user_pk, user_sk):
def test_validate_transfer_asset_id_mismatch(b, signed_create_tx, user_pk, user_sk, _bdb):
from transactions.common.exceptions import AssetIdMismatch
tx_transfer = Transfer.generate(signed_create_tx.to_inputs(), [([user_pk], 1)], [signed_create_tx.id])
@ -69,7 +69,23 @@ def test_asset_id_mismatch(alice, user_pk):
Transaction.get_asset_id([tx1, tx2])
def test_create_valid_divisible_asset(b, user_pk, user_sk):
def test_create_valid_divisible_asset(b, user_pk, user_sk, _bdb):
tx = Create.generate([user_pk], [([user_pk], 2)])
tx_signed = tx.sign([user_sk])
assert b.validate_transaction(tx_signed) == tx_signed
def test_v_2_0_validation_create(b, signed_2_0_create_tx, _bdb):
validated = b.validate_transaction(signed_2_0_create_tx)
assert validated.to_dict() == signed_2_0_create_tx
def test_v_2_0_validation_create_invalid(b, signed_2_0_create_tx_assets, _bdb):
assert b.validate_transaction(signed_2_0_create_tx_assets)
def test_v_2_0_validation_transfer(b, signed_2_0_create_tx, signed_2_0_transfer_tx, _bdb):
validated = b.validate_transaction(signed_2_0_create_tx)
b.store_bulk_transactions([validated])
assert validated.to_dict() == signed_2_0_create_tx
assert b.validate_transaction(signed_2_0_transfer_tx).to_dict() == signed_2_0_transfer_tx

View File

@ -3,8 +3,6 @@
# SPDX-License-Identifier: (Apache-2.0 AND CC-BY-4.0)
# Code is Apache-2.0 and docs are CC-BY-4.0
from planetmint.backend.tarantool.connection import TarantoolDBConnection
def _check_spaces_by_list(conn, space_names):
_exists = []

View File

@ -7,7 +7,7 @@ import pytest
def test_get_connection_raises_a_configuration_error(monkeypatch):
from planetmint.backend.connection import ConnectionError
from planetmint.backend.exceptions import ConnectionError
from planetmint.backend.tarantool.connection import TarantoolDBConnection
with pytest.raises(ConnectionError):

View File

@ -14,7 +14,6 @@ from planetmint import ValidatorElection
from planetmint.commands.planetmint import run_election_show
from planetmint.commands.planetmint import run_election_new_chain_migration
from planetmint.backend.connection import Connection
from planetmint.backend.tarantool.const import TARANT_TABLE_GOVERNANCE
from planetmint.lib import Block
from transactions.types.elections.chain_migration_election import ChainMigrationElection
@ -323,7 +322,7 @@ def test_election_new_upsert_validator_with_tendermint(b, priv_validator_path, u
election_id = run_election_new_upsert_validator(new_args, b)
assert b.get_transaction(election_id, TARANT_TABLE_GOVERNANCE)
assert b.get_transaction(election_id)
@pytest.mark.bdb
@ -350,7 +349,7 @@ def test_election_new_upsert_validator_without_tendermint(caplog, b, priv_valida
with caplog.at_level(logging.INFO):
election_id = run_election_new_upsert_validator(args, b)
assert caplog.records[0].msg == "[SUCCESS] Submitted proposal with id: " + election_id
assert b.get_transaction(election_id, TARANT_TABLE_GOVERNANCE)
assert b.get_transaction(election_id)
@pytest.mark.abci
@ -359,7 +358,7 @@ def test_election_new_chain_migration_with_tendermint(b, priv_validator_path, us
election_id = run_election_new_chain_migration(new_args, b)
assert b.get_transaction(election_id, TARANT_TABLE_GOVERNANCE)
assert b.get_transaction(election_id)
@pytest.mark.bdb
@ -376,7 +375,7 @@ def test_election_new_chain_migration_without_tendermint(caplog, b, priv_validat
with caplog.at_level(logging.INFO):
election_id = run_election_new_chain_migration(args, b)
assert caplog.records[0].msg == "[SUCCESS] Submitted proposal with id: " + election_id
assert b.get_transaction(election_id, TARANT_TABLE_GOVERNANCE)
assert b.get_transaction(election_id)
@pytest.mark.bdb
@ -445,7 +444,7 @@ def test_election_approve_with_tendermint(b, priv_validator_path, user_sk, valid
args = Namespace(action="approve", election_id=election_id, sk=priv_validator_path, config={})
approve = run_election_approve(args, b)
assert b.get_transaction(approve, TARANT_TABLE_GOVERNANCE)
assert b.get_transaction(approve)
@pytest.mark.bdb
@ -462,7 +461,7 @@ def test_election_approve_without_tendermint(caplog, b, priv_validator_path, new
with caplog.at_level(logging.INFO):
approval_id = run_election_approve(args, b)
assert caplog.records[0].msg == "[SUCCESS] Your vote has been submitted"
assert b.get_transaction(approval_id, TARANT_TABLE_GOVERNANCE)
assert b.get_transaction(approval_id)
@pytest.mark.bdb

View File

@ -27,7 +27,6 @@ from transactions.common.transaction_mode_types import BROADCAST_TX_COMMIT
from planetmint.tendermint_utils import key_from_base64
from planetmint.backend import schema, query
from transactions.common.crypto import key_pair_from_ed25519_key, public_key_from_ed25519_key
from transactions.common.exceptions import DatabaseDoesNotExist
from planetmint.lib import Block
from tests.utils import gen_vote
from planetmint.config import Config
@ -736,3 +735,110 @@ def generate_votes(election, voters, keys):
v = gen_vote(election, voter, keys)
votes.append(v)
return votes
@pytest.fixture
def signed_2_0_create_tx():
return {
"inputs": [
{
"owners_before": ["7WaJCRqUJMZjVyQxqq8GNjkw11gacFmDAZGPLdNxfBgx"],
"fulfills": None,
"fulfillment": "pGSAIGC5nQ37hCCMAWIUBAJn4wVBOkHlURaWzWLjE5rTzG91gUC0Akx2m_AoPy1H6yTz7Ou2I-OGjNjWgvR5EATn8XZ1u-g91XL3CkSXXiL2sUJqDibJQJjGZjag_7fRu5_VkDUD",
}
],
"outputs": [
{
"public_keys": ["7WaJCRqUJMZjVyQxqq8GNjkw11gacFmDAZGPLdNxfBgx"],
"condition": {
"details": {
"type": "ed25519-sha-256",
"public_key": "7WaJCRqUJMZjVyQxqq8GNjkw11gacFmDAZGPLdNxfBgx",
},
"uri": "ni:///sha-256;xtKK2YRiX7_EPF2harsf-PELcJwfHQM7jZ_YvilEOOI?fpt=ed25519-sha-256&cost=131072",
},
"amount": "3000",
}
],
"operation": "CREATE",
"metadata": "QmRBri4SARi56PgB2ALFVjHsLhQDUh4jYbeiHaU94vLoxd",
"asset": {"data": "QmW5GVMW98D3mktSDfWHS8nX2UiCd8gP1uCiujnFX4yK8n"},
"version": "2.0",
"id": "334014a29d99a488789c711b7dc5fceb534d1a9290b14d0270dbe6b60e2f036e",
}
@pytest.fixture
def signed_2_0_create_tx_assets():
return {
"inputs": [
{
"owners_before": ["5V4AANHTSLdQH1mEA1pohW3jMduY9xMJ1voos7gRfMQF"],
"fulfills": None,
"fulfillment": "pGSAIEKelMEu8AzcA9kcDLrsEXhSpZG-lf2c9CuZpzZU_ONkgUBMztcnweWqwHVfVk9Y-IRgfdh864yXYTrTKzSMy6uvNjQeLtGzKxz4gjb01NUu6WLvZBAvr0Ws4glfxKiDLjkP",
}
],
"outputs": [
{
"public_keys": ["5V4AANHTSLdQH1mEA1pohW3jMduY9xMJ1voos7gRfMQF"],
"condition": {
"details": {
"type": "ed25519-sha-256",
"public_key": "5V4AANHTSLdQH1mEA1pohW3jMduY9xMJ1voos7gRfMQF",
},
"uri": "ni:///sha-256;M3l9yVs7ItjP-lxT7B2ta6rpRa-GHt6TBSYpy8l-IS8?fpt=ed25519-sha-256&cost=131072",
},
"amount": "3000",
}
],
"operation": "CREATE",
"metadata": "QmRBri4SARi56PgB2ALFVjHsLhQDUh4jYbeiHaU94vLoxd",
"assets": {"data": "QmW5GVMW98D3mktSDfWHS8nX2UiCd8gP1uCiujnFX4yK8n"},
"version": "2.0",
"id": "3e2a2c5eef5e6a0c4e1e5f8d0dc1d3d9b4f035592a9788f8bfa7d59f86d123d3",
}
@pytest.fixture
def signed_2_0_transfer_tx():
return {
"inputs": [
{
"owners_before": ["7WaJCRqUJMZjVyQxqq8GNjkw11gacFmDAZGPLdNxfBgx"],
"fulfills": {
"transaction_id": "334014a29d99a488789c711b7dc5fceb534d1a9290b14d0270dbe6b60e2f036e",
"output_index": 0,
},
"fulfillment": "pGSAIGC5nQ37hCCMAWIUBAJn4wVBOkHlURaWzWLjE5rTzG91gUBHNp8jobEyMqcIcIFl-TaAEDHRMyigDutgCIIomyVgb1a0LIk5eEpMTVP4ACxZnrVH-SIKEDHNdH4FGyBMka4B",
}
],
"outputs": [
{
"public_keys": ["3m1tUV5hmWPBaNQEoyFtZxFgDFiHYAYvPMzczNHwWp5v"],
"condition": {
"details": {
"type": "ed25519-sha-256",
"public_key": "3m1tUV5hmWPBaNQEoyFtZxFgDFiHYAYvPMzczNHwWp5v",
},
"uri": "ni:///sha-256;4pXSmxViATpOG8Mcc0gYsa-4bjRnLk5MY06VXv_UeJA?fpt=ed25519-sha-256&cost=131072",
},
"amount": "50",
},
{
"public_keys": ["7WaJCRqUJMZjVyQxqq8GNjkw11gacFmDAZGPLdNxfBgx"],
"condition": {
"details": {
"type": "ed25519-sha-256",
"public_key": "7WaJCRqUJMZjVyQxqq8GNjkw11gacFmDAZGPLdNxfBgx",
},
"uri": "ni:///sha-256;xtKK2YRiX7_EPF2harsf-PELcJwfHQM7jZ_YvilEOOI?fpt=ed25519-sha-256&cost=131072",
},
"amount": "2950",
},
],
"operation": "TRANSFER",
"metadata": "QmTjWHzypFxE8uuXJXMJQJxgAEKjoWmQimGiutmPyJ6CAB",
"asset": {"id": "334014a29d99a488789c711b7dc5fceb534d1a9290b14d0270dbe6b60e2f036e"},
"version": "2.0",
"id": "e577641b0e2eb619e282f802516ce043e9d4af51dd4b6c959e18246e85cae2a6",
}

View File

@ -50,7 +50,6 @@ class TestBigchainApi(object):
with pytest.raises(CriticalDoubleSpend):
b.store_bulk_transactions([transfer_tx2])
def test_double_inclusion(self, b, alice):
from tarantool.error import DatabaseError

View File

@ -411,7 +411,7 @@ def test_rollback_pre_commit_state_after_crash(b):
rollback(b)
for tx in txs:
assert b.get_transaction(tx.id, TARANT_TABLE_GOVERNANCE)
assert b.get_transaction(tx.id)
assert b.get_latest_abci_chain()
assert len(b.get_validator_set()["validators"]) == 1
assert b.get_election(migration_election.id)
@ -422,7 +422,7 @@ def test_rollback_pre_commit_state_after_crash(b):
rollback(b)
for tx in txs:
assert not b.get_transaction(tx.id, TARANT_TABLE_GOVERNANCE)
assert not b.get_transaction(tx.id)
assert not b.get_latest_abci_chain()
assert len(b.get_validator_set()["validators"]) == 4
assert len(b.get_validator_set(2)["validators"]) == 4

View File

@ -170,69 +170,21 @@ def test_update_utxoset(b, signed_create_tx, signed_transfer_tx, db_conn):
@pytest.mark.bdb
def test_store_transaction(mocker, b, signed_create_tx, signed_transfer_tx, db_context):
from planetmint.backend.tarantool.connection import TarantoolDBConnection
def test_store_transaction(mocker, b, signed_create_tx, signed_transfer_tx):
mocked_store_transaction = mocker.patch("planetmint.backend.query.store_transactions")
b.store_bulk_transactions([signed_create_tx])
if not isinstance(b.connection, TarantoolDBConnection):
mongo_client = MongoClient(host=db_context.host, port=db_context.port)
utxoset = mongo_client[db_context.name]["utxos"]
assert utxoset.count_documents({}) == 1
utxo = utxoset.find_one()
assert utxo["transaction_id"] == signed_create_tx.id
assert utxo["output_index"] == 0
mocked_store_transaction.assert_called_once_with(
b.connection,
[signed_create_tx.to_dict()],
)
mocked_store_transaction.assert_any_call(b.connection, [signed_create_tx.to_dict()], "transactions")
mocked_store_transaction.reset_mock()
b.store_bulk_transactions([signed_transfer_tx])
if not isinstance(b.connection, TarantoolDBConnection):
assert utxoset.count_documents({}) == 1
utxo = utxoset.find_one()
assert utxo["transaction_id"] == signed_transfer_tx.id
assert utxo["output_index"] == 0
if not isinstance(b.connection, TarantoolDBConnection):
mocked_store_transaction.assert_called_once_with(
b.connection,
[signed_transfer_tx.to_dict()],
)
@pytest.mark.bdb
def test_store_bulk_transaction(mocker, b, signed_create_tx, signed_transfer_tx, db_context):
from planetmint.backend.tarantool.connection import TarantoolDBConnection
def test_store_bulk_transaction(mocker, b, signed_create_tx, signed_transfer_tx):
mocked_store_transactions = mocker.patch("planetmint.backend.query.store_transactions")
b.store_bulk_transactions((signed_create_tx,))
if not isinstance(b.connection, TarantoolDBConnection):
mongo_client = MongoClient(host=db_context.host, port=db_context.port)
utxoset = mongo_client[db_context.name]["utxos"]
assert utxoset.count_documents({}) == 1
utxo = utxoset.find_one()
assert utxo["transaction_id"] == signed_create_tx.id
assert utxo["output_index"] == 0
mocked_store_transactions.assert_called_once_with(
b.connection,
[signed_create_tx.to_dict()],
)
mocked_store_transactions.assert_any_call(b.connection, [signed_create_tx.to_dict()], "transactions")
mocked_store_transactions.reset_mock()
b.store_bulk_transactions((signed_transfer_tx,))
if not isinstance(b.connection, TarantoolDBConnection):
assert utxoset.count_documents({}) == 1
utxo = utxoset.find_one()
assert utxo["transaction_id"] == signed_transfer_tx.id
assert utxo["output_index"] == 0
if not isinstance(b.connection, TarantoolDBConnection):
mocked_store_transactions.assert_called_once_with(
b.connection,
[signed_transfer_tx.to_dict()],
)
@pytest.mark.bdb

View File

@ -89,7 +89,7 @@ def test_get_spent_issue_1271(b, alice, bob, carol):
assert b.validate_transaction(tx_5)
b.store_bulk_transactions([tx_5])
assert b.get_spent(tx_2.id, 0) == tx_5.to_dict()
assert b.get_spent(tx_2.id, 0) == tx_5.to_dict()
assert not b.get_spent(tx_5.id, 0)
assert b.get_outputs_filtered(alice.public_key)
assert b.get_outputs_filtered(alice.public_key, spent=False)

View File

@ -248,7 +248,7 @@ def test_upsert_validator(b, node_key, node_keys, ed25519_node_keys):
)
code, message = b.write_transaction(election, BROADCAST_TX_COMMIT)
assert code == 202
assert b.get_transaction(election.id, TARANT_TABLE_GOVERNANCE)
assert b.get_transaction(election.id)
tx_vote = gen_vote(election, 0, ed25519_node_keys)
assert b.validate_transaction(tx_vote)

View File

@ -10,7 +10,7 @@ import random
from functools import singledispatch
from planetmint.backend.localmongodb.connection import LocalMongoDBConnection
from planetmint.backend.tarantool.connection import TarantoolDBConnection
from planetmint.backend.schema import TABLES, SPACE_NAMES
from planetmint.backend.schema import TABLES
from transactions.common import crypto
from transactions.common.transaction_mode_types import BROADCAST_TX_COMMIT
from transactions.types.assets.create import Create
@ -40,7 +40,9 @@ def generate_block(planet):
from transactions.common.crypto import generate_key_pair
alice = generate_key_pair()
tx = Create.generate([alice.public_key], [([alice.public_key], 1)], assets=[{"data":None}]).sign([alice.private_key])
tx = Create.generate([alice.public_key], [([alice.public_key], 1)], assets=[{"data": None}]).sign(
[alice.private_key]
)
code, message = planet.write_transaction(tx, BROADCAST_TX_COMMIT)
assert code == 202

31
tox.ini
View File

@ -1,31 +0,0 @@
[tox]
skipsdist = true
envlist = py{39}, docsroot
[gh-actions]
python =
3.9 = docsroot
[base]
basepython = python3.9
deps = pip>=9.0.1
[testenv]
usedevelop = True
setenv =
PYTHONPATH={toxinidir}:{toxinidir}/planetmint
deps = {[base]deps}
install_command = pip install {opts} {packages}
extras = test
commands = pytest -v -n auto --cov=planetmint --basetemp={envtmpdir}
[testenv:docsroot]
basepython = {[base]basepython}
changedir = docs/root/source
deps =
{[base]deps}
typing-extensions
-r{toxinidir}/docs/root/requirements.txt
extras = None
commands = sphinx-build -b html -d {envtmpdir}/doctrees . {envtmpdir}/html