Skip to content
Snippets Groups Projects
Commit 25fec39b authored by inso's avatar inso
Browse files

Add Sources in repositories

parent d461f6c7
No related branches found
No related tags found
No related merge requests found
...@@ -6,3 +6,4 @@ from .node import Node ...@@ -6,3 +6,4 @@ from .node import Node
from .connection import Connection from .connection import Connection
from .user_parameters import UserParameters from .user_parameters import UserParameters
from .app_data import AppData from .app_data import AppData
from .source import Source
...@@ -45,7 +45,7 @@ class Blockchain: ...@@ -45,7 +45,7 @@ class Blockchain:
# 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
nb_members = attr.ib(convert=int, default=0, cmp=False, hash=False) members_count = attr.ib(convert=int, default=0, cmp=False, hash=False)
# Current monetary mass in units # Current monetary mass in units
current_mass = attr.ib(convert=int, default=0, cmp=False, hash=False) current_mass = attr.ib(convert=int, default=0, cmp=False, hash=False)
# Median time in seconds # Median time in seconds
...@@ -58,5 +58,13 @@ class Blockchain: ...@@ -58,5 +58,13 @@ class Blockchain:
last_ud_time = attr.ib(convert=int, default=0, cmp=False, hash=False) last_ud_time = attr.ib(convert=int, default=0, cmp=False, hash=False)
# Previous monetary mass in units # Previous monetary mass in units
previous_mass = attr.ib(convert=int, default=0, cmp=False, hash=False) previous_mass = attr.ib(convert=int, default=0, cmp=False, hash=False)
# Previous members count
previous_members_count = attr.ib(convert=int, default=0, cmp=False, hash=False)
# Previous UD amount in units (multiply by 10^base)
previous_ud = attr.ib(convert=int, default=0, cmp=False, hash=False)
# Previous UD base
previous_ud_base = attr.ib(convert=int, default=0, cmp=False, hash=False)
# Previous UD base
previous_ud_time = attr.ib(convert=int, default=0, cmp=False, hash=False)
# Currency name # Currency name
currency = attr.ib(convert=str, default="", cmp=False, hash=False) currency = attr.ib(convert=str, default="", cmp=False, hash=False)
import attr
from duniterpy.documents import block_uid
@attr.s()
class Source:
identifier = attr.ib(convert=str)
currency = attr.ib(convert=str)
pubkey = attr.ib(convert=str)
type = attr.ib(convert=str, validator=lambda i, a, s: s == 'T' or s == 'D')
offset = attr.ib(convert=int, cmp=False, hash=False)
amount = attr.ib(convert=int, cmp=False, hash=False)
base = attr.ib(convert=int, cmp=False, hash=False)
import attr import attr
import re import re
from ..entities import Blockchain from ..entities import Blockchain
from .nodes import NodesProcessor
from ..connectors import BmaConnector
from duniterpy.api import bma, errors from duniterpy.api import bma, errors
from duniterpy.documents import Block, BMAEndpoint from duniterpy.documents import Block, BMAEndpoint
import asyncio import asyncio
...@@ -11,6 +13,15 @@ class BlockchainProcessor: ...@@ -11,6 +13,15 @@ class BlockchainProcessor:
_repo = attr.ib() # :type sakia.data.repositories.CertificationsRepo _repo = attr.ib() # :type sakia.data.repositories.CertificationsRepo
_bma_connector = attr.ib() # :type sakia.data.connectors.bma.BmaConnector _bma_connector = attr.ib() # :type sakia.data.connectors.bma.BmaConnector
@classmethod
def instanciate(cls, app):
"""
Instanciate a blockchain processor
:param sakia.app.Application app: the app
"""
return cls(app.db.blockchains_repo,
BmaConnector(NodesProcessor(app.db.nodes_repo)))
def current_buid(self, currency): def current_buid(self, currency):
""" """
Get the local current blockuid Get the local current blockuid
...@@ -39,12 +50,12 @@ class BlockchainProcessor: ...@@ -39,12 +50,12 @@ class BlockchainProcessor:
""" """
return self._repo.get_one({'currency': currency}).monetary_mass return self._repo.get_one({'currency': currency}).monetary_mass
def nb_members(self, currency): def members_count(self, currency):
""" """
Get the number of members in the blockchain Get the number of members in the blockchain
:rtype: int :rtype: int
""" """
return self._repo.get_one({'currency': currency}).nb_members return self._repo.get_one({'currency': currency}).members_count
def last_ud(self, currency): def last_ud(self, currency):
""" """
...@@ -54,6 +65,44 @@ class BlockchainProcessor: ...@@ -54,6 +65,44 @@ class BlockchainProcessor:
blockchain = self._repo.get_one({'currency': currency}) blockchain = self._repo.get_one({'currency': currency})
return blockchain.last_ud, blockchain.last_ud_base return blockchain.last_ud, blockchain.last_ud_base
def last_ud_time(self, currency):
"""
Get the last ud time
:rtype: int
"""
blockchain = self._repo.get_one({'currency': currency})
return blockchain.last_ud_time
def previous_monetary_mass(self, currency):
"""
Get the local current monetary mass
:rtype: int
"""
return self._repo.get_one({'currency': currency}).previous_mass
def previous_members_count(self, currency):
"""
Get the local current monetary mass
:rtype: int
"""
return self._repo.get_one({'currency': currency}).previous_members_count
def previous_ud(self, currency):
"""
Get the previous ud value and base
:rtype: int, int
"""
blockchain = self._repo.get_one({'currency': currency})
return blockchain.previous_ud, blockchain.previous_ud_base
def previous_ud_time(self, currency):
"""
Get the previous ud time
:rtype: int
"""
blockchain = self._repo.get_one({'currency': currency})
return blockchain.previous_ud_time
async def new_blocks_with_identities(self, currency): async def new_blocks_with_identities(self, currency):
""" """
Get blocks more recent than local blockuid Get blocks more recent than local blockuid
...@@ -66,13 +115,13 @@ class BlockchainProcessor: ...@@ -66,13 +115,13 @@ class BlockchainProcessor:
bma.blockchain.Actives, bma.blockchain.Actives,
bma.blockchain.Excluded, bma.blockchain.Excluded,
bma.blockchain.Newcomers): bma.blockchain.Newcomers):
future_requests.append(self._bma_connector.get(req)) future_requests.append(self._bma_connector.get(currency, req))
results = await asyncio.gather(future_requests) results = await asyncio.gather(future_requests)
for res in results: for res in results:
with_identities += res["result"]["blocks"] with_identities += res["result"]["blocks"]
local_current_buid = self.current_buid() local_current_buid = self.current_buid(currency)
return sorted([b for b in with_identities if b > local_current_buid.number]) return sorted([b for b in with_identities if b > local_current_buid.number])
async def new_blocks_with_money(self, currency): async def new_blocks_with_money(self, currency):
...@@ -83,13 +132,13 @@ class BlockchainProcessor: ...@@ -83,13 +132,13 @@ class BlockchainProcessor:
with_money = [] with_money = []
future_requests = [] future_requests = []
for req in (bma.blockchain.UD, bma.blockchain.TX): for req in (bma.blockchain.UD, bma.blockchain.TX):
future_requests.append(self._bma_connector.get(req)) future_requests.append(self._bma_connector.get(currency, req))
results = await asyncio.gather(future_requests) results = await asyncio.gather(future_requests)
for res in results: for res in results:
with_money += res["result"]["blocks"] with_money += res["result"]["blocks"]
local_current_buid = self.current_buid() local_current_buid = self.current_buid(currency)
return sorted([b for b in with_money if b > local_current_buid.number]) return sorted([b for b in with_money if b > local_current_buid.number])
async def blocks(self, numbers, currency): async def blocks(self, numbers, currency):
...@@ -103,7 +152,7 @@ class BlockchainProcessor: ...@@ -103,7 +152,7 @@ class BlockchainProcessor:
to_block = max(numbers) to_block = max(numbers)
count = to_block - from_block count = to_block - from_block
blocks_data = await self._bma_connector.get(bma.blockchain.Blocks, req_args={'count': count, blocks_data = await self._bma_connector.get(currency, bma.blockchain.Blocks, req_args={'count': count,
'from_': from_block}) 'from_': from_block})
blocks = [] blocks = []
for data in blocks_data: for data in blocks_data:
......
...@@ -5,3 +5,4 @@ from .certifications import CertificationsRepo ...@@ -5,3 +5,4 @@ from .certifications import CertificationsRepo
from .transactions import TransactionsRepo from .transactions import TransactionsRepo
from .nodes import NodesRepo from .nodes import NodesRepo
from .connections import ConnectionsRepo from .connections import ConnectionsRepo
from .sources import SourcesRepo
...@@ -9,6 +9,7 @@ from .blockchains import BlockchainsRepo ...@@ -9,6 +9,7 @@ from .blockchains import BlockchainsRepo
from .certifications import CertificationsRepo from .certifications import CertificationsRepo
from .transactions import TransactionsRepo from .transactions import TransactionsRepo
from .nodes import NodesRepo from .nodes import NodesRepo
from .sources import SourcesRepo
@attr.s(frozen=True) @attr.s(frozen=True)
...@@ -16,12 +17,13 @@ class SakiaDatabase: ...@@ -16,12 +17,13 @@ class SakiaDatabase:
"""The repository for Identities entities. """The repository for Identities entities.
""" """
conn = attr.ib() # :type sqlite3.Connection conn = attr.ib() # :type sqlite3.Connection
connections_repo = attr.ib() connections_repo = attr.ib(default=None)
identities_repo = attr.ib() identities_repo = attr.ib(default=None)
blockchains_repo = attr.ib() blockchains_repo = attr.ib(default=None)
certifications_repo = attr.ib() certifications_repo = attr.ib(default=None)
transactions_repo = attr.ib() transactions_repo = attr.ib(default=None)
nodes_repo = attr.ib() nodes_repo = attr.ib(default=None)
sources_repo = attr.ib(default=None)
_logger = attr.ib(default=attr.Factory(lambda: logging.getLogger('sakia'))) _logger = attr.ib(default=attr.Factory(lambda: logging.getLogger('sakia')))
db_file = 'sakia.db' db_file = 'sakia.db'
...@@ -34,7 +36,7 @@ class SakiaDatabase: ...@@ -34,7 +36,7 @@ class SakiaDatabase:
detect_types=sqlite3.PARSE_DECLTYPES) detect_types=sqlite3.PARSE_DECLTYPES)
meta = SakiaDatabase(con, ConnectionsRepo(con), IdentitiesRepo(con), meta = SakiaDatabase(con, ConnectionsRepo(con), IdentitiesRepo(con),
BlockchainsRepo(con), CertificationsRepo(con), TransactionsRepo(con), BlockchainsRepo(con), CertificationsRepo(con), TransactionsRepo(con),
NodesRepo(con)) NodesRepo(con), SourcesRepo(con))
meta.prepare() meta.prepare()
meta.upgrade_database() meta.upgrade_database()
return meta return meta
......
...@@ -104,4 +104,17 @@ CREATE TABLE IF NOT EXISTS connections( ...@@ -104,4 +104,17 @@ CREATE TABLE IF NOT EXISTS connections(
PRIMARY KEY (currency, pubkey) PRIMARY KEY (currency, pubkey)
); );
-- Cnnections TABLE
CREATE TABLE IF NOT EXISTS sources(
identifier VARCHAR(255),
currency VARCHAR(30),
pubkey VARCHAR(50),
type VARCHAR(8),
offset INT,
amount INT,
base INT,
PRIMARY KEY (identifier)
);
import attr
from ..entities import Source
@attr.s(frozen=True)
class SourcesRepo:
"""The repository for Communities entities.
"""
_conn = attr.ib() # :type sqlite3.Connection
_primary_keys = (Source.identifier,)
def insert(self, source):
"""
Commit a source to the database
:param sakia.data.entities.Source source: the source to commit
"""
with self._conn:
source_tuple = attr.astuple(source)
values = ",".join(['?'] * len(source_tuple))
self._conn.execute("INSERT INTO sources VALUES ({0})".format(values), source_tuple)
def get_one(self, **search):
"""
Get an existing source in the database
:param dict search: the criterions of the lookup
:rtype: sakia.data.entities.Source
"""
with self._conn:
filters = []
values = []
for k, v in search.items():
filters.append("{k}=?".format(k=k))
values.append(v)
request = "SELECT * FROM sources WHERE {filters}".format(filters=" AND ".join(filters))
c = self._conn.execute(request, tuple(values))
data = c.fetchone()
if data:
return Source(*data)
def get_all(self, **search):
"""
Get all existing source in the database corresponding to the search
:param dict search: the criterions of the lookup
:rtype: sakia.data.entities.Source
"""
with self._conn:
filters = []
values = []
for k, v in search.items():
value = v
filters.append("{key} = ?".format(key=k))
values.append(value)
request = "SELECT * FROM sources WHERE {filters}".format(filters=" AND ".join(filters))
c = self._conn.execute(request, tuple(values))
datas = c.fetchall()
if datas:
return [Source(*data) for data in datas]
return []
def drop(self, source):
"""
Drop an existing source from the database
:param sakia.data.entities.Source source: the source to update
"""
with self._conn:
where_fields = attr.astuple(source, filter=attr.filters.include(*SourcesRepo._primary_keys))
self._conn.execute("""DELETE FROM sources
WHERE
identifier=?""", where_fields)
from sakia.data.repositories import SourcesRepo, SakiaDatabase
from sakia.data.entities import Source
from duniterpy.documents import BlockUID
import unittest
import sqlite3
class TestSourcesRepo(unittest.TestCase):
def setUp(self):
self.meta_repo = SakiaDatabase(sqlite3.connect(":memory:", detect_types=sqlite3.PARSE_DECLTYPES))
self.meta_repo.prepare()
self.meta_repo.upgrade_database()
def tearDown(self):
pass
def test_add_get_drop_source(self):
sources_repo = SourcesRepo(self.meta_repo.conn)
sources_repo.insert(Source("0835CEE9B4766B3866DD942971B3EE2CF953599EB9D35BFD5F1345879498B843",
"testcurrency",
"FADxcH5LmXGmGFgdixSes6nWnC4Vb4pRUBYT81zQRhjn",
"T",
3,
1565,
1))
source = sources_repo.get_one(identifier="0835CEE9B4766B3866DD942971B3EE2CF953599EB9D35BFD5F1345879498B843")
self.assertEqual(source.currency, "testcurrency")
self.assertEqual(source.pubkey, "FADxcH5LmXGmGFgdixSes6nWnC4Vb4pRUBYT81zQRhjn")
self.assertEqual(source.type, "T")
self.assertEqual(source.amount, 1565)
self.assertEqual(source.base, 1)
self.assertEqual(source.offset, 3)
sources_repo.drop(source)
source = sources_repo.get_one(identifier="0835CEE9B4766B3866DD942971B3EE2CF953599EB9D35BFD5F1345879498B843")
self.assertIsNone(source)
def test_add_get_multiple_source(self):
sources_repo = SourcesRepo(self.meta_repo.conn)
sources_repo.insert(Source("0835CEE9B4766B3866DD942971B3EE2CF953599EB9D35BFD5F1345879498B843",
"testcurrency",
"FADxcH5LmXGmGFgdixSes6nWnC4Vb4pRUBYT81zQRhjn",
"T",
3,
1565,
1))
sources_repo.insert(Source("2pyPsXM8UCB88jP2NRM4rUHxb63qm89JMEWbpoRrhyDK",
"testcurrency",
"FADxcH5LmXGmGFgdixSes6nWnC4Vb4pRUBYT81zQRhjn",
"D",
22635,
726946,
1))
sources = sources_repo.get_all(currency="testcurrency", pubkey="FADxcH5LmXGmGFgdixSes6nWnC4Vb4pRUBYT81zQRhjn")
self.assertIn("testcurrency", [s.currency for s in sources])
self.assertIn("FADxcH5LmXGmGFgdixSes6nWnC4Vb4pRUBYT81zQRhjn", [s.pubkey for s in sources])
self.assertIn("2pyPsXM8UCB88jP2NRM4rUHxb63qm89JMEWbpoRrhyDK", [s.identifier for s in sources])
self.assertIn("T", [s.type for s in sources])
self.assertIn("D", [s.type for s in sources])
self.assertIn(726946, [s.amount for s in sources])
self.assertIn(1565, [s.amount for s in sources])
self.assertIn("0835CEE9B4766B3866DD942971B3EE2CF953599EB9D35BFD5F1345879498B843", [s.identifier for s in sources])
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment