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

merge community in blockchain repository

add paginate and sort in get_all
parent 06fc3c70
No related branches found
No related tags found
1 merge request!537Feature/backend
from .identity import Identity from .identity import Identity
from .community import Community from .blockchain import Blockchain, BlockchainParameters
from .blockchain import Blockchain
from .certification import Certification from .certification import Certification
from .transaction import Transaction from .transaction import Transaction
from .node import Node from .node import Node
...@@ -2,8 +2,46 @@ import attr ...@@ -2,8 +2,46 @@ import attr
from duniterpy.documents import block_uid, BlockUID from duniterpy.documents import block_uid, BlockUID
@attr.s()
class BlockchainParameters:
# 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)
@attr.s() @attr.s()
class Blockchain: class Blockchain:
# Parameters in block 0
parameters = attr.ib(default=BlockchainParameters())
# block number and hash # block number and hash
current_buid = attr.ib(convert=block_uid, default=BlockUID.empty()) current_buid = attr.ib(convert=block_uid, default=BlockUID.empty())
# Number of members # Number of members
......
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 .identities import IdentitiesRepo
from .communities import CommunitiesRepo
from .blockchains import BlockchainsRepo from .blockchains import BlockchainsRepo
from .meta import MetaDatabase from .meta import MetaDatabase
from .certifications import CertificationsRepo from .certifications import CertificationsRepo
......
from typing import List
import attr import attr
from ..entities import Blockchain from ..entities import Blockchain, BlockchainParameters
@attr.s(frozen=True) @attr.s(frozen=True)
...@@ -16,7 +18,8 @@ class BlockchainsRepo: ...@@ -16,7 +18,8 @@ class BlockchainsRepo:
:param sakia.data.entities.Blockchain blockchain: the blockchain to commit :param sakia.data.entities.Blockchain blockchain: the blockchain to commit
""" """
with self._conn: with self._conn:
blockchain_tuple = attr.astuple(blockchain) blockchain_tuple = attr.astuple(blockchain.parameters) \
+ attr.astuple(blockchain, filter=attr.filters.exclude(Blockchain.parameters))
values = ",".join(['?'] * len(blockchain_tuple)) values = ",".join(['?'] * len(blockchain_tuple))
self._conn.execute("INSERT INTO blockchains VALUES ({0})".format(values), blockchain_tuple) self._conn.execute("INSERT INTO blockchains VALUES ({0})".format(values), blockchain_tuple)
...@@ -26,7 +29,8 @@ class BlockchainsRepo: ...@@ -26,7 +29,8 @@ class BlockchainsRepo:
:param sakia.data.entities.Blockchain blockchain: the blockchain to update :param sakia.data.entities.Blockchain blockchain: the blockchain to update
""" """
with self._conn: with self._conn:
updated_fields = attr.astuple(blockchain, filter=attr.filters.exclude(*BlockchainsRepo._primary_keys)) updated_fields = attr.astuple(blockchain, filter=attr.filters.exclude(
Blockchain.parameters, *BlockchainsRepo._primary_keys))
where_fields = attr.astuple(blockchain, filter=attr.filters.include(*BlockchainsRepo._primary_keys)) where_fields = attr.astuple(blockchain, filter=attr.filters.include(*BlockchainsRepo._primary_keys))
self._conn.execute("""UPDATE blockchains SET self._conn.execute("""UPDATE blockchains SET
current_buid=?, current_buid=?,
...@@ -58,29 +62,49 @@ class BlockchainsRepo: ...@@ -58,29 +62,49 @@ class BlockchainsRepo:
c = self._conn.execute(request, tuple(values)) c = self._conn.execute(request, tuple(values))
data = c.fetchone() data = c.fetchone()
if data: if data:
return Blockchain(*data) return Blockchain(BlockchainParameters(*data[:15]), *data[16:])
def get_all(self, **search): def get_all(self, offset=0, limit=1000, sort_by="currency", sort_order="ASC", **search) -> List[Blockchain]:
""" """
Get all existing blockchain in the database corresponding to the search Get all existing blockchain in the database corresponding to the search
:param int offset: offset in results to paginate
:param int limit: limit results to paginate
:param str sort_by: column name to sort by
:param str sort_order: sort order ASC or DESC
:param dict search: the criterions of the lookup :param dict search: the criterions of the lookup
:rtype: sakia.data.entities.Blockchain :rtype: [sakia.data.entities.Blockchain]
""" """
with self._conn: with self._conn:
filters = [] filters = []
values = [] values = []
if search:
for k, v in search.items(): for k, v in search.items():
operator = "LIKE" if k == "currency" else "=" filters.append("{k}=?".format(k=k))
value = "%{value}%".format(value=v) if k == "currency" else v values.append(v)
filters.append("{key} {operator} ?".format(key=k, operator=operator))
values.append(value)
request = "SELECT * FROM blockchains WHERE {filters}".format(filters=" AND ".join(filters))
request = """SELECT * FROM blockchains WHERE {filters}
ORDER BY {sort_by} {sort_order}
LIMIT {limit} OFFSET {offset}""".format(
filters=" AND ".join(filters),
offset=offset,
limit=limit,
sort_by=sort_by,
sort_order=sort_order
)
c = self._conn.execute(request, tuple(values)) c = self._conn.execute(request, tuple(values))
else:
request = """SELECT * FROM blockchains
ORDER BY {sort_by} {sort_order}
LIMIT {limit} OFFSET {offset}""".format(
offset=offset,
limit=limit,
sort_by=sort_by,
sort_order=sort_order
)
c = self._conn.execute(request)
datas = c.fetchall() datas = c.fetchall()
if datas: if datas:
return [Blockchain(*data) for data in datas] return [Blockchain(BlockchainParameters(*data[:15]), *data[16:]) for data in datas]
return [] return []
def drop(self, blockchain): def drop(self, blockchain):
......
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)
...@@ -16,8 +16,8 @@ CREATE TABLE IF NOT EXISTS identities( ...@@ -16,8 +16,8 @@ CREATE TABLE IF NOT EXISTS identities(
PRIMARY KEY (currency, pubkey, uid, blockstamp) PRIMARY KEY (currency, pubkey, uid, blockstamp)
); );
-- COMMUNITIES TABLE -- BLOCKCHAIN TABLE
CREATE TABLE IF NOT EXISTS communities ( CREATE TABLE IF NOT EXISTS blockchains (
c FLOAT(1, 6), c FLOAT(1, 6),
dt INT, dt INT,
ud0 INT, ud0 INT,
...@@ -34,12 +34,6 @@ CREATE TABLE IF NOT EXISTS communities ( ...@@ -34,12 +34,6 @@ CREATE TABLE IF NOT EXISTS communities (
dt_diff_eval INT, dt_diff_eval INT,
blocks_rot INT, blocks_rot INT,
percent_rot FLOAT(1, 6), percent_rot FLOAT(1, 6),
currency VARCHAR(30),
PRIMARY KEY (currency)
);
-- BLOCKCHAIN TABLE
CREATE TABLE IF NOT EXISTS blockchains (
current_buid INT, current_buid INT,
nb_members INT, nb_members INT,
current_mass INT, current_mass INT,
......
...@@ -3,7 +3,7 @@ import unittest ...@@ -3,7 +3,7 @@ import unittest
from duniterpy.documents import BlockUID from duniterpy.documents import BlockUID
from sakia.data.entities import Blockchain from sakia.data.entities import Blockchain, BlockchainParameters
from sakia.data.repositories import BlockchainsRepo, MetaDatabase from sakia.data.repositories import BlockchainsRepo, MetaDatabase
...@@ -23,6 +23,23 @@ class TestBlockchainsRepo(unittest.TestCase): ...@@ -23,6 +23,23 @@ class TestBlockchainsRepo(unittest.TestCase):
meta_repo.upgrade_database() meta_repo.upgrade_database()
blockchains_repo = BlockchainsRepo(self.con) blockchains_repo = BlockchainsRepo(self.con)
blockchains_repo.insert(Blockchain( blockchains_repo.insert(Blockchain(
BlockchainParameters(
0.1,
86400,
100000,
10800,
40,
2629800,
31557600,
1,
0.9,
604800,
5,
12,
300,
25,
10,
0.66),
"20-7518C700E78B56CC21FB1DDC6CBAB24E0FACC9A798F5ED8736EA007F38617D67", "20-7518C700E78B56CC21FB1DDC6CBAB24E0FACC9A798F5ED8736EA007F38617D67",
10, 10,
1000000, 1000000,
...@@ -33,6 +50,23 @@ class TestBlockchainsRepo(unittest.TestCase): ...@@ -33,6 +50,23 @@ class TestBlockchainsRepo(unittest.TestCase):
"testcurrency" "testcurrency"
)) ))
blockchain = blockchains_repo.get_one(currency="testcurrency") blockchain = blockchains_repo.get_one(currency="testcurrency")
self.assertEqual(blockchain.parameters, BlockchainParameters(
0.1,
86400,
100000,
10800,
40,
2629800,
31557600,
1,
0.9,
604800,
5,
12,
300,
25,
10,
0.66))
self.assertEqual(blockchain.currency, "testcurrency") self.assertEqual(blockchain.currency, "testcurrency")
self.assertEqual(blockchain.current_buid, BlockUID(20, self.assertEqual(blockchain.current_buid, BlockUID(20,
"7518C700E78B56CC21FB1DDC6CBAB24E0FACC9A798F5ED8736EA007F38617D67") "7518C700E78B56CC21FB1DDC6CBAB24E0FACC9A798F5ED8736EA007F38617D67")
...@@ -49,6 +83,23 @@ class TestBlockchainsRepo(unittest.TestCase): ...@@ -49,6 +83,23 @@ class TestBlockchainsRepo(unittest.TestCase):
meta_repo.upgrade_database() meta_repo.upgrade_database()
blockchains_repo = BlockchainsRepo(self.con) blockchains_repo = BlockchainsRepo(self.con)
blockchains_repo.insert(Blockchain( blockchains_repo.insert(Blockchain(
BlockchainParameters(
0.1,
86400,
100000,
10800,
40,
2629800,
31557600,
1,
0.9,
604800,
5,
12,
300,
25,
10,
0.66),
"20-7518C700E78B56CC21FB1DDC6CBAB24E0FACC9A798F5ED8736EA007F38617D67", "20-7518C700E78B56CC21FB1DDC6CBAB24E0FACC9A798F5ED8736EA007F38617D67",
10, 10,
1000000, 1000000,
...@@ -57,9 +108,25 @@ class TestBlockchainsRepo(unittest.TestCase): ...@@ -57,9 +108,25 @@ class TestBlockchainsRepo(unittest.TestCase):
0, 0,
999999, 999999,
"testcurrency" "testcurrency"
) ))
)
blockchains_repo.insert(Blockchain( blockchains_repo.insert(Blockchain(
BlockchainParameters(
0.1,
86400 * 365,
100000,
10800,
40,
2629800,
31557600,
1,
0.9,
604800,
5,
12,
300,
25,
10,
0.66),
"20-7518C700E78B56CC21FB1DDC6CBAB24E0FACC9A798F5ED8736EA007F38617D67", "20-7518C700E78B56CC21FB1DDC6CBAB24E0FACC9A798F5ED8736EA007F38617D67",
20, 20,
1000000, 1000000,
...@@ -68,14 +135,17 @@ class TestBlockchainsRepo(unittest.TestCase): ...@@ -68,14 +135,17 @@ class TestBlockchainsRepo(unittest.TestCase):
0, 0,
999999, 999999,
"testcurrency2" "testcurrency2"
) ))
)
blockchains = blockchains_repo.get_all()
# result sorted by currency name by default
self.assertEquals(86400, blockchains[0].parameters.dt)
self.assertEquals("testcurrency", blockchains[0].currency)
self.assertEquals(10, blockchains[0].nb_members)
blockchains = blockchains_repo.get_all(currency="testcurrency") self.assertEquals(86400*365, blockchains[1].parameters.dt)
self.assertIn("testcurrency", [i.currency for i in blockchains]) self.assertEquals("testcurrency2", blockchains[1].currency)
self.assertIn("testcurrency2", [i.currency for i in blockchains]) self.assertEquals(20, blockchains[1].nb_members)
self.assertIn(10, [i.nb_members for i in blockchains])
self.assertIn(20, [i.nb_members for i in blockchains])
def test_add_update_blockchain(self): def test_add_update_blockchain(self):
meta_repo = MetaDatabase(self.con) meta_repo = MetaDatabase(self.con)
...@@ -83,6 +153,23 @@ class TestBlockchainsRepo(unittest.TestCase): ...@@ -83,6 +153,23 @@ class TestBlockchainsRepo(unittest.TestCase):
meta_repo.upgrade_database() meta_repo.upgrade_database()
blockchains_repo = BlockchainsRepo(self.con) blockchains_repo = BlockchainsRepo(self.con)
blockchain = Blockchain( blockchain = Blockchain(
BlockchainParameters(
0.1,
86400,
100000,
10800,
40,
2629800,
31557600,
1,
0.9,
604800,
5,
12,
300,
25,
10,
0.66),
"20-7518C700E78B56CC21FB1DDC6CBAB24E0FACC9A798F5ED8736EA007F38617D67", "20-7518C700E78B56CC21FB1DDC6CBAB24E0FACC9A798F5ED8736EA007F38617D67",
10, 10,
1000000, 1000000,
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment