Merge branch 'planetmint-tarantool' into connection_singleton

Signed-off-by: Jürgen Eckel <juergen@riddleandcode.com>
This commit is contained in:
Jürgen Eckel 2022-09-23 00:46:44 +02:00
commit b881843461
No known key found for this signature in database
41 changed files with 265 additions and 304 deletions

View File

@ -81,6 +81,7 @@ def zenroom_script_input():
return SCRIPT_INPUT
@pytest.fixture
def zenroom_data():
return ZENROOM_DATA

View File

@ -38,6 +38,26 @@ def test_zenroom_signing(
zenroomscpt = ZenroomSha256(script=fulfill_script_zencode, data=zenroom_data, keys=zen_public_keys)
print(f"zenroom is: {zenroomscpt.script}")
def test_zenroom_signing(gen_key_zencode, secret_key_to_private_key_zencode,
fulfill_script_zencode, zenroom_data, zenroom_house_assets,
condition_script_zencode):
biolabs = generate_keypair()
version = '2.0'
alice = json.loads(zencode_exec(gen_key_zencode).output)['keyring']
bob = json.loads(zencode_exec(gen_key_zencode).output)['keyring']
zen_public_keys = json.loads(zencode_exec(secret_key_to_private_key_zencode.format('Alice'),
keys=json.dumps({'keyring': alice})).output)
zen_public_keys.update(json.loads(zencode_exec(secret_key_to_private_key_zencode.format('Bob'),
keys=json.dumps({'keyring': bob})).output))
zenroomscpt = ZenroomSha256(script=fulfill_script_zencode, data=zenroom_data, keys=zen_public_keys)
print(F'zenroom is: {zenroomscpt.script}')
# CRYPTO-CONDITIONS: generate the condition uri
condition_uri_zen = zenroomscpt.condition.serialize_uri()
print(f"\nzenroom condition URI: {condition_uri_zen}")
@ -73,6 +93,11 @@ def test_zenroom_signing(
"output": ["ok"],
"policies": {},
}
metadata = {
"result": {
"output": ["ok"]
}
}
token_creation_tx = {
"operation": "CREATE",

View File

@ -151,6 +151,7 @@ and
Planetmint has been developed with simple logical gateways in mind. The logic got introduced by [cryptoconditions](https://https://docs.planetmint.io/projects/cryptoconditions). The cryptocondition documentation contains all details about how conditoins are defined and how they can be verified and fulfilled.
<<<<<<< HEAD
The integration of such into the transaction schema of Planetmint is shown below.
## Zenroom Smart Contracts and Policies
@ -159,3 +160,6 @@ The integration of such into the transaction schema of Planetmint is shown below
At the moment these contracts can only be stateless, which implies that the conditions and fulfillments need to be transacted in the same transaction. However, [PRP-10](https://github.com/planetmint/PRPs/tree/main/10) aims to make stateful contracts possible, which enables asynchronous and party-independent processing of contracts.
As for network-wide or asset-based policies [PRP-11](https://github.com/planetmint/PRPs/tree/main/11) specifies how these can be implemented and how these can be used to verify a transaction state before it is commited to the network.
=======
The integration of such into the transaction schema of Planetmint is shown below.
>>>>>>> planetmint-tarantool

View File

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

View File

@ -6,23 +6,19 @@ Content-Type: application/json
"transactions": [
{
"asset": {
"data": {
"msg": "Hello Planetmint!"
}
"data": "QmQP5C3PmhH9oB84n7YqSY4WVqmYatdoo1BdwhH4zmcwqM"
},
"id": "6438c733f53dff60bdeded80e8c95126dd3a7ce8c1ee5d5591d030e61cde35d2",
"id": "e4ebc02324e10925226bf2143363c1a28481ee38f70a9245a5a76df5f4380a7a",
"inputs": [
{
"fulfillment": "pGSAIDE5i63cn4X8T8N1sZ2mGkJD5lNRnBM4PZgI_zvzbr-cgUBcdRj6EnG3MPl47m3XPd1HNfe7q3WL4T6MewNNnat33UvzVnPHo_vossv57M7L064VwrYMLGp097H7IeHpDngK",
"fulfillment": "pGSAIDE5i63cn4X8T8N1sZ2mGkJD5lNRnBM4PZgI_zvzbr-cgUDVDqtaQTYon0UJ-k2YEGfKfDWAwz9BnfBPkKvSHAgfU5O-1S8eY4mNjHAQConK47tnE7ksezmOrLL0_DR1Mm0P",
"fulfills": null,
"owners_before": [
"4K9sWUMFwTgaDGPfdynrbxWqWS6sWmKbZoTjxLtVUibD"
]
}
],
"metadata": {
"sequence": 0
},
"metadata": "QmZs4UHLHCUGLQr6rzbtJTjT8Sf5pw6FNuaRZ5pzguk5FV",
"operation": "CREATE",
"outputs": [
{

View File

@ -1,3 +1,3 @@
GET /api/v1/blocks?transaction_id=6438c733f53dff60bdeded80e8c95126dd3a7ce8c1ee5d5591d030e61cde35d2 HTTP/1.1
GET /api/v1/blocks?transaction_id=e4ebc02324e10925226bf2143363c1a28481ee38f70a9245a5a76df5f4380a7a HTTP/1.1
Host: example.com

View File

@ -1,3 +1,3 @@
GET /api/v1/transactions?operation=TRANSFER&asset_id=6438c733f53dff60bdeded80e8c95126dd3a7ce8c1ee5d5591d030e61cde35d2 HTTP/1.1
GET /api/v1/transactions?operation=TRANSFER&asset_id=e4ebc02324e10925226bf2143363c1a28481ee38f70a9245a5a76df5f4380a7a HTTP/1.1
Host: example.com

View File

@ -3,24 +3,22 @@ Content-Type: application/json
[{
"asset": {
"id": "6438c733f53dff60bdeded80e8c95126dd3a7ce8c1ee5d5591d030e61cde35d2"
"id": "e4ebc02324e10925226bf2143363c1a28481ee38f70a9245a5a76df5f4380a7a"
},
"id": "2bf8ae1e3bc889a26df129dd6bbe6ccab30d1ae8e9e434fae1c4446042a68931",
"id": "b3f39407b3907587de26bedec93cd6b2c6958bca90f77349f1db9780f014bc1f",
"inputs": [
{
"fulfillment": "pGSAIDE5i63cn4X8T8N1sZ2mGkJD5lNRnBM4PZgI_zvzbr-cgUA90mMa9AWnbI70CUSVgzV9kRFf3tQ20RUIczNFqmwg9xrpOk_5uNoJB4bWRIojZmUhEyxSueCHLpqPXCEuyisE",
"fulfillment": "pGSAIDE5i63cn4X8T8N1sZ2mGkJD5lNRnBM4PZgI_zvzbr-cgUCtt9Thk_enrynxclNFj8B76QvIFbvhyj_38wuy1vA-lncUb2Q7bwJvnmmufeXucyEBTZQ0xoI5dfjG3KeTsLkH",
"fulfills": {
"output_index": 0,
"transaction_id": "6438c733f53dff60bdeded80e8c95126dd3a7ce8c1ee5d5591d030e61cde35d2"
"transaction_id": "e4ebc02324e10925226bf2143363c1a28481ee38f70a9245a5a76df5f4380a7a"
},
"owners_before": [
"4K9sWUMFwTgaDGPfdynrbxWqWS6sWmKbZoTjxLtVUibD"
]
}
],
"metadata": {
"sequence": 1
},
"metadata": "QmQ9Sc3VWZ3nH5FWVVi2MNMDhyjTiKrEb6mN79qqt1Uq9s",
"operation": "TRANSFER",
"outputs": [
{
@ -41,24 +39,22 @@ Content-Type: application/json
},
{
"asset": {
"id": "6438c733f53dff60bdeded80e8c95126dd3a7ce8c1ee5d5591d030e61cde35d2"
"id": "e4ebc02324e10925226bf2143363c1a28481ee38f70a9245a5a76df5f4380a7a"
},
"id": "b9b614175eaed7cc93d9b80ebc2a91d35ae31928a7c218ae982272bb1785ef16",
"id": "95d99c245cd83af10f3c8ba6c32eda7cb668698b5aaaeec67be3faf915bb6b5d",
"inputs": [
{
"fulfillment": "pGSAICw7Ul-c2lG6NFbHp3FbKRC7fivQcNGO7GS4wV3A-1QggUDi2bAVKJgEyE3LzMrAnAu1PnNs9DbDNkABaY6j3OCNEVwNVNg3V3qELOFNnH8vGUevREr4E-8Vb1Kzk4VR71MO",
"fulfillment": "pGSAICw7Ul-c2lG6NFbHp3FbKRC7fivQcNGO7GS4wV3A-1QggUA2Z5Iw7YlMO0K9H_qcfGyepj6rqODxUZSysK_QS_tiZSlSdkXzCSLRCDO07EsyeBKEUUXpWHoBUv1lqJhFtjUK",
"fulfills": {
"output_index": 0,
"transaction_id": "2bf8ae1e3bc889a26df129dd6bbe6ccab30d1ae8e9e434fae1c4446042a68931"
"transaction_id": "b3f39407b3907587de26bedec93cd6b2c6958bca90f77349f1db9780f014bc1f"
},
"owners_before": [
"3yfQPHeWAa1MxTX9Zf9176QqcpcnWcanVZZbaHb8B3h9"
]
}
],
"metadata": {
"sequence": 2
},
"metadata": "QmRRg9RGq3TmV6nj2SXJacPuTdwaFDGTPACJLdN368pN3t",
"operation": "TRANSFER",
"outputs": [
{

View File

@ -1,3 +1,3 @@
GET /api/v1/transactions/6438c733f53dff60bdeded80e8c95126dd3a7ce8c1ee5d5591d030e61cde35d2 HTTP/1.1
GET /api/v1/transactions/e4ebc02324e10925226bf2143363c1a28481ee38f70a9245a5a76df5f4380a7a HTTP/1.1
Host: example.com

View File

@ -3,23 +3,19 @@ Content-Type: application/json
{
"asset": {
"data": {
"msg": "Hello Planetmint!"
}
"data": "QmQP5C3PmhH9oB84n7YqSY4WVqmYatdoo1BdwhH4zmcwqM"
},
"id": "6438c733f53dff60bdeded80e8c95126dd3a7ce8c1ee5d5591d030e61cde35d2",
"id": "e4ebc02324e10925226bf2143363c1a28481ee38f70a9245a5a76df5f4380a7a",
"inputs": [
{
"fulfillment": "pGSAIDE5i63cn4X8T8N1sZ2mGkJD5lNRnBM4PZgI_zvzbr-cgUBcdRj6EnG3MPl47m3XPd1HNfe7q3WL4T6MewNNnat33UvzVnPHo_vossv57M7L064VwrYMLGp097H7IeHpDngK",
"fulfillment": "pGSAIDE5i63cn4X8T8N1sZ2mGkJD5lNRnBM4PZgI_zvzbr-cgUDVDqtaQTYon0UJ-k2YEGfKfDWAwz9BnfBPkKvSHAgfU5O-1S8eY4mNjHAQConK47tnE7ksezmOrLL0_DR1Mm0P",
"fulfills": null,
"owners_before": [
"4K9sWUMFwTgaDGPfdynrbxWqWS6sWmKbZoTjxLtVUibD"
]
}
],
"metadata": {
"sequence": 0
},
"metadata": "QmZs4UHLHCUGLQr6rzbtJTjT8Sf5pw6FNuaRZ5pzguk5FV",
"operation": "CREATE",
"outputs": [
{

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.0.1/http-client-server-api.html",
"docs": "https://docs.planetmint.io/projects/server/en/v1.2.2/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.0.1/",
"docs": "https://docs.planetmint.io/projects/server/en/v1.2.2/",
"software": "Planetmint",
"version": "1.0.1"
"version": "1.2.2"
}

View File

@ -4,23 +4,19 @@ Content-Type: application/json
{
"asset": {
"data": {
"msg": "Hello Planetmint!"
}
"data": "QmQP5C3PmhH9oB84n7YqSY4WVqmYatdoo1BdwhH4zmcwqM"
},
"id": "6438c733f53dff60bdeded80e8c95126dd3a7ce8c1ee5d5591d030e61cde35d2",
"id": "e4ebc02324e10925226bf2143363c1a28481ee38f70a9245a5a76df5f4380a7a",
"inputs": [
{
"fulfillment": "pGSAIDE5i63cn4X8T8N1sZ2mGkJD5lNRnBM4PZgI_zvzbr-cgUBcdRj6EnG3MPl47m3XPd1HNfe7q3WL4T6MewNNnat33UvzVnPHo_vossv57M7L064VwrYMLGp097H7IeHpDngK",
"fulfillment": "pGSAIDE5i63cn4X8T8N1sZ2mGkJD5lNRnBM4PZgI_zvzbr-cgUDVDqtaQTYon0UJ-k2YEGfKfDWAwz9BnfBPkKvSHAgfU5O-1S8eY4mNjHAQConK47tnE7ksezmOrLL0_DR1Mm0P",
"fulfills": null,
"owners_before": [
"4K9sWUMFwTgaDGPfdynrbxWqWS6sWmKbZoTjxLtVUibD"
]
}
],
"metadata": {
"sequence": 0
},
"metadata": "QmZs4UHLHCUGLQr6rzbtJTjT8Sf5pw6FNuaRZ5pzguk5FV",
"operation": "CREATE",
"outputs": [
{

View File

@ -3,23 +3,19 @@ Content-Type: application/json
{
"asset": {
"data": {
"msg": "Hello Planetmint!"
}
"data": "QmQP5C3PmhH9oB84n7YqSY4WVqmYatdoo1BdwhH4zmcwqM"
},
"id": "6438c733f53dff60bdeded80e8c95126dd3a7ce8c1ee5d5591d030e61cde35d2",
"id": "e4ebc02324e10925226bf2143363c1a28481ee38f70a9245a5a76df5f4380a7a",
"inputs": [
{
"fulfillment": "pGSAIDE5i63cn4X8T8N1sZ2mGkJD5lNRnBM4PZgI_zvzbr-cgUBcdRj6EnG3MPl47m3XPd1HNfe7q3WL4T6MewNNnat33UvzVnPHo_vossv57M7L064VwrYMLGp097H7IeHpDngK",
"fulfillment": "pGSAIDE5i63cn4X8T8N1sZ2mGkJD5lNRnBM4PZgI_zvzbr-cgUDVDqtaQTYon0UJ-k2YEGfKfDWAwz9BnfBPkKvSHAgfU5O-1S8eY4mNjHAQConK47tnE7ksezmOrLL0_DR1Mm0P",
"fulfills": null,
"owners_before": [
"4K9sWUMFwTgaDGPfdynrbxWqWS6sWmKbZoTjxLtVUibD"
]
}
],
"metadata": {
"sequence": 0
},
"metadata": "QmZs4UHLHCUGLQr6rzbtJTjT8Sf5pw6FNuaRZ5pzguk5FV",
"operation": "CREATE",
"outputs": [
{

View File

@ -43,7 +43,11 @@ $ python notarize.py
# Install Planetmint
## Local Node
Planemtint is a Tendermint applicatoin with an attached database.
<<<<<<< HEAD
A basic installation installs the database, Tendermint and therafter Planetmint.
=======
A basic installation installs the database, Tenermint and therafter Planetmint.
>>>>>>> planetmint-tarantool
Planetmint currently supports Tarantool and MongoDB database. The installation is as follows:
```

View File

@ -3,7 +3,6 @@ import base58
from hashlib import sha3_256
from cryptoconditions.types.zenroom import ZenroomSha256
from planetmint_driver.crypto import generate_keypair
from .helper.hosts import Hosts
from zenroom import zencode_exec
import time
@ -72,7 +71,7 @@ def test_zenroom_signing(
"output": ["ok"],
"policies": {},
}
metadata = {"result": {"output": ["ok"]}}
token_creation_tx = {
"operation": "CREATE",
"asset": {"data": {"test": "my asset"}},

View File

@ -13,4 +13,4 @@ configuration or the ``PLANETMINT_DATABASE_BACKEND`` environment variable.
# Include the backend interfaces
from planetmint.backend import schema, query, convert # noqa
from planetmint.backend.connection import connect, Connection
from planetmint.backend.connection import Connection

View File

@ -20,93 +20,43 @@ BACKENDS = {
logger = logging.getLogger(__name__)
def connect(
host: str = None, port: int = None, login: str = None, password: str = None, backend: str = None, **kwargs
):
try:
backend = backend
if not backend and kwargs and kwargs.get("backend"):
backend = kwargs["backend"]
if backend and backend != Config().get()["database"]["backend"]:
Config().init_config(backend)
else:
backend = Config().get()["database"]["backend"]
except KeyError:
logger.info("Backend {} not supported".format(backend))
raise ConfigurationError
host = host or Config().get()["database"]["host"] if not kwargs.get("host") else kwargs["host"]
port = port or Config().get()["database"]["port"] if not kwargs.get("port") else kwargs["port"]
login = login or Config().get()["database"]["login"] if not kwargs.get("login") else kwargs["login"]
password = password or Config().get()["database"]["password"]
try:
if backend == "tarantool_db":
modulepath, _, class_name = BACKENDS[backend].rpartition(".")
Class = getattr(import_module(modulepath), class_name)
return Class(host=host, port=port, user=login, password=password, kwargs=kwargs)
elif backend == "localmongodb":
modulepath, _, class_name = BACKENDS[backend].rpartition(".")
Class = getattr(import_module(modulepath), class_name)
dbname = _kwargs_parser(key="name", kwargs=kwargs) or Config().get()["database"]["name"]
replicaset = _kwargs_parser(key="replicaset", kwargs=kwargs) or Config().get()["database"]["replicaset"]
ssl = _kwargs_parser(key="ssl", kwargs=kwargs) or Config().get()["database"]["ssl"]
login = (
login or Config().get()["database"]["login"]
if _kwargs_parser(key="login", kwargs=kwargs) is None
else _kwargs_parser(key="login", kwargs=kwargs) # noqa: E501
)
password = (
password or Config().get()["database"]["password"]
if _kwargs_parser(key="password", kwargs=kwargs) is None
else _kwargs_parser(key="password", kwargs=kwargs) # noqa: E501
)
ca_cert = _kwargs_parser(key="ca_cert", kwargs=kwargs) or Config().get()["database"]["ca_cert"]
certfile = _kwargs_parser(key="certfile", kwargs=kwargs) or Config().get()["database"]["certfile"]
keyfile = _kwargs_parser(key="keyfile", kwargs=kwargs) or Config().get()["database"]["keyfile"]
keyfile_passphrase = (
_kwargs_parser(key="keyfile_passphrase", kwargs=kwargs)
or Config().get()["database"]["keyfile_passphrase"]
)
crlfile = _kwargs_parser(key="crlfile", kwargs=kwargs) or Config().get()["database"]["crlfile"]
max_tries = _kwargs_parser(key="max_tries", kwargs=kwargs)
connection_timeout = _kwargs_parser(key="connection_timeout", kwargs=kwargs)
return Class(
host=host,
port=port,
dbname=dbname,
max_tries=max_tries,
connection_timeout=connection_timeout,
replicaset=replicaset,
ssl=ssl,
login=login,
password=password,
ca_cert=ca_cert,
certfile=certfile,
keyfile=keyfile,
keyfile_passphrase=keyfile_passphrase,
crlfile=crlfile,
)
except tarantool.error.NetworkError as network_err:
print(f"Host {host}:{port} can't be reached.\n{network_err}")
raise network_err
def _kwargs_parser(key, kwargs):
if kwargs.get(key):
return kwargs[key]
return None
class DBSingleton(type):
_instances = {}
class Connection:
def __call__(cls, *args, **kwargs):
if cls not in cls._instances:
try:
backend = kwargs.get("backend") if kwargs and kwargs.get("backend") else None
if backend is not None and backend != Config().get()["database"]["backend"]:
Config().init_config(backend)
else:
backend = Config().get()["database"]["backend"]
except KeyError:
logger.info("Backend {} not supported".format(backend))
raise ConfigurationError
modulepath, _, class_name = BACKENDS[backend].rpartition('.')
Class = getattr(import_module(modulepath), class_name)
cls._instances[cls] = super(DBSingleton, Class).__call__(*args, **kwargs)
return cls._instances[cls]
class Connection(metaclass=DBSingleton):
def __init__(self) -> None:
pass
class DBConnection(metaclass=DBSingleton):
"""Connection class interface.
All backend implementations should provide a connection class that inherits
from and implements this class.
"""
def __init__(self, host=None, port=None, dbname=None, connection_timeout=None, max_tries=None, **kwargs):
def __init__(self, host: str =None, port: int = None, login: str = None, password: str = None, backend: str = None,
connection_timeout: int = None, max_tries: int = None, **kwargs):
"""Create a new :class:`~.Connection` instance.
Args:
host (str): the host to connect to.
@ -120,24 +70,16 @@ class Connection:
**kwargs: arbitrary keyword arguments provided by the
configuration's ``database`` settings
"""
dbconf = Config().get()['database']
dbconf = Config().get()["database"]
self.host = host or dbconf["host"] if not kwargs.get("host") else kwargs["host"]
self.port = port or dbconf['port'] if not kwargs.get("port") else kwargs["port"]
self.login = login or dbconf['login'] if not kwargs.get("login") else kwargs["login"]
self.password = password or dbconf['password'] if not kwargs.get("password") else kwargs["password"]
self.host = host or dbconf["host"]
self.port = port or dbconf["port"]
self.dbname = dbname or dbconf["name"]
self.connection_timeout = (
connection_timeout if connection_timeout is not None else dbconf["connection_timeout"]
)
self.max_tries = max_tries if max_tries is not None else dbconf["max_tries"]
self.connection_timeout = connection_timeout if connection_timeout is not None else Config().get()["database"]
self.max_tries = max_tries if max_tries is not None else dbconf['max_tries']
self.max_tries_counter = range(self.max_tries) if self.max_tries != 0 else repeat(0)
self._conn = None
@property
def conn(self):
if self._conn is None:
self.connect()
return self._conn
def run(self, query):
"""Run a query.
@ -160,23 +102,12 @@ class Connection:
:exc:`~ConnectionError`: If the connection to the database
fails.
"""
raise NotImplementedError()
attempt = 0
for i in self.max_tries_counter:
attempt += 1
try:
self._conn = self._connect()
except ConnectionError as exc:
logger.warning(
"Attempt %s/%s. Connection to %s:%s failed after %sms.",
attempt,
self.max_tries if self.max_tries != 0 else "",
self.host,
self.port,
self.connection_timeout,
)
if attempt == self.max_tries:
logger.critical("Cannot connect to the Database. Giving up.")
raise ConnectionError() from exc
else:
break
def close(self):
"""Try to close connection to the database.
Raises:
:exc:`~ConnectionError`: If the connection to the database
fails.
"""
raise NotImplementedError()

View File

@ -8,28 +8,18 @@ from ssl import CERT_REQUIRED
import pymongo
from planetmint.config import Config
from planetmint.backend.exceptions import DuplicateKeyError, OperationError, ConnectionError
from planetmint.backend.exceptions import (DuplicateKeyError,
OperationError,
ConnectionError)
from planetmint.transactions.common.exceptions import ConfigurationError
from planetmint.utils import Lazy
from planetmint.backend.connection import Connection
from planetmint.backend.connection import DBConnection, _kwargs_parser
logger = logging.getLogger(__name__)
class LocalMongoDBConnection(DBConnection):
class LocalMongoDBConnection(Connection):
def __init__(
self,
replicaset=None,
ssl=None,
login=None,
password=None,
ca_cert=None,
certfile=None,
keyfile=None,
keyfile_passphrase=None,
crlfile=None,
**kwargs,
):
def __init__(self, host: str =None, port: int = None, login: str = None, password: str = None, **kwargs):
"""Create a new Connection instance.
Args:
@ -39,16 +29,24 @@ class LocalMongoDBConnection(Connection):
configuration's ``database`` settings
"""
super().__init__(**kwargs)
self.replicaset = replicaset or Config().get()["database"]["replicaset"]
self.ssl = ssl if ssl is not None else Config().get()["database"]["ssl"]
self.login = login or Config().get()["database"]["login"]
self.password = password or Config().get()["database"]["password"]
self.ca_cert = ca_cert or Config().get()["database"]["ca_cert"]
self.certfile = certfile or Config().get()["database"]["certfile"]
self.keyfile = keyfile or Config().get()["database"]["keyfile"]
self.keyfile_passphrase = keyfile_passphrase or Config().get()["database"]["keyfile_passphrase"]
self.crlfile = crlfile or Config().get()["database"]["crlfile"]
super().__init__(host=host, port=port, login=login, password=password, **kwargs)
dbconf = Config().get()['database']
self.dbname = _kwargs_parser(key="name", kwargs=kwargs) or dbconf['name']
self.replicaset = _kwargs_parser(key="replicaset", kwargs=kwargs) or dbconf['replicaset']
self.ssl = _kwargs_parser(key="ssl", kwargs=kwargs) or dbconf['ssl']
self.ca_cert = _kwargs_parser(key="ca_cert", kwargs=kwargs) or dbconf['ca_cert']
self.certfile = _kwargs_parser(key="certfile", kwargs=kwargs) or dbconf['certfile']
self.keyfile = _kwargs_parser(key="keyfile", kwargs=kwargs) or dbconf['keyfile']
self.keyfile_passphrase = _kwargs_parser(key="keyfile_passphrase", kwargs=kwargs) or dbconf[
'keyfile_passphrase']
self.crlfile = _kwargs_parser(key="crlfile", kwargs=kwargs) or dbconf['crlfile']
self.max_tries = _kwargs_parser(key="max_tries", kwargs=kwargs)
self.connection_timeout = _kwargs_parser(key="connection_timeout", kwargs=kwargs)
self.__conn = None
self.connect()
if not self.ssl:
self.ssl = False
if not self.keyfile_passphrase:
@ -56,7 +54,7 @@ class LocalMongoDBConnection(Connection):
@property
def db(self):
return self.conn[self.dbname]
return self.connect()[self.dbname]
def query(self):
return Lazy()
@ -72,10 +70,11 @@ class LocalMongoDBConnection(Connection):
def run(self, query):
try:
try:
return query.run(self.conn)
return query.run(self.connect())
except pymongo.errors.AutoReconnect:
logger.warning("Lost connection to the database, " "retrying query.")
return query.run(self.conn)
logger.warning('Lost connection to the database, '
'retrying query.')
return query.run(self.connect())
except pymongo.errors.AutoReconnect as exc:
raise ConnectionError from exc
except pymongo.errors.DuplicateKeyError as exc:
@ -84,7 +83,7 @@ class LocalMongoDBConnection(Connection):
print(f"DETAILS: {exc.details}")
raise OperationError from exc
def _connect(self):
def connect(self):
"""Try to connect to the database.
Raises:
@ -95,7 +94,8 @@ class LocalMongoDBConnection(Connection):
:exc:`~ConfigurationError`: If there is a ConfigurationError while
connecting to the database.
"""
if self.__conn:
return self._conn
try:
# FYI: the connection process might raise a
# `ServerSelectionTimeoutError`, that is a subclass of
@ -130,16 +130,25 @@ class LocalMongoDBConnection(Connection):
**MONGO_OPTS,
)
if self.login is not None:
client[self.dbname].authenticate(self.login, mechanism="MONGODB-X509")
client[self.dbname].authenticate(self.login,
mechanism='MONGODB-X509')
self.__conn = client
return client
except (pymongo.errors.ConnectionFailure, pymongo.errors.OperationFailure) as exc:
logger.info("Exception in _connect(): {}".format(exc))
except (pymongo.errors.ConnectionFailure,
pymongo.errors.OperationFailure) as exc:
logger.info('Exception in connect(): {}'.format(exc))
raise ConnectionError(str(exc)) from exc
except pymongo.errors.ConfigurationError as exc:
raise ConfigurationError from exc
def close(self):
try:
self.__conn.close()
self.__conn = None
except Exception as exc:
logger.info('Exception in planetmint.backend.localmongodb.close(): {}'.format(exc))
raise ConnectionError(str(exc)) from exc
MONGO_OPTS = {
"socketTimeoutMS": 20000,

View File

@ -14,7 +14,7 @@ register_query = module_dispatch_registrar(convert)
@register_query(LocalMongoDBConnection)
def prepare_asset(connection, transaction_type, transaction_id, filter_operation, asset):
if transaction_type in filter_operation:
if transaction_type not in filter_operation:
asset["id"] = transaction_id
return asset

View File

@ -1,5 +1,4 @@
from functools import singledispatch
# Copyright © 2020 Interplanetary Database Association e.V.,
# Planetmint and IPDB software contributors.
# SPDX-License-Identifier: (Apache-2.0 AND CC-BY-4.0)

View File

@ -9,7 +9,7 @@ from functools import singledispatch
import logging
from planetmint.config import Config
from planetmint.backend.connection import connect
from planetmint.backend.connection import Connection
from planetmint.transactions.common.exceptions import ValidationError
from planetmint.transactions.common.utils import (
validate_all_values_for_key_in_obj,
@ -134,8 +134,9 @@ def init_database(connection=None, dbname=None):
configuration.
"""
connection = connection or connect()
dbname = dbname or Config().get()["database"]["name"]
connection = connection or Connection()
print("=========================================", connection.__class__, "=========================================================")
dbname = dbname or Config().get()['database']['name']
create_database(connection, dbname)
create_tables(connection, dbname)

View File

@ -7,29 +7,30 @@ import logging
import tarantool
from planetmint.config import Config
from planetmint.transactions.common.exceptions import ConfigurationError
from planetmint.transactions.common.exceptions import ConfigurationError, ConnectionError
from planetmint.utils import Lazy
from planetmint.backend.connection import Connection
from planetmint.backend.connection import DBConnection
logger = logging.getLogger(__name__)
class TarantoolDBConnection(Connection):
class TarantoolDBConnection(DBConnection):
def __init__(
self,
host: str = "localhost",
port: int = 3303,
user: str = None,
login: str = None,
password: str = None,
**kwargs,
):
try:
super().__init__(**kwargs)
self.host = host
self.port = port
# TODO add user support later on
self.init_path = Config().get()["database"]["init_config"]["absolute_path"]
self.drop_path = Config().get()["database"]["drop_config"]["absolute_path"]
super().__init__(host=host, port=port, login=login, password=password, **kwargs)
dbconf = Config().get()["database"]
self.init_path = dbconf["init_config"]["absolute_path"]
self.drop_path = dbconf["drop_config"]["absolute_path"]
self.__conn = None
self.connect()
self.SPACE_NAMES = [
"abci_chains",
"assets",
@ -46,7 +47,7 @@ class TarantoolDBConnection(Connection):
]
except tarantool.error.NetworkError as network_err:
logger.info("Host cant be reached")
raise network_err
raise ConnectionError
except ConfigurationError:
logger.info("Exception in _connect(): {}")
raise ConfigurationError
@ -60,27 +61,40 @@ class TarantoolDBConnection(Connection):
f.close()
return "".join(execute).encode()
def _connect(self):
return tarantool.connect(host=self.host, port=self.port)
def connect(self):
if not self.__conn:
self.__conn = tarantool.connect(host=self.host, port=self.port)
return self.__conn
def close(self):
try:
self.__conn.close()
self.__conn = None
except Exception as exc:
logger.info('Exception in planetmint.backend.tarantool.close(): {}'.format(exc))
raise ConnectionError(str(exc)) from exc
def get_space(self, space_name: str):
return self.conn.space(space_name)
return self.get_connection().space(space_name)
def space(self, space_name: str):
return self.query().space(space_name)
def run(self, query, only_data=True):
try:
return query.run(self.conn).data if only_data else query.run(self.conn)
return query.run(self.get_connection()).data if only_data else query.run(self.get_connection())
except tarantool.error.OperationalError as op_error:
raise op_error
except tarantool.error.NetworkError as net_error:
raise net_error
def get_connection(self):
return self.conn
if not self.__conn:
self.connect()
return self.__conn
def drop_database(self):
self.close()
db_config = Config().get()["database"]
cmd_resp = self.run_command(command=self.drop_path, config=db_config) # noqa: F841

View File

@ -16,7 +16,7 @@ register_query = module_dispatch_registrar(convert)
def prepare_asset(connection, transaction_type, transaction_id, filter_operation, asset):
asset_id = transaction_id
if transaction_type not in filter_operation:
asset_id = asset["id"]
asset_id = asset['id']
return tuple([asset, transaction_id, asset_id])

View File

@ -256,9 +256,9 @@ def run_drop(args):
if response != "y":
return
from planetmint.backend.connection import connect
from planetmint.backend.connection import Connection
conn = connect()
conn = Connection()
try:
schema.drop_database(conn)
except DatabaseDoesNotExist:

View File

@ -1,7 +1,6 @@
import copy
import logging
import os
# from planetmint.log import DEFAULT_LOGGING_CONFIG as log_config
from planetmint.version import __version__ # noqa

View File

@ -10,6 +10,7 @@ MongoDB.
import logging
from collections import namedtuple
from uuid import uuid4
from planetmint.backend.connection import Connection
import rapidjson
@ -73,7 +74,7 @@ class Planetmint(object):
self.validation = config_utils.load_validation_plugin(validationPlugin)
else:
self.validation = BaseValidationRules
self.connection = connection if connection is not None else planetmint.backend.connect()
self.connection = connection if connection is not None else Connection()
def post_transaction(self, transaction, mode):
"""Submit a valid transaction to the mempool."""

View File

@ -11,7 +11,6 @@ from logging.config import dictConfig as set_logging_config
from planetmint.config import Config, DEFAULT_LOGGING_CONFIG
import os
def _normalize_log_level(level):
try:
return level.upper()

View File

@ -11,6 +11,9 @@ from planetmint.exceptions import BigchainDBError
class ConfigurationError(BigchainDBError):
"""Raised when there is a problem with server configuration"""
class ConnectionError(BigchainDBError):
"""Raised when there is a problem with server connection"""
class DatabaseDoesNotExist(BigchainDBError):
"""Raised when trying to delete the database but the db is not there"""

View File

@ -904,8 +904,12 @@ class Transaction(object):
if asset_id != self.asset["id"]:
raise AssetIdMismatch(("The asset id of the input does not" " match the asset id of the" " transaction"))
input_amount = sum([input_condition.amount for input_condition in input_conditions])
output_amount = sum([output_condition.amount for output_condition in self.outputs])
input_amount = sum(
[input_condition.amount for input_condition in input_conditions]
)
output_amount = sum(
[output_condition.amount for output_condition in self.outputs]
)
if output_amount != input_amount:
raise AmountError(

View File

@ -3,7 +3,7 @@
# 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.2.1"
__version__ = "1.2.2"
__short_version__ = "1.2"
# Supported Tendermint versions

View File

@ -89,7 +89,15 @@ docs_require = [
check_setuptools_features()
dev_require = ["ipdb", "ipython", "watchdog", "logging_tree", "pre-commit", "twine", "ptvsd"]
dev_require = [
"ipdb",
"ipython",
"watchdog",
"logging_tree",
"pre-commit",
"twine",
"ptvsd"
]
tests_require = [
"coverage",

View File

@ -1,5 +1,5 @@
import pytest
from planetmint.backend.connection import connect
from planetmint.backend.connection import Connection
#
@ -27,5 +27,5 @@ from planetmint.backend.connection import connect
@pytest.fixture
def db_conn():
conn = connect()
conn = Connection()
return conn

View File

@ -16,7 +16,6 @@ pytestmark = pytest.mark.bdb
def test_get_txids_filtered(signed_create_tx, signed_transfer_tx, db_conn):
from planetmint.backend.tarantool import query
# create and insert two blocks, one for the create and one for the
# transfer transaction
create_tx_dict = signed_create_tx.to_dict()

View File

@ -7,16 +7,12 @@ import pytest
def test_get_connection_raises_a_configuration_error(monkeypatch):
from planetmint.transactions.common.exceptions import ConfigurationError
from planetmint.backend.connection import connect
from planetmint.transactions.common.exceptions import ConfigurationError, ConnectionError
from planetmint.backend.connection import Connection
from planetmint.backend.localmongodb.connection import LocalMongoDBConnection
from planetmint.backend.tarantool.connection import TarantoolDBConnection
with pytest.raises(ConfigurationError):
connect("localhost", "1337", "mydb", "password", "msaccess")
with pytest.raises(ConfigurationError):
# We need to force a misconfiguration here
monkeypatch.setattr(
"planetmint.backend.connection.BACKENDS", {"catsandra": "planetmint.backend.meowmeow.Catsandra"}
)
connect("localhost", "1337", "mydb", "password", "catsandra")
with pytest.raises(ConnectionError):
LocalMongoDBConnection('localhost', '1337', 'mydb', 'password')
with pytest.raises(ConnectionError):
TarantoolDBConnection('localhost', '1337', 'mydb', 'password')

View File

@ -8,7 +8,6 @@ import pytest
from planetmint.config import Config
@pytest.fixture
def mock_run_configure(monkeypatch):
from planetmint.commands import planetmint

View File

@ -14,13 +14,13 @@ import pytest
from planetmint.config import Config
from planetmint import ValidatorElection
from planetmint.commands.planetmint import run_election_show
from planetmint.backend.connection import Connection
from planetmint.transactions.types.elections.election import Election
from planetmint.lib import Block
from planetmint.transactions.types.elections.chain_migration_election import ChainMigrationElection
from tests.utils import generate_election, generate_validators
def test_make_sure_we_dont_remove_any_command():
# thanks to: http://stackoverflow.com/a/18161115/597097
from planetmint.commands.planetmint import create_parser
@ -95,7 +95,6 @@ def test_bigchain_show_config(capsys):
# dict returned is different that what is expected after run_show_config
# and run_show_config updates the planetmint.config
from planetmint.config import Config
_config = Config().get()
sorted_config = json.dumps(_config, indent=4, sort_keys=True)
print(f"_config : {sorted_config}")
@ -104,11 +103,10 @@ def test_bigchain_show_config(capsys):
def test__run_init(mocker):
init_db_mock = mocker.patch("planetmint.backend.tarantool.connection.TarantoolDBConnection.init_database")
init_db_mock = mocker.patch(
'planetmint.backend.tarantool.connection.TarantoolDBConnection.init_database')
from planetmint.backend.connection import connect
conn = connect()
conn = Connection()
conn.init_database()
init_db_mock.assert_called_once_with()

View File

@ -19,11 +19,10 @@ from ipld import marshal, multihash
from collections import namedtuple
from logging import getLogger
from logging.config import dictConfig
from planetmint.backend.connection import connect
from planetmint.backend.connection import Connection
from planetmint.backend.tarantool.connection import TarantoolDBConnection
import pytest
# from pymongo import MongoClient
from planetmint import ValidatorElection
@ -118,22 +117,22 @@ def _configure_planetmint(request):
config_utils.set_config(config)
@pytest.fixture(scope="session")
@pytest.fixture(scope='session')
def _setup_database(_configure_planetmint): # TODO Here is located setup database
from planetmint.config import Config
print("Initializing test db")
dbname = Config().get()["database"]["name"]
conn = connect()
print('Initializing test db')
dbname = Config().get()['database']['name']
conn = Connection()
_drop_db(conn, dbname)
schema.init_database(conn, dbname)
print("Finishing init database")
print('Finishing init database')
yield
print("Deleting `{}` database".format(dbname))
conn = connect()
print('Deleting `{}` database'.format(dbname))
conn = Connection()
_drop_db(conn, dbname)
print("Finished deleting `{}`".format(dbname))
@ -145,10 +144,9 @@ def _bdb(_setup_database, _configure_planetmint):
from planetmint.transactions.common.transaction import Transaction
from .utils import flush_db
from planetmint.config import Config
conn = connect()
conn = Connection()
yield
dbname = Config().get()["database"]["name"]
dbname = Config().get()['database']['name']
flush_db(conn, dbname)
to_dict.cache_clear()
@ -252,7 +250,6 @@ def abci_fixture():
return types_pb2
@pytest.fixture
def b():
from planetmint import Planetmint
@ -393,7 +390,7 @@ def db_name(db_config):
@pytest.fixture
def db_conn():
return connect()
return Connection()
@pytest.fixture
@ -550,7 +547,6 @@ def tarantool_client(db_context): # TODO Here add TarantoolConnectionClass
#
#
@pytest.fixture
def utxo_collection(tarantool_client, _setup_database):
return tarantool_client.get_space("utxos")
@ -568,7 +564,6 @@ def dummy_unspent_outputs():
@pytest.fixture
def utxoset(dummy_unspent_outputs, utxo_collection):
from json import dumps
num_rows_before_operation = utxo_collection.select().rowcount
for utxo in dummy_unspent_outputs:
res = utxo_collection.insert((utxo["transaction_id"], utxo["output_index"], dumps(utxo)))
@ -624,7 +619,6 @@ def node_keys():
"PecJ58SaNRsWJZodDmqjpCWqG6btdwXFHLyE40RYlYM=": "uz8bYgoL4rHErWT1gjjrnA+W7bgD/uDQWSRKDmC8otc95wnnxJo1GxYlmh0OaqOkJaobpu13BcUcvITjRFiVgw==",
}
@pytest.fixture
def priv_validator_path(node_keys):
(public_key, private_key) = list(node_keys.items())[0]

View File

@ -91,7 +91,7 @@ def test_filter_unspent_outputs(b, user_pk, user_sk):
def test_outputs_query_key_order(b, user_pk, user_sk, user2_pk, user2_sk):
from planetmint import backend
from planetmint.backend.connection import connect
from planetmint.backend.connection import Connection
from planetmint.backend import query
tx1 = Create.generate([user_pk], [([user_pk], 3), ([user_pk], 2), ([user_pk], 1)]).sign([user_sk])
@ -116,7 +116,11 @@ def test_outputs_query_key_order(b, user_pk, user_sk, user2_pk, user2_sk):
assert len(outputs) == 1
# clean the transaction, metdata and asset collection
connection = connect()
# conn = connect()
connection = Connection()
# conn.run(conn.collection('transactions').delete_many({}))
# conn.run(conn.collection('metadata').delete_many({}))
# conn.run(conn.collection('assets').delete_many({}))
query.delete_transactions(connection, txn_ids=[tx1.id, tx2.id])
b.store_bulk_transactions([tx1])

View File

@ -290,7 +290,6 @@ def test_delete_zero_unspent_outputs(b, utxoset):
@pytest.mark.bdb
def test_delete_one_unspent_outputs(b, utxoset):
from planetmint.backend.tarantool.connection import TarantoolDBConnection
unspent_outputs, utxo_collection = utxoset
delete_res = b.delete_unspent_outputs(unspent_outputs[0])
if not isinstance(b.connection, TarantoolDBConnection):
@ -319,7 +318,6 @@ def test_delete_one_unspent_outputs(b, utxoset):
@pytest.mark.bdb
def test_delete_many_unspent_outputs(b, utxoset):
from planetmint.backend.tarantool.connection import TarantoolDBConnection
unspent_outputs, utxo_collection = utxoset
delete_res = b.delete_unspent_outputs(*unspent_outputs[::2])
if not isinstance(b.connection, TarantoolDBConnection):
@ -357,7 +355,6 @@ def test_store_zero_unspent_output(b, utxo_collection):
@pytest.mark.bdb
def test_store_one_unspent_output(b, unspent_output_1, utxo_collection):
from planetmint.backend.tarantool.connection import TarantoolDBConnection
res = b.store_unspent_outputs(unspent_output_1)
if not isinstance(b.connection, TarantoolDBConnection):
assert res.acknowledged
@ -382,7 +379,6 @@ def test_store_one_unspent_output(b, unspent_output_1, utxo_collection):
@pytest.mark.bdb
def test_store_many_unspent_outputs(b, unspent_outputs, utxo_collection):
from planetmint.backend.tarantool.connection import TarantoolDBConnection
res = b.store_unspent_outputs(*unspent_outputs)
if not isinstance(b.connection, TarantoolDBConnection):
assert res.acknowledged

View File

@ -18,6 +18,7 @@ from planetmint.transactions.types.elections.election import Election
from planetmint.lib import Block
from planetmint.transactions.types.elections.chain_migration_election import ChainMigrationElection
from planetmint.upsert_validator.validator_election import ValidatorElection
from planetmint.backend.exceptions import ConnectionError
from planetmint.upsert_validator.validator_utils import new_validator_set
from planetmint.tendermint_utils import public_key_to_base64
from planetmint.version import __tm_supported_versions__
@ -54,34 +55,25 @@ def config(request, monkeypatch):
monkeypatch.setattr("planetmint.config", config)
return config
def test_bigchain_class_initialization_with_parameters():
from planetmint.backend.localmongodb.connection import LocalMongoDBConnection
from planetmint.transactions.common.exceptions import ConfigurationError
init_db_kwargs = {
'backend': 'localmongodb',
'host': 'this_is_the_db_host',
'port': 12345,
'name': 'this_is_the_db_name',
}
with pytest.raises(ConfigurationError):
LocalMongoDBConnection(**init_db_kwargs)
def test_bigchain_class_default_initialization(config):
from planetmint import Planetmint
from planetmint.validation import BaseValidationRules
planet = Planetmint()
assert planet.connection.host == config["database"]["host"]
assert planet.connection.port == config["database"]["port"]
assert planet.validation == BaseValidationRules
def test_bigchain_class_initialization_with_parameters():
from planetmint import Planetmint
from planetmint.backend import connect
from planetmint.validation import BaseValidationRules
init_db_kwargs = {
"backend": "localmongodb",
"host": "this_is_the_db_host",
"port": 12345,
"name": "this_is_the_db_name",
}
connection = connect(**init_db_kwargs)
planet = Planetmint(connection=connection)
assert planet.connection == connection
assert planet.connection.host == init_db_kwargs["host"]
assert planet.connection.port == init_db_kwargs["port"]
# assert planet.connection.name == init_db_kwargs['name']
assert planet.connection.host == config['database']['host']
assert planet.connection.port == config['database']['port']
assert planet.validation == BaseValidationRules

View File

@ -348,7 +348,9 @@ def test_post_transfer_transaction_endpoint(client, user_pk, user_sk, posted_cre
@pytest.mark.abci
def test_post_invalid_transfer_transaction_returns_400(client, user_pk, posted_create_tx):
def test_post_invalid_transfer_transaction_returns_400(
client, user_pk, posted_create_tx
):
from planetmint.transactions.common.exceptions import InvalidSignature
transfer_tx = Transfer.generate(posted_create_tx.to_inputs(), [([user_pk], 1)], asset_id=posted_create_tx.id)