Skip to content
Snippets Groups Projects
Commit 1c1d9899 authored by inso's avatar inso Committed by GitHub
Browse files

Merge pull request #535 from vtexier/feature/backend

add community repository
parents 0675182c 433b9970
No related branches found
No related tags found
No related merge requests found
duniterpy>=0.20.dev0
git+https://github.com/Insoleet/quamash.git@master
asynctest
networkx
\ No newline at end of file
networkx
git+https://github.com/hynek/attrs.git@master
git+https://github.com/duniter/duniter-python-api.git@master
from .identity import Identity
\ No newline at end of file
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 .meta import MetaDatabase
\ No newline at end of file
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
......@@ -16,9 +17,8 @@ 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)
values = ",".join(['?'] * len(identity_tuple))
self._conn.execute("INSERT INTO identities VALUES ({0})".format(values), identity_tuple)
def update(self, identity):
"""
......@@ -28,20 +28,20 @@ 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.
Finish editing this message first!
Please register or to comment