Skip to content
Snippets Groups Projects
Commit 433b9970 authored by Vincent Texier's avatar Vincent Texier
Browse files

add community repository

tests on repo
refactor meta sql in separate file
parent 0675182c
Branches
Tags
1 merge request!535add community repository
duniterpy>=0.20.dev0
git+https://github.com/Insoleet/quamash.git@master
asynctest
networkx
git+https://github.com/hynek/attrs.git@master
git+https://github.com/duniter/duniter-python-api.git@master
from .identity import Identity
from .community import Community
import attr
from duniterpy.documents import block_uid, BlockUID
@attr.s()
class Blockchain:
current_buid = attr.ib(convert=block_uid, default=BlockUID.empty())
nb_members = attr.ib(convert=int, default=0, cmp=False)
current_mass = attr.ib(convert=int, default=0, cmp=False)
median_time = attr.ib(convert=int, default=0, cmp=False)
last_ud = attr.ib(convert=int, default=0, cmp=False)
last_ud_base = attr.ib(convert=int, default=0, cmp=False)
previous_mass = attr.ib(convert=int, default=0, cmp=False)
currency = attr.ib(convert=str, default="", cmp=False)
import attr
@attr.s()
class Community:
# The decimal percent growth of the UD every [dt] period
c = attr.ib(convert=float, default=0, cmp=False)
# Time period between two UD in seconds
dt = attr.ib(convert=int, default=0, cmp=False)
# UD(0), i.e. initial Universal Dividend
ud0 = attr.ib(convert=int, default=0, cmp=False)
# Minimum delay between 2 certifications of a same issuer, in seconds. Must be positive or zero
sig_period = attr.ib(convert=int, default=0, cmp=False)
# Maximum quantity of active certifications made by member
sig_stock = attr.ib(convert=int, default=0, cmp=False)
# Maximum delay in seconds a certification can wait before being expired for non-writing
sig_window = attr.ib(convert=int, default=0, cmp=False)
# Maximum age of a active signature (in seconds)
sig_validity = attr.ib(convert=int, default=0, cmp=False)
# Minimum quantity of signatures to be part of the WoT
sig_qty = attr.ib(convert=int, default=0, cmp=False)
# Minimum decimal percent of sentries to reach to match the distance rule
xpercent = attr.ib(convert=float, default=0, cmp=False)
# Maximum age of an active membership( in seconds)
ms_validity = attr.ib(convert=int, default=0, cmp=False)
# Maximum distance between each WoT member and a newcomer
step_max = attr.ib(convert=int, default=0, cmp=False)
# Number of blocks used for calculating median time
median_time_blocks = attr.ib(convert=int, default=0, cmp=False)
# The average time for writing 1 block (wished time) in seconds
avg_gen_time = attr.ib(convert=int, default=0, cmp=False)
# The number of blocks required to evaluate again PoWMin value
dt_diff_eval = attr.ib(convert=int, default=0, cmp=False)
# The number of previous blocks to check for personalized difficulty
blocks_rot = attr.ib(convert=int, default=0, cmp=False)
# The decimal percent of previous issuers to reach for personalized difficulty
percent_rot = attr.ib(convert=float, default=0, cmp=False)
# Currency name
currency = attr.ib(convert=str, default="", cmp=False)
import attr
@attr.s
class CommunityProcessor:
_repo = attr.ib() # :type sakia.data.repositories.CommunitiesRepo
async def get_from_currency(self, currency):
"""
Get the community of a currency
:param currency:
:rtype: sakia.data.entities.Community
"""
return self._repo.get_one(currency=currency)
from .identities import IdentitiesRepo
from .communities import CommunitiesRepo
from .meta import MetaDatabase
import attr
from ..entities import Community
@attr.s(frozen=True)
class CommunitiesRepo:
"""The repository for Communities entities.
"""
_conn = attr.ib() # :type sqlite3.Connection
_primary_keys = (Community.currency,)
def insert(self, community):
"""
Commit a community to the database
:param sakia.data.entities.Community community: the community to commit
"""
with self._conn:
community_tuple = attr.astuple(community)
values = ",".join(['?'] * len(community_tuple))
self._conn.execute("INSERT INTO communities VALUES ({0})".format(values), community_tuple)
def update(self, community):
"""
Update an existing community in the database
:param sakia.data.entities.Community community: the community to update
"""
with self._conn:
updated_fields = attr.astuple(community, filter=attr.filters.exclude(*CommunitiesRepo._primary_keys))
where_fields = attr.astuple(community, filter=attr.filters.include(*CommunitiesRepo._primary_keys))
self._conn.execute("""UPDATE communities SET
c=?,
dt=?,
ud0=?,
sig_period=?,
sig_stock=?,
sig_window=?,
sig_validity=?,
sig_qty=?,
xpercent=?,
ms_validity=?,
step_max=?,
median_time_blocks=?,
avg_gen_time=?,
dt_diff_eval=?,
blocks_rot=?,
percent_rot=?
WHERE
currency=?""",
updated_fields + where_fields)
def get_one(self, **search):
"""
Get an existing community in the database
:param dict search: the criterions of the lookup
:rtype: sakia.data.entities.Community
"""
with self._conn:
filters = []
values = []
for k, v in search.items():
filters.append("{k}=?".format(k=k))
values.append(v)
request = "SELECT * FROM communities WHERE {filters}".format(filters=" AND ".join(filters))
c = self._conn.execute(request, tuple(values))
data = c.fetchone()
if data:
return Community(*data)
def get_all(self, **search):
"""
Get all existing community in the database corresponding to the search
:param dict search: the criterions of the lookup
:rtype: sakia.data.entities.Community
"""
with self._conn:
filters = []
values = []
for k, v in search.items():
operator = "LIKE" if k == "currency" else "="
value = "%{value}%".format(value=v) if k == "currency" else v
filters.append("{key} {operator} ?".format(key=k, operator=operator))
values.append(value)
request = "SELECT * FROM communities WHERE {filters}".format(filters=" AND ".join(filters))
c = self._conn.execute(request, tuple(values))
datas = c.fetchall()
if datas:
return [Community(*data) for data in datas]
return []
def drop(self, community):
"""
Drop an existing community from the database
:param sakia.data.entities.Community community: the community to update
"""
with self._conn:
where_fields = attr.astuple(community, filter=attr.filters.include(*CommunitiesRepo._primary_keys))
self._conn.execute("DELETE FROM communities WHERE currency=?", where_fields)
import attr
from ..entities import Identity
......@@ -17,8 +18,7 @@ class IdentitiesRepo:
with self._conn:
identity_tuple = attr.astuple(identity)
values = ",".join(['?'] * len(identity_tuple))
self._conn.execute("INSERT INTO identities "
"VALUES ({0})".format(values), identity_tuple)
self._conn.execute("INSERT INTO identities VALUES ({0})".format(values), identity_tuple)
def update(self, identity):
"""
......@@ -28,19 +28,19 @@ class IdentitiesRepo:
with self._conn:
updated_fields = attr.astuple(identity, filter=attr.filters.exclude(*IdentitiesRepo._primary_keys))
where_fields = attr.astuple(identity, filter=attr.filters.include(*IdentitiesRepo._primary_keys))
self._conn.execute("UPDATE identities SET "
"signature=?, "
"ts=?,"
"written=?,"
"revoked=?,"
"member=?,"
"ms_buid=?,"
"ms_timestamp=?"
"WHERE "
"currency=? AND "
"pubkey=? AND "
"uid=? AND "
"blockstamp=?", updated_fields + where_fields
self._conn.execute("""UPDATE identities SET
signature=?,
ts=?,
written=?,
revoked=?,
member=?,
ms_buid=?,
ms_timestamp=?
WHERE
currency=? AND
pubkey=? AND
uid=? AND
blockstamp=?""", updated_fields + where_fields
)
def get_one(self, **search):
......@@ -56,8 +56,7 @@ class IdentitiesRepo:
filters.append("{k}=?".format(k=k))
values.append(v)
request = "SELECT * FROM identities WHERE "
request += " AND ".join(filters)
request = "SELECT * FROM identities WHERE {filters}".format(filters=" AND ".join(filters))
c = self._conn.execute(request, tuple(values))
data = c.fetchone()
......@@ -77,8 +76,7 @@ class IdentitiesRepo:
filters.append("{k}=?".format(k=k))
values.append(v)
request = "SELECT * FROM identities WHERE "
request += " AND ".join(filters)
request = "SELECT * FROM identities WHERE {filters}".format(filters=" AND ".join(filters))
c = self._conn.execute(request, tuple(values))
datas = c.fetchall()
......@@ -93,8 +91,8 @@ class IdentitiesRepo:
"""
with self._conn:
where_fields = attr.astuple(identity, filter=attr.filters.include(*IdentitiesRepo._primary_keys))
self._conn.execute("DELETE FROM identities WHERE "
"currency=? AND "
"pubkey=? AND "
"uid=? AND "
"blockstamp=?", where_fields)
self._conn.execute("""DELETE FROM identities WHERE
currency=? AND
pubkey=? AND
uid=? AND
blockstamp=?""", where_fields)
import attr
import os
@attr.s(frozen=True)
......@@ -13,11 +14,11 @@ class MetaDatabase:
Prepares the database if the table is missing
"""
with self._conn:
self._conn.execute("create table if not exists meta("
"id integer not null,"
"version integer not null,"
"primary key (id)"
")"
self._conn.execute("""CREATE TABLE IF NOT EXISTS meta(
id INTEGER NOT NULL,
version INTEGER NOT NULL,
PRIMARY KEY (id)
)"""
)
@property
......@@ -42,22 +43,9 @@ class MetaDatabase:
Init all the tables
:return:
"""
sql_file = open(os.path.join(os.path.dirname(__file__), 'meta.sql'), 'r')
with self._conn:
self._conn.execute("create table if not exists identities("
"currency varchar(30), "
"pubkey varchar(50),"
"uid varchar(255),"
"blockstamp varchar(100),"
"signature varchar(100),"
"ts int,"
"written boolean,"
"revoked boolean,"
"member boolean,"
"ms_buid varchar(100),"
"ms_timestamp int,"
"PRIMARY KEY (currency, pubkey, uid, blockstamp)"
")"
)
self._conn.executescript(sql_file.read())
def version(self):
with self._conn:
......@@ -68,4 +56,3 @@ class MetaDatabase:
else:
self._conn.execute("INSERT INTO meta VALUES (1, 0)")
return 0
-- IDENTITY TABLE
CREATE TABLE IF NOT EXISTS identities(
currency VARCHAR(30),
pubkey VARCHAR(50),
uid VARCHAR(255),
blockstamp VARCHAR(100),
signature VARCHAR(100),
ts INT,
written BOOLEAN,
revoked BOOLEAN,
member BOOLEAN,
ms_buid VARCHAR(100),
ms_timestamp INT,
PRIMARY KEY (currency, pubkey, uid, blockstamp)
);
-- COMMUNITY TABLE
CREATE TABLE IF NOT EXISTS communities(
c FLOAT(1,6),
dt INT,
ud0 INT,
sig_period INT,
sig_stock INT,
sig_window INT,
sig_validity INT,
sig_qty INT,
xpercent FLOAT(1,6),
ms_validity INT,
step_max INT,
median_time_blocks INT,
avg_gen_time INT,
dt_diff_eval INT,
blocks_rot INT,
percent_rot FLOAT(1,6),
currency VARCHAR(30),
PRIMARY KEY (currency)
);
import sqlite3
import unittest
from duniterpy.documents import BlockUID
from sakia.data.entities import Community
from sakia.data.repositories import CommunitiesRepo, MetaDatabase
class TestIdentitiesRepo(unittest.TestCase):
def setUp(self):
sqlite3.register_adapter(BlockUID, str)
sqlite3.register_adapter(bool, int)
sqlite3.register_converter("BOOLEAN", lambda v: bool(int(v)))
self.con = sqlite3.connect(":memory:", detect_types=sqlite3.PARSE_DECLTYPES)
def tearDown(self):
self.con.close()
def test_add_get_drop_community(self):
meta_repo = MetaDatabase(self.con)
meta_repo.prepare()
meta_repo.upgrade_database()
communities_repo = CommunitiesRepo(self.con)
communities_repo.insert(Community(
0.1,
86400,
100000,
10800,
40,
2629800,
31557600,
1,
0.9,
604800,
5,
12,
300,
25,
10,
0.66,
"testcurrency"
))
community = communities_repo.get_one(currency="testcurrency")
self.assertEqual(community.currency, "testcurrency")
self.assertEqual(community.c, 0.1)
self.assertEqual(community.dt, 86400)
communities_repo.drop(community)
community = communities_repo.get_one(currency="testcurrency")
self.assertIsNone(community)
def test_add_get_multiple_community(self):
meta_repo = MetaDatabase(self.con)
meta_repo.prepare()
meta_repo.upgrade_database()
communities_repo = CommunitiesRepo(self.con)
communities_repo.insert(Community(
0.1,
86400,
100000,
10800,
40,
2629800,
31557600,
1,
0.9,
604800,
5,
12,
300,
25,
10,
0.66,
"testcurrency"
)
)
communities_repo.insert(Community(
0.1,
86400 * 365,
100000,
10800,
40,
2629800,
31557600,
1,
0.9,
604800,
5,
12,
300,
25,
10,
0.66,
"testcurrency2"
)
)
communities = communities_repo.get_all(currency="testcurrency")
self.assertIn("testcurrency", [i.currency for i in communities])
self.assertIn("testcurrency2", [i.currency for i in communities])
self.assertIn(86400, [i.dt for i in communities])
self.assertIn(86400 * 365, [i.dt for i in communities])
def test_add_update_community(self):
meta_repo = MetaDatabase(self.con)
meta_repo.prepare()
meta_repo.upgrade_database()
communities_repo = CommunitiesRepo(self.con)
community = Community(
0.1,
86400,
100000,
10800,
40,
2629800,
31557600,
1,
0.9,
604800,
5,
12,
300,
25,
10,
0.66,
"testcurrency"
)
communities_repo.insert(community)
community.c = 0.0922
communities_repo.update(community)
community2 = communities_repo.get_one(currency="testcurrency")
self.assertEquals(0.0922, community2.c)
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment