diff --git a/src/sakia/app.py b/src/sakia/app.py index 86ab4ee71de054b86527b02024962e52923c3eae..ab0c862af20df3f505d3c157a69eabd94ddf05b1 100644 --- a/src/sakia/app.py +++ b/src/sakia/app.py @@ -109,10 +109,10 @@ class Application(QObject): self.transactions_services[currency] = TransactionsService(currency, transactions_processor, identities_processor, bma_connector) - self.blockchain_services[currency] = BlockchainService(currency, blockchain_processor, bma_connector, + self.blockchain_services[currency] = BlockchainService(self, currency, blockchain_processor, bma_connector, self.identities_services[currency], self.transactions_services[currency]) - self.network_services[currency] = NetworkService.load(currency, nodes_processor, + self.network_services[currency] = NetworkService.load(self, currency, nodes_processor, self.blockchain_services[currency]) self.sources_services[currency] = SourcesServices(currency, sources_processor, bma_connector) diff --git a/src/sakia/data/connectors/node.py b/src/sakia/data/connectors/node.py index 1dde86ca4d4a93347de6d9bdc8c897334282948c..c352dc990b43c41208833642564bc285cc33044c 100644 --- a/src/sakia/data/connectors/node.py +++ b/src/sakia/data/connectors/node.py @@ -7,7 +7,7 @@ import aiohttp import jsonschema from PyQt5.QtCore import QObject, pyqtSignal from aiohttp.errors import ClientError, DisconnectedError -from aiohttp.errors import WSClientDisconnectedError, WSServerHandshakeError, ClientResponseError +from aiohttp.errors import WSServerHandshakeError, ClientResponseError from duniterpy.api import bma, errors from duniterpy.documents import BlockUID, MalformedDocumentError, BMAEndpoint @@ -159,13 +159,13 @@ class NodeConnector(QObject): async for msg in ws: if msg.tp == aiohttp.MsgType.text: self._logger.debug("Received a block : {0}".format(self.node.pubkey[:5])) - block_data = bma.parse_text(msg.data) + block_data = bma.parse_text(msg.data, bma.ws.WS_BLOCk_SCHEMA) await self.refresh_block(block_data) elif msg.tp == aiohttp.MsgType.closed: break elif msg.tp == aiohttp.MsgType.error: break - except (WSServerHandshakeError, WSClientDisconnectedError, + except (WSServerHandshakeError, ClientResponseError, ValueError) as e: self._logger.debug("Websocket block {0} : {1} - {2}" .format(type(e).__name__, str(e), self.node.pubkey[:5])) @@ -320,13 +320,13 @@ class NodeConnector(QObject): async for msg in ws: if msg.tp == aiohttp.MsgType.text: self._logger.debug("Received a peer : {0}".format(self.node.pubkey[:5])) - peer_data = bma.parse_text(msg.data) + peer_data = bma.parse_text(msg.data, bma.ws.WS_PEER_SCHEMA) self.refresh_peer_data(peer_data) elif msg.tp == aiohttp.MsgType.closed: break elif msg.tp == aiohttp.MsgType.error: break - except (WSServerHandshakeError, WSClientDisconnectedError, + except (WSServerHandshakeError, ClientResponseError, ValueError) as e: self._logger.debug("Websocket peer {0} : {1} - {2}" .format(type(e).__name__, str(e), self.node.pubkey[:5])) diff --git a/src/sakia/data/processors/blockchain.py b/src/sakia/data/processors/blockchain.py index ab5bc52fb853874647d22c39f82465991be139d0..4acd2fead212a85f6be32a44f6250283d47c3ac9 100644 --- a/src/sakia/data/processors/blockchain.py +++ b/src/sakia/data/processors/blockchain.py @@ -117,11 +117,11 @@ class BlockchainProcessor: """ with_identities = [] future_requests = [] - for req in (bma.blockchain.Joiners, - bma.blockchain.Leavers, - bma.blockchain.Actives, - bma.blockchain.Excluded, - bma.blockchain.Newcomers): + for req in (bma.blockchain.joiners, + bma.blockchain.leavers, + bma.blockchain.actives, + bma.blockchain.excluded, + bma.blockchain.newcomers): future_requests.append(self._bma_connector.get(currency, req)) results = await asyncio.gather(*future_requests) @@ -138,7 +138,7 @@ class BlockchainProcessor: """ with_money = [] 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(currency, req)) results = await asyncio.gather(*future_requests) @@ -159,7 +159,7 @@ class BlockchainProcessor: to_block = max(numbers) count = to_block - from_block - blocks_data = await self._bma_connector.get(currency, 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}) blocks = [] for data in blocks_data: @@ -175,10 +175,9 @@ class BlockchainProcessor: blockchain = self._repo.get_one(currency=currency) if not blockchain: blockchain = Blockchain(currency=currency) - blockchain_parameters = BlockchainParameters() log_stream("Requesting blockchain parameters") try: - parameters = await self._bma_connector.get(currency, bma.blockchain.Parameters) + parameters = await self._bma_connector.get(currency, bma.blockchain.parameters) blockchain.parameters.ms_validity = parameters['msValidity'] blockchain.parameters.avg_gen_time = parameters['avgGenTime'] blockchain.parameters.blocks_rot = parameters['blocksRot'] @@ -203,7 +202,7 @@ class BlockchainProcessor: log_stream("Requesting current block") try: - current_block = await self._bma_connector.get(currency, bma.blockchain.Current) + current_block = await self._bma_connector.get(currency, bma.blockchain.current) signed_raw = "{0}{1}\n".format(current_block['raw'], current_block['signature']) block = Block.from_signed_raw(signed_raw) blockchain.current_buid = block.blockUID @@ -214,7 +213,7 @@ class BlockchainProcessor: raise log_stream("Requesting blocks with dividend") - with_ud = await self._bma_connector.get(currency, bma.blockchain.UD) + with_ud = await self._bma_connector.get(currency, bma.blockchain.ud) blocks_with_ud = with_ud['result']['blocks'] if len(blocks_with_ud) > 0: @@ -222,7 +221,7 @@ class BlockchainProcessor: try: index = max(len(blocks_with_ud) - 1, 0) block_number = blocks_with_ud[index] - block_with_ud = await self._bma_connector.get(currency, bma.blockchain.Block, + block_with_ud = await self._bma_connector.get(currency, bma.blockchain.block, req_args={'number': block_number}) if block_with_ud: blockchain.last_members_count = block_with_ud['membersCount'] @@ -238,7 +237,7 @@ class BlockchainProcessor: try: index = max(len(blocks_with_ud) - 2, 0) block_number = blocks_with_ud[index] - block_with_ud = await self._bma_connector.get(currency, bma.blockchain.Block, + block_with_ud = await self._bma_connector.get(currency, bma.blockchain.block, req_args={'number': block_number}) blockchain.previous_mass = block_with_ud['monetaryMass'] blockchain.previous_members_count = block_with_ud['membersCount'] @@ -250,4 +249,3 @@ class BlockchainProcessor: raise self._repo.insert(blockchain) - diff --git a/src/sakia/data/processors/certifications.py b/src/sakia/data/processors/certifications.py index 17455bb5f8fce020aaab4067d13b27f9a1593ae4..9065ef17d65f08f6a3fd095b92ba60228505e9cd 100644 --- a/src/sakia/data/processors/certifications.py +++ b/src/sakia/data/processors/certifications.py @@ -57,7 +57,7 @@ class CertificationsProcessor: self._certifications_repo.insert(cert) return cert - def commit_certification(self, cert): + def insert_or_update_certification(self, cert): """ Commits a certification to the DB :param sakia.data.entities.Certification cert: @@ -78,8 +78,8 @@ class CertificationsProcessor: identities = list() certifiers = list() try: - data = await self._bma_connector.get(identity.currency, bma.wot.CertifiersOf, - {'search': identity.pubkey}) + data = await self._bma_connector.get(identity.currency, bma.wot.certifiers_of, + req_args={'search': identity.pubkey}) for certifier_data in data['certifications']: certification = Certification(currency=identity.currency, @@ -110,7 +110,7 @@ class CertificationsProcessor: log_stream("Requesting certified by data") certified = list() try: - data = await self._bma_connector.get(identity.currency, bma.wot.CertifiedBy, {'search': identity.pubkey}) + data = await self._bma_connector.get(identity.currency, bma.wot.certified_by, req_args={'search': identity.pubkey}) for certified_data in data['certifications']: certification = Certification(currency=identity.currency, certifier=identity.pubkey, @@ -138,7 +138,7 @@ class CertificationsProcessor: log_stream('Commiting certifications...') for i, cert in enumerate(certifiers + certified): log_stream('Certification {0}/{1}'.format(i, len(certifiers + certified))) - self.commit_certification(cert) + self.insert_or_update_certification(cert) await asyncio.sleep(0) log_stream('Commiting identities...') diff --git a/src/sakia/data/processors/identities.py b/src/sakia/data/processors/identities.py index d0f87ca46da7135ee6a7b9c18b72291edb10a04d..654d8191d02bc7e09a2d2b752b2757bc2b206c12 100644 --- a/src/sakia/data/processors/identities.py +++ b/src/sakia/data/processors/identities.py @@ -122,7 +122,7 @@ class IdentitiesProcessor: else: return written[0] - def commit_identity(self, identity): + def insert_or_update_identity(self, identity): """ Saves an identity state in the db :param sakia.data.entities.Identity identity: the identity updated @@ -139,7 +139,7 @@ class IdentitiesProcessor: :param function log_stream: """ log_stream("Requesting membership data") - memberships_data = await self._bma_connector.get(identity.currency, bma.blockchain.Membership, + memberships_data = await self._bma_connector.get(identity.currency, bma.blockchain.memberships, req_args={'search': identity.pubkey}) if block_uid(memberships_data['sigDate']) == identity.blockstamp \ and memberships_data['uid'] == identity.uid: @@ -150,7 +150,7 @@ class IdentitiesProcessor: if identity.membership_buid: log_stream("Requesting membership timestamp") - ms_block_data = await self._bma_connector.get(identity.currency, bma.blockchain.Block, + ms_block_data = await self._bma_connector.get(identity.currency, bma.blockchain.block, req_args={'number': identity.membership_buid.number}) if ms_block_data: identity.membership_timestamp = ms_block_data['medianTime'] @@ -158,8 +158,8 @@ class IdentitiesProcessor: if memberships_data['memberships']: log_stream("Requesting identity requirements status") - requirements_data = await self._bma_connector.get(identity.currency, bma.wot.Requirements, - get_args={'search': identity.pubkey}) + requirements_data = await self._bma_connector.get(identity.currency, bma.wot.requirements, + req_args={'search': identity.pubkey}) identity.member = requirements_data['membershipExpiresIn'] > 0 and not requirements_data['outdistanced'] async def publish_selfcert(self, currency, identity, salt, password): @@ -183,7 +183,8 @@ class IdentitiesProcessor: selfcert.sign([key]) self._logger.debug("Key publish : {0}".format(selfcert.signed_raw())) - responses = await self._bma_connector.broadcast(currency, bma.wot.Add, {}, {'identity': selfcert.signed_raw()}) + responses = await self._bma_connector.broadcast(currency, bma.wot.add, + req_args={'identity': selfcert.signed_raw()}) result = (False, "") for r in responses: if r.status == 200: diff --git a/src/sakia/data/processors/sources.py b/src/sakia/data/processors/sources.py index 2e248348dae50b707da8c94ebed5d003abaf1a8e..4ebef26a4483e1984b614e30809962e605c739e6 100644 --- a/src/sakia/data/processors/sources.py +++ b/src/sakia/data/processors/sources.py @@ -30,7 +30,8 @@ class SourcesProcessor: if not one_source: log_stream("Requesting sources") try: - sources_data = await self._bma_connector.get(currency, bma.tx.Sources, req_args={'pubkey': pubkey}) + sources_data = await self._bma_connector.get(currency, bma.tx.sources, + req_args={'pubkey': pubkey}) log_stream("Found {0} sources".format(len(sources_data['sources']))) for i, s in enumerate(sources_data['sources']): diff --git a/src/sakia/data/processors/transactions.py b/src/sakia/data/processors/transactions.py index 17bf2b7161a996c948f6603e82c51f83e451c267..b5f9049962c4dbd10818891b87eca03696bf3743 100644 --- a/src/sakia/data/processors/transactions.py +++ b/src/sakia/data/processors/transactions.py @@ -104,10 +104,10 @@ class TransactionsProcessor: :param community: The community target of the transaction """ tx.sha_hash = txdoc.sha_hash - responses = await community.bma_access.broadcast(bma.tx.Process, + responses = await community.bma_access.broadcast(bma.tx.process, post_args={'transaction': txdoc.signed_raw()}) blockUID = community.network.current_blockUID - block = await community.bma_access.future_request(bma.blockchain.Block, + block = await community.bma_access.future_request(bma.blockchain.block, req_args={'number': blockUID.number}) signed_raw = "{0}{1}\n".format(block['raw'], block['signature']) block_doc = Block.from_signed_raw(signed_raw) diff --git a/src/sakia/data/processors/tx_lifecycle.py b/src/sakia/data/processors/tx_lifecycle.py index 49b10afe80204b0ba75c20598412986b5e5ab57f..df010d333926afce3c9f1a3d2eb588812408a876 100644 --- a/src/sakia/data/processors/tx_lifecycle.py +++ b/src/sakia/data/processors/tx_lifecycle.py @@ -2,6 +2,7 @@ import time from sakia.data.entities import Transaction from duniterpy.documents import Block + def _not_found_in_blockchain(tx, rollback, block, mediantime_target, mediantime_blocks): """ Check if the transaction could not be found in the blockchain diff --git a/src/sakia/data/repositories/blockchains.py b/src/sakia/data/repositories/blockchains.py index d0c9a8dfe161f702563686eaef047c1692d7ab6e..a8a0863dd8135cc4c94a1b283c13b430b11cef30 100644 --- a/src/sakia/data/repositories/blockchains.py +++ b/src/sakia/data/repositories/blockchains.py @@ -17,38 +17,36 @@ class BlockchainsRepo: Commit a blockchain to the database :param sakia.data.entities.Blockchain blockchain: the blockchain to commit """ - with self._conn: - blockchain_tuple = attr.astuple(blockchain.parameters) \ - + attr.astuple(blockchain, filter=attr.filters.exclude(Blockchain.parameters)) - values = ",".join(['?'] * len(blockchain_tuple)) - self._conn.execute("INSERT INTO blockchains VALUES ({0})".format(values), blockchain_tuple) + blockchain_tuple = attr.astuple(blockchain.parameters) \ + + attr.astuple(blockchain, filter=attr.filters.exclude(Blockchain.parameters)) + values = ",".join(['?'] * len(blockchain_tuple)) + self._conn.execute("INSERT INTO blockchains VALUES ({0})".format(values), blockchain_tuple) def update(self, blockchain): """ Update an existing blockchain in the database :param sakia.data.entities.Blockchain blockchain: the blockchain to update """ - with self._conn: - 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)) - self._conn.execute("""UPDATE blockchains SET - current_buid=?, - current_members_count=?, - current_mass=?, - median_time=?, - last_members_count=?, - last_ud=?, - last_ud_base=?, - last_ud_time=?, - previous_mass=?, - previous_members_count=?, - previous_ud=?, - previous_ud_base=?, - previous_ud_time=? - WHERE - currency=?""", - updated_fields + where_fields) + 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)) + self._conn.execute("""UPDATE blockchains SET + current_buid=?, + current_members_count=?, + current_mass=?, + median_time=?, + last_members_count=?, + last_ud=?, + last_ud_base=?, + last_ud_time=?, + previous_mass=?, + previous_members_count=?, + previous_ud=?, + previous_ud_base=?, + previous_ud_time=? + WHERE + currency=?""", + updated_fields + where_fields) def get_one(self, **search): """ @@ -56,19 +54,18 @@ class BlockchainsRepo: :param dict search: the criterions of the lookup :rtype: sakia.data.entities.Blockchain """ - with self._conn: - filters = [] - values = [] - for k, v in search.items(): - filters.append("{k}=?".format(k=k)) - values.append(v) + filters = [] + values = [] + for k, v in search.items(): + filters.append("{k}=?".format(k=k)) + values.append(v) - request = "SELECT * FROM blockchains WHERE {filters}".format(filters=" AND ".join(filters)) + request = "SELECT * FROM blockchains WHERE {filters}".format(filters=" AND ".join(filters)) - c = self._conn.execute(request, tuple(values)) - data = c.fetchone() - if data: - return Blockchain(BlockchainParameters(*data[:17]), *data[18:]) + c = self._conn.execute(request, tuple(values)) + data = c.fetchone() + if data: + return Blockchain(BlockchainParameters(*data[:17]), *data[18:]) def get_all(self, offset=0, limit=1000, sort_by="currency", sort_order="ASC", **search) -> List[Blockchain]: """ @@ -80,37 +77,36 @@ class BlockchainsRepo: :param dict search: the criterions of the lookup :rtype: [sakia.data.entities.Blockchain] """ - with self._conn: - filters = [] - values = [] - if search: - for k, v in search.items(): - filters.append("{k}=?".format(k=k)) - values.append(v) + filters = [] + values = [] + if search: + for k, v in search.items(): + filters.append("{k}=?".format(k=k)) + values.append(v) - 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)) - 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() - if datas: - return [Blockchain(BlockchainParameters(*data[:17]), *data[18:]) for data in datas] + 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)) + 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() + if datas: + return [Blockchain(BlockchainParameters(*data[:17]), *data[18:]) for data in datas] return [] def drop(self, blockchain): @@ -118,6 +114,5 @@ class BlockchainsRepo: Drop an existing blockchain from the database :param sakia.data.entities.Blockchain blockchain: the blockchain to update """ - with self._conn: - where_fields = attr.astuple(blockchain, filter=attr.filters.include(*BlockchainsRepo._primary_keys)) - self._conn.execute("DELETE FROM blockchains WHERE currency=?", where_fields) + where_fields = attr.astuple(blockchain, filter=attr.filters.include(*BlockchainsRepo._primary_keys)) + self._conn.execute("DELETE FROM blockchains WHERE currency=?", where_fields) diff --git a/src/sakia/data/repositories/certifications.py b/src/sakia/data/repositories/certifications.py index d4a5975b2ec2efcc925318f54e89c51117db3b02..87a5f7de3a64fc26f4314a69e284ae44b70672ff 100644 --- a/src/sakia/data/repositories/certifications.py +++ b/src/sakia/data/repositories/certifications.py @@ -16,29 +16,27 @@ class CertificationsRepo: Commit a certification to the database :param sakia.data.entities.Certification certification: the certification to commit """ - with self._conn: - certification_tuple = attr.astuple(certification) - values = ",".join(['?'] * len(certification_tuple)) - self._conn.execute("INSERT INTO certifications VALUES ({0})".format(values), certification_tuple) + certification_tuple = attr.astuple(certification) + values = ",".join(['?'] * len(certification_tuple)) + self._conn.execute("INSERT INTO certifications VALUES ({0})".format(values), certification_tuple) def update(self, certification): """ Update an existing certification in the database :param sakia.data.entities.Certification certification: the certification to update """ - with self._conn: - updated_fields = attr.astuple(certification, filter=attr.filters.exclude(*CertificationsRepo._primary_keys)) - where_fields = attr.astuple(certification, filter=attr.filters.include(*CertificationsRepo._primary_keys)) - self._conn.execute("""UPDATE certifications SET - ts=?, - signature=?, - written_on=? - WHERE - currency=? AND - certifier=? AND - certified=? AND - block=?""", - updated_fields + where_fields) + updated_fields = attr.astuple(certification, filter=attr.filters.exclude(*CertificationsRepo._primary_keys)) + where_fields = attr.astuple(certification, filter=attr.filters.include(*CertificationsRepo._primary_keys)) + self._conn.execute("""UPDATE certifications SET + ts=?, + signature=?, + written_on=? + WHERE + currency=? AND + certifier=? AND + certified=? AND + block=?""", + updated_fields + where_fields) def get_one(self, **search): """ @@ -46,19 +44,18 @@ class CertificationsRepo: :param dict search: the criterions of the lookup :rtype: sakia.data.entities.Certification """ - with self._conn: - filters = [] - values = [] - for k, v in search.items(): - filters.append("{k}=?".format(k=k)) - values.append(v) + filters = [] + values = [] + for k, v in search.items(): + filters.append("{k}=?".format(k=k)) + values.append(v) - request = "SELECT * FROM certifications WHERE {filters}".format(filters=" AND ".join(filters)) + request = "SELECT * FROM certifications WHERE {filters}".format(filters=" AND ".join(filters)) - c = self._conn.execute(request, tuple(values)) - data = c.fetchone() - if data: - return Certification(*data) + c = self._conn.execute(request, tuple(values)) + data = c.fetchone() + if data: + return Certification(*data) def get_all(self, **search): """ @@ -66,20 +63,19 @@ class CertificationsRepo: :param dict search: the criterions of the lookup :rtype: sakia.data.entities.Certification """ - with self._conn: - filters = [] - values = [] - for k, v in search.items(): - value = v - filters.append("{key} = ?".format(key=k)) - values.append(value) + filters = [] + values = [] + for k, v in search.items(): + value = v + filters.append("{key} = ?".format(key=k)) + values.append(value) - request = "SELECT * FROM certifications WHERE {filters}".format(filters=" AND ".join(filters)) + request = "SELECT * FROM certifications WHERE {filters}".format(filters=" AND ".join(filters)) - c = self._conn.execute(request, tuple(values)) - datas = c.fetchall() - if datas: - return [Certification(*data) for data in datas] + c = self._conn.execute(request, tuple(values)) + datas = c.fetchall() + if datas: + return [Certification(*data) for data in datas] return [] def drop(self, certification): @@ -87,11 +83,11 @@ class CertificationsRepo: Drop an existing certification from the database :param sakia.data.entities.Certification certification: the certification to update """ - with self._conn: - where_fields = attr.astuple(certification, filter=attr.filters.include(*CertificationsRepo._primary_keys)) - self._conn.execute("""DELETE FROM certifications - WHERE - currency=? AND - certifier=? AND - certified=? AND - block=?""", where_fields) + where_fields = attr.astuple(certification, filter=attr.filters.include(*CertificationsRepo._primary_keys)) + self._conn.execute("""DELETE FROM certifications + WHERE + currency=? AND + certifier=? AND + certified=? AND + block=?""", where_fields) + diff --git a/src/sakia/data/repositories/connections.py b/src/sakia/data/repositories/connections.py index 4c3cd757484804d34e580c5d4e86df0392e37cbc..148305cb9ce9cca617d876b1ac9ca54ee4470da6 100644 --- a/src/sakia/data/repositories/connections.py +++ b/src/sakia/data/repositories/connections.py @@ -16,10 +16,9 @@ class ConnectionsRepo: Commit a connection to the database :param sakia.data.entities.Connection connection: the connection to commit """ - with self._conn: - connection_tuple = attr.astuple(connection, filter=attr.filters.exclude(Connection.password)) - values = ",".join(['?'] * len(connection_tuple)) - self._conn.execute("INSERT INTO connections VALUES ({0})".format(values), connection_tuple) + connection_tuple = attr.astuple(connection, filter=attr.filters.exclude(Connection.password)) + values = ",".join(['?'] * len(connection_tuple)) + self._conn.execute("INSERT INTO connections VALUES ({0})".format(values), connection_tuple) def get_one(self, **search): """ @@ -27,19 +26,18 @@ class ConnectionsRepo: :param dict search: the criterions of the lookup :rtype: sakia.data.entities.Connection """ - with self._conn: - filters = [] - values = [] - for k, v in search.items(): - filters.append("{k}=?".format(k=k)) - values.append(v) + filters = [] + values = [] + for k, v in search.items(): + filters.append("{k}=?".format(k=k)) + values.append(v) - request = "SELECT * FROM connections WHERE {filters}".format(filters=" AND ".join(filters)) + request = "SELECT * FROM connections WHERE {filters}".format(filters=" AND ".join(filters)) - c = self._conn.execute(request, tuple(values)) - data = c.fetchone() - if data: - return Connection(*data) + c = self._conn.execute(request, tuple(values)) + data = c.fetchone() + if data: + return Connection(*data) def get_all(self, **search): """ @@ -47,22 +45,21 @@ class ConnectionsRepo: :param dict search: the criterions of the lookup :rtype: sakia.data.entities.Connection """ - with self._conn: - filters = [] - values = [] - for k, v in search.items(): - value = v - filters.append("{connection} = ?".format(connection=k)) - values.append(value) + filters = [] + values = [] + for k, v in search.items(): + value = v + filters.append("{connection} = ?".format(connection=k)) + values.append(value) - request = "SELECT * FROM connections" - if filters: - request += "WHERE {filters}".format(filters=" AND ".join(filters)) + request = "SELECT * FROM connections" + if filters: + request += "WHERE {filters}".format(filters=" AND ".join(filters)) - c = self._conn.execute(request, tuple(values)) - datas = c.fetchall() - if datas: - return [Connection(*data) for data in datas] + c = self._conn.execute(request, tuple(values)) + datas = c.fetchall() + if datas: + return [Connection(*data) for data in datas] return [] def get_currencies(self): @@ -71,12 +68,11 @@ class ConnectionsRepo: :param dict search: the criterions of the lookup :rtype: List[str] """ - with self._conn: - request = "SELECT DISTINCT currency FROM connections" - c = self._conn.execute(request) - datas = c.fetchall() - if datas: - return [data[0] for data in datas] + request = "SELECT DISTINCT currency FROM connections" + c = self._conn.execute(request) + datas = c.fetchall() + if datas: + return [data[0] for data in datas] return [] def drop(self, connection): @@ -84,9 +80,9 @@ class ConnectionsRepo: Drop an existing connection from the database :param sakia.data.entities.Connection connection: the connection to update """ - with self._conn: - where_fields = attr.astuple(connection, filter=attr.filters.include(*ConnectionsRepo._primary_connections)) - self._conn.execute("""DELETE FROM connections - WHERE - currency=? AND - pubkey=?""", where_fields) + where_fields = attr.astuple(connection, filter=attr.filters.include(*ConnectionsRepo._primary_connections)) + self._conn.execute("""DELETE FROM connections + WHERE + currency=? AND + pubkey=?""", where_fields) + diff --git a/src/sakia/data/repositories/identities.py b/src/sakia/data/repositories/identities.py index 10c229e6bf8f69989a7048b8254db826be879440..b27021566d6f8f2dc5ed3ff45d5b9293fbe6c38f 100644 --- a/src/sakia/data/repositories/identities.py +++ b/src/sakia/data/repositories/identities.py @@ -17,35 +17,33 @@ class IdentitiesRepo: Commit an identity to the database :param sakia.data.entities.Identity identity: the identity to commit """ - 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) + identity_tuple = attr.astuple(identity) + values = ",".join(['?'] * len(identity_tuple)) + self._conn.execute("INSERT INTO identities VALUES ({0})".format(values), identity_tuple) def update(self, identity): """ Update an existing identity in the database :param sakia.data.entities.Identity identity: the identity to update """ - 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_on=?, - revoked_on=?, - member=?, - ms_buid=?, - ms_timestamp=?, - ms_written_on=?, - ms_type=? - WHERE - currency=? AND - pubkey=? AND - uid=? AND - blockstamp=?""", updated_fields + where_fields - ) + 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_on=?, + revoked_on=?, + member=?, + ms_buid=?, + ms_timestamp=?, + ms_written_on=?, + ms_type=? + WHERE + currency=? AND + pubkey=? AND + uid=? AND + blockstamp=?""", updated_fields + where_fields + ) def get_one(self, **search): """ @@ -53,19 +51,18 @@ class IdentitiesRepo: :param dict search: the criterions of the lookup :rtype: sakia.data.entities.Identity """ - with self._conn: - filters = [] - values = [] - for k, v in search.items(): - filters.append("{k}=?".format(k=k)) - values.append(v) + filters = [] + values = [] + for k, v in search.items(): + filters.append("{k}=?".format(k=k)) + values.append(v) - request = "SELECT * FROM identities WHERE {filters}".format(filters=" AND ".join(filters)) + request = "SELECT * FROM identities WHERE {filters}".format(filters=" AND ".join(filters)) - c = self._conn.execute(request, tuple(values)) - data = c.fetchone() - if data: - return Identity(*data) + c = self._conn.execute(request, tuple(values)) + data = c.fetchone() + if data: + return Identity(*data) def get_written(self, offset=0, limit=1000, sort_by="currency", sort_order="ASC", **search): """ @@ -75,30 +72,29 @@ class IdentitiesRepo: :param dict search: the criterions of the lookup :rtype: List[sakia.data.entities.Identity] """ - with self._conn: - filters = [] - values = [] - for k, v in search.items(): - if isinstance(v, bool): - v = int(v) - filters.append("{k}=?".format(k=k)) - values.append(v) - - request = """SELECT * FROM identities WHERE {filters} - AND ms_written_on!="{empty_buid}" - ORDER BY {sort_by} {sort_order} - LIMIT {limit} OFFSET {offset}""" \ - .format(filters=" AND ".join(filters), - empty_buid=str(BlockUID.empty()), - offset=offset, - limit=limit, - sort_by=sort_by, - sort_order=sort_order - ) - c = self._conn.execute(request, tuple(values)) - datas = c.fetchall() - if datas: - return [Identity(*data) for data in datas] + filters = [] + values = [] + for k, v in search.items(): + if isinstance(v, bool): + v = int(v) + filters.append("{k}=?".format(k=k)) + values.append(v) + + request = """SELECT * FROM identities WHERE {filters} + AND ms_written_on!="{empty_buid}" + ORDER BY {sort_by} {sort_order} + LIMIT {limit} OFFSET {offset}""" \ + .format(filters=" AND ".join(filters), + empty_buid=str(BlockUID.empty()), + offset=offset, + limit=limit, + sort_by=sort_by, + sort_order=sort_order + ) + c = self._conn.execute(request, tuple(values)) + datas = c.fetchall() + if datas: + return [Identity(*data) for data in datas] return [] def get_all(self, **search): @@ -107,21 +103,20 @@ class IdentitiesRepo: :param dict search: the criterions of the lookup :rtype: sakia.data.entities.Identity """ - with self._conn: - filters = [] - values = [] - for k, v in search.items(): - if isinstance(v, bool): - v = int(v) - filters.append("{k}=?".format(k=k)) - values.append(v) - - request = "SELECT * FROM identities WHERE {filters}".format(filters=" AND ".join(filters)) - - c = self._conn.execute(request, tuple(values)) - datas = c.fetchall() - if datas: - return [Identity(*data) for data in datas] + filters = [] + values = [] + for k, v in search.items(): + if isinstance(v, bool): + v = int(v) + filters.append("{k}=?".format(k=k)) + values.append(v) + + request = "SELECT * FROM identities WHERE {filters}".format(filters=" AND ".join(filters)) + + c = self._conn.execute(request, tuple(values)) + datas = c.fetchall() + if datas: + return [Identity(*data) for data in datas] return [] def find_all(self, currency, text): @@ -130,13 +125,12 @@ class IdentitiesRepo: :param dict search: the criterions of the lookup :rtype: sakia.data.entities.Identity """ - with self._conn: - request = "SELECT * FROM identities WHERE currency=? AND (UID LIKE ? or PUBKEY LIKE ?)" + request = "SELECT * FROM identities WHERE currency=? AND (UID LIKE ? or PUBKEY LIKE ?)" - c = self._conn.execute(request, (currency, "%{0}%".format(text), "%{0}%".format(text))) - datas = c.fetchall() - if datas: - return [Identity(*data) for data in datas] + c = self._conn.execute(request, (currency, "%{0}%".format(text), "%{0}%".format(text))) + datas = c.fetchall() + if datas: + return [Identity(*data) for data in datas] return [] def drop(self, identity): @@ -144,10 +138,10 @@ class IdentitiesRepo: Drop an existing identity from the database :param sakia.data.entities.Identity identity: the identity to update """ - 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) + 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) + diff --git a/src/sakia/data/repositories/meta.py b/src/sakia/data/repositories/meta.py index 826f2959d26e07cc36dc478a4c201f62e041c9c3..5dac0e56d8bf156d02913abf91d0e3ede2e739e8 100644 --- a/src/sakia/data/repositories/meta.py +++ b/src/sakia/data/repositories/meta.py @@ -14,7 +14,8 @@ from .sources import SourcesRepo @attr.s(frozen=True) class SakiaDatabase: - """The repository for Identities entities. + """ + This is Sakia unique SQLite database. """ conn = attr.ib() # :type sqlite3.Connection connections_repo = attr.ib(default=None) @@ -93,3 +94,6 @@ class SakiaDatabase: else: self.conn.execute("INSERT INTO meta VALUES (1, 0)") return 0 + + def commit(self): + self.conn.commit() diff --git a/src/sakia/data/repositories/nodes.py b/src/sakia/data/repositories/nodes.py index 38117b971c494adfde6f66e552c74ddb55f6fd12..ebc92b3e9741004707df7b563ef3dd47ef5f432b 100644 --- a/src/sakia/data/repositories/nodes.py +++ b/src/sakia/data/repositories/nodes.py @@ -15,42 +15,40 @@ class NodesRepo: Commit a node to the database :param sakia.data.entities.Node node: the node to commit """ - with self._conn: - node_tuple = attr.astuple(node, tuple_factory=list) - node_tuple[2] = "\n".join([str(n) for n in node_tuple[2]]) - node_tuple[12] = "\n".join([str(n) for n in node_tuple[11]]) - values = ",".join(['?'] * len(node_tuple)) - self._conn.execute("INSERT INTO nodes VALUES ({0})".format(values), node_tuple) + node_tuple = attr.astuple(node, tuple_factory=list) + node_tuple[2] = "\n".join([str(n) for n in node_tuple[2]]) + node_tuple[12] = "\n".join([str(n) for n in node_tuple[11]]) + values = ",".join(['?'] * len(node_tuple)) + self._conn.execute("INSERT INTO nodes VALUES ({0})".format(values), node_tuple) def update(self, node): """ Update an existing node in the database :param sakia.data.entities.Node node: the node to update """ - with self._conn: - updated_fields = attr.astuple(node, tuple_factory=list, - filter=attr.filters.exclude(*NodesRepo._primary_keys)) - updated_fields[0] = "\n".join([str(n) for n in updated_fields[0]]) - updated_fields[10] = "\n".join([str(n) for n in updated_fields[9]]) - where_fields = attr.astuple(node, tuple_factory=list, - filter=attr.filters.include(*NodesRepo._primary_keys)) - self._conn.execute("""UPDATE nodes SET - endpoints=?, - peer_buid=?, - uid=?, - current_buid=?, - current_ts=?, - previous_buid=?, - state=?, - software=?, - version=?, - merkle_peers_root=?, - merkle_peers_leaves=?, - root=? - WHERE - currency=? AND - pubkey=?""", - updated_fields + where_fields) + updated_fields = attr.astuple(node, tuple_factory=list, + filter=attr.filters.exclude(*NodesRepo._primary_keys)) + updated_fields[0] = "\n".join([str(n) for n in updated_fields[0]]) + updated_fields[10] = "\n".join([str(n) for n in updated_fields[9]]) + where_fields = attr.astuple(node, tuple_factory=list, + filter=attr.filters.include(*NodesRepo._primary_keys)) + self._conn.execute("""UPDATE nodes SET + endpoints=?, + peer_buid=?, + uid=?, + current_buid=?, + current_ts=?, + previous_buid=?, + state=?, + software=?, + version=?, + merkle_peers_root=?, + merkle_peers_leaves=?, + root=? + WHERE + currency=? AND + pubkey=?""", + updated_fields + where_fields) def get_one(self, **search): """ @@ -58,21 +56,20 @@ class NodesRepo: :param dict search: the criterions of the lookup :rtype: sakia.data.entities.Node """ - with self._conn: - filters = [] - values = [] - for k, v in search.items(): - if isinstance(v, bool): - v = int(v) - filters.append("{k}=?".format(k=k)) - values.append(v) + filters = [] + values = [] + for k, v in search.items(): + if isinstance(v, bool): + v = int(v) + filters.append("{k}=?".format(k=k)) + values.append(v) - request = "SELECT * FROM nodes WHERE {filters}".format(filters=" AND ".join(filters)) + request = "SELECT * FROM nodes WHERE {filters}".format(filters=" AND ".join(filters)) - c = self._conn.execute(request, tuple(values)) - data = c.fetchone() - if data: - return Node(*data) + c = self._conn.execute(request, tuple(values)) + data = c.fetchone() + if data: + return Node(*data) def get_all(self, **search): """ @@ -80,23 +77,22 @@ class NodesRepo: :param dict search: the criterions of the lookup :rtype: sakia.data.entities.Node """ - with self._conn: - filters = [] - values = [] - for k, v in search.items(): - if isinstance(v, bool): - value = int(v) - else: - value = v - filters.append("{key} = ?".format(key=k)) - values.append(value) + filters = [] + values = [] + for k, v in search.items(): + if isinstance(v, bool): + value = int(v) + else: + value = v + filters.append("{key} = ?".format(key=k)) + values.append(value) - request = "SELECT * FROM nodes WHERE {filters}".format(filters=" AND ".join(filters)) + request = "SELECT * FROM nodes WHERE {filters}".format(filters=" AND ".join(filters)) - c = self._conn.execute(request, tuple(values)) - datas = c.fetchall() - if datas: - return [Node(*data) for data in datas] + c = self._conn.execute(request, tuple(values)) + datas = c.fetchall() + if datas: + return [Node(*data) for data in datas] return [] def drop(self, node): @@ -104,8 +100,7 @@ class NodesRepo: Drop an existing node from the database :param sakia.data.entities.Node node: the node to update """ - with self._conn: - where_fields = attr.astuple(node, filter=attr.filters.include(*NodesRepo._primary_keys)) - self._conn.execute("""DELETE FROM nodes - WHERE - currency=? AND pubkey=?""", where_fields) + where_fields = attr.astuple(node, filter=attr.filters.include(*NodesRepo._primary_keys)) + self._conn.execute("""DELETE FROM nodes + WHERE + currency=? AND pubkey=?""", where_fields) diff --git a/src/sakia/data/repositories/sources.py b/src/sakia/data/repositories/sources.py index 715e1f2b5b2035c9ed1fa08540c8f765ddb486eb..93c08dd4adce4b39fee857abd75788125f5e5a3f 100644 --- a/src/sakia/data/repositories/sources.py +++ b/src/sakia/data/repositories/sources.py @@ -15,10 +15,9 @@ class SourcesRepo: 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) + 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): """ @@ -26,19 +25,18 @@ class SourcesRepo: :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) + 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)) + 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) + c = self._conn.execute(request, tuple(values)) + data = c.fetchone() + if data: + return Source(*data) def get_all(self, **search): """ @@ -46,20 +44,19 @@ class SourcesRepo: :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) + 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)) + 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] + c = self._conn.execute(request, tuple(values)) + datas = c.fetchall() + if datas: + return [Source(*data) for data in datas] return [] def drop(self, source): @@ -67,8 +64,8 @@ class SourcesRepo: 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) + where_fields = attr.astuple(source, filter=attr.filters.include(*SourcesRepo._primary_keys)) + self._conn.execute("""DELETE FROM sources + WHERE + identifier=?""", where_fields) + diff --git a/src/sakia/data/repositories/transactions.py b/src/sakia/data/repositories/transactions.py index 3457db6602f87ad6c50dfb8c8eddd862f1d711fd..17ac139f27fde1edaf8c020d2dd42cd10732988e 100644 --- a/src/sakia/data/repositories/transactions.py +++ b/src/sakia/data/repositories/transactions.py @@ -15,35 +15,33 @@ class TransactionsRepo: Commit a transaction to the database :param sakia.data.entities.Transaction transaction: the transaction to commit """ - with self._conn: - transaction_tuple = attr.astuple(transaction) - values = ",".join(['?'] * len(transaction_tuple)) - self._conn.execute("INSERT INTO transactions VALUES ({0})".format(values), transaction_tuple) + transaction_tuple = attr.astuple(transaction) + values = ",".join(['?'] * len(transaction_tuple)) + self._conn.execute("INSERT INTO transactions VALUES ({0})".format(values), transaction_tuple) def update(self, transaction): """ Update an existing transaction in the database :param sakia.data.entities.Transaction transaction: the transaction to update """ - with self._conn: - updated_fields = attr.astuple(transaction, filter=attr.filters.exclude(*TransactionsRepo._primary_keys)) - where_fields = attr.astuple(transaction, filter=attr.filters.include(*TransactionsRepo._primary_keys)) - self._conn.execute("""UPDATE transactions SET - currency=?, - written_on=?, - blockstamp=?, - ts=?, - signature=?, - issuer = ?, - receiver = ?, - amount = ?, - amountbase = ?, - comment = ?, - txid = ?, - state = ? - WHERE - sha_hash=?""", - updated_fields + where_fields) + updated_fields = attr.astuple(transaction, filter=attr.filters.exclude(*TransactionsRepo._primary_keys)) + where_fields = attr.astuple(transaction, filter=attr.filters.include(*TransactionsRepo._primary_keys)) + self._conn.execute("""UPDATE transactions SET + currency=?, + written_on=?, + blockstamp=?, + ts=?, + signature=?, + issuer = ?, + receiver = ?, + amount = ?, + amountbase = ?, + comment = ?, + txid = ?, + state = ? + WHERE + sha_hash=?""", + updated_fields + where_fields) def get_one(self, **search): """ @@ -51,19 +49,18 @@ class TransactionsRepo: :param dict search: the criterions of the lookup :rtype: sakia.data.entities.Transaction """ - with self._conn: - filters = [] - values = [] - for k, v in search.items(): - filters.append("{k}=?".format(k=k)) - values.append(v) + filters = [] + values = [] + for k, v in search.items(): + filters.append("{k}=?".format(k=k)) + values.append(v) - request = "SELECT * FROM transactions WHERE {filters}".format(filters=" AND ".join(filters)) + request = "SELECT * FROM transactions WHERE {filters}".format(filters=" AND ".join(filters)) - c = self._conn.execute(request, tuple(values)) - data = c.fetchone() - if data: - return Transaction(*data) + c = self._conn.execute(request, tuple(values)) + data = c.fetchone() + if data: + return Transaction(*data) def get_all(self, **search): """ @@ -71,20 +68,19 @@ class TransactionsRepo: :param dict search: the criterions of the lookup :rtype: sakia.data.entities.Transaction """ - with self._conn: - filters = [] - values = [] - for k, v in search.items(): - value = v - filters.append("{key} = ?".format(key=k)) - values.append(value) + filters = [] + values = [] + for k, v in search.items(): + value = v + filters.append("{key} = ?".format(key=k)) + values.append(value) - request = "SELECT * FROM transactions WHERE {filters}".format(filters=" AND ".join(filters)) + request = "SELECT * FROM transactions WHERE {filters}".format(filters=" AND ".join(filters)) - c = self._conn.execute(request, tuple(values)) - datas = c.fetchall() - if datas: - return [Transaction(*data) for data in datas] + c = self._conn.execute(request, tuple(values)) + datas = c.fetchall() + if datas: + return [Transaction(*data) for data in datas] return [] def get_transfers(self, currency, pubkey, offset=0, limit=1000, sort_by="currency", sort_order="ASC"): @@ -94,20 +90,19 @@ class TransactionsRepo: :param str pubkey: the criterions of the lookup :rtype: List[sakia.data.entities.Transaction] """ - with self._conn: - request = """SELECT * FROM transactions - WHERE currency=? AND (issuer=? or receiver=?) - 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, (currency, pubkey, pubkey)) - datas = c.fetchall() - if datas: - return [Transaction(*data) for data in datas] + request = """SELECT * FROM transactions + WHERE currency=? AND (issuer=? or receiver=?) + 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, (currency, pubkey, pubkey)) + datas = c.fetchall() + if datas: + return [Transaction(*data) for data in datas] return [] def drop(self, transaction): @@ -115,8 +110,7 @@ class TransactionsRepo: Drop an existing transaction from the database :param sakia.data.entities.Transaction transaction: the transaction to update """ - with self._conn: - where_fields = attr.astuple(transaction, filter=attr.filters.include(*TransactionsRepo._primary_keys)) - self._conn.execute("""DELETE FROM transactions - WHERE - sha_hash=?""", where_fields) + where_fields = attr.astuple(transaction, filter=attr.filters.include(*TransactionsRepo._primary_keys)) + self._conn.execute("""DELETE FROM transactions + WHERE + sha_hash=?""", where_fields) diff --git a/src/sakia/gui/dialogs/connection_cfg/controller.py b/src/sakia/gui/dialogs/connection_cfg/controller.py index fb81e05a37f915620a921356103824db7034eb50..ab797579dc11d6f6ae60114ac1e9356c6fa016a5 100644 --- a/src/sakia/gui/dialogs/connection_cfg/controller.py +++ b/src/sakia/gui/dialogs/connection_cfg/controller.py @@ -1,8 +1,6 @@ import asyncio import logging -from PyQt5.QtGui import QCursor -from PyQt5.QtWidgets import QDialog, QApplication, QMenu from aiohttp.errors import DisconnectedError, ClientError, TimeoutError from duniterpy.documents import MalformedDocumentError @@ -142,7 +140,7 @@ class ConnectionConfigController(ComponentController): self.view.stacked_pages.setCurrentWidget(self.view.page_connection) connection_identity = await self.step_key - self.model.commit_connection() + self.model.insert_or_update_connection() self.view.stacked_pages.setCurrentWidget(self.view.page_services) self.view.progress_bar.setValue(0) self.view.progress_bar.setMaximum(3) @@ -151,7 +149,7 @@ class ConnectionConfigController(ComponentController): if mode in (ConnectionConfigController.REGISTER, ConnectionConfigController.CONNECT): self.view.stream_log("Saving identity...") - self.model.commit_identity(connection_identity) + self.model.insert_or_update_identity(connection_identity) self.view.stream_log("Initializing identity informations...") await self.model.initialize_identity(connection_identity, log_stream=self.view.stream_log) self.view.stream_log("Initializing certifications informations...") @@ -172,6 +170,7 @@ class ConnectionConfigController(ComponentController): await self.model.initialize_sources(self.view.stream_log) self._logger.debug("Validate changes") + self.model.app.db.commit() self.accept() def check_key(self): diff --git a/src/sakia/gui/dialogs/connection_cfg/model.py b/src/sakia/gui/dialogs/connection_cfg/model.py index e3937962dba0673f55618006ae7532de28ecd1b5..4d85c955bbe46715d724e0053e7990087a20dab0 100644 --- a/src/sakia/gui/dialogs/connection_cfg/model.py +++ b/src/sakia/gui/dialogs/connection_cfg/model.py @@ -50,12 +50,12 @@ class ConnectionConfigModel(ComponentModel): self.connection.salt = salt self.connection.pubkey = SigningKey(self.connection.salt, password).pubkey - def commit_connection(self): + def insert_or_update_connection(self): ConnectionsProcessor(self.app.db.connections_repo).commit_connection(self.connection) NodesProcessor(self.app.db.nodes_repo).commit_node(self.node_connector.node) - def commit_identity(self, identity): - self.identities_processor.commit_identity(identity) + def insert_or_update_identity(self, identity): + self.identities_processor.insert_or_update_identity(identity) async def initialize_blockchain(self, log_stream): """ @@ -151,7 +151,7 @@ class ConnectionConfigModel(ComponentModel): async def execute_requests(parsers, search): tries = 0 - request = bma.wot.CertifiersOf + request = bma.wot.certifiers_of nonlocal registered for endpoint in [e for e in self.node_connector.node.endpoints if isinstance(e, BMAEndpoint)]: if not registered[0] and not registered[2]: @@ -163,8 +163,8 @@ class ConnectionConfigModel(ComponentModel): except errors.DuniterError as e: if e.ucode in (errors.NO_MEMBER_MATCHING_PUB_OR_UID, e.ucode == errors.NO_MATCHING_IDENTITY): - if request == bma.wot.CertifiersOf: - request = bma.wot.Lookup + if request == bma.wot.certifiers_of: + request = bma.wot.lookup tries = 0 else: tries += 1 @@ -180,8 +180,8 @@ class ConnectionConfigModel(ComponentModel): # We execute search based on pubkey # And look for account UID uid_parsers = { - bma.wot.CertifiersOf: _parse_uid_certifiers, - bma.wot.Lookup: _parse_uid_lookup + bma.wot.certifiers_of: _parse_uid_certifiers, + bma.wot.lookup: _parse_uid_lookup } await execute_requests(uid_parsers, identity.pubkey) @@ -189,8 +189,8 @@ class ConnectionConfigModel(ComponentModel): # We look for the uid and check for the pubkey if not registered[0] and not registered[2]: pubkey_parsers = { - bma.wot.CertifiersOf: _parse_pubkey_certifiers, - bma.wot.Lookup: _parse_pubkey_lookup + bma.wot.certifiers_of: _parse_pubkey_certifiers, + bma.wot.lookup: _parse_pubkey_lookup } await execute_requests(pubkey_parsers, identity.uid) diff --git a/src/sakia/services/blockchain.py b/src/sakia/services/blockchain.py index 7b2cede4cab6e0b8c75d418375a55667331b3700..9d8264ee9e447e7322767eec413ef80c3ac20fb1 100644 --- a/src/sakia/services/blockchain.py +++ b/src/sakia/services/blockchain.py @@ -1,5 +1,4 @@ from PyQt5.QtCore import QObject -from duniterpy.api import bma import math import logging @@ -9,10 +8,11 @@ class BlockchainService(QObject): Blockchain service is managing new blocks received to update data locally """ - def __init__(self, currency, blockchain_processor, bma_connector, identities_service, transactions_service): + def __init__(self, app, currency, blockchain_processor, bma_connector, identities_service, transactions_service): """ Constructor the identities service + :param sakia.app.Application app: Sakia application :param str currency: The currency name of the community :param sakia.data.processors.BlockchainProcessor blockchain_processor: the blockchain processor for given currency :param sakia.data.connectors.BmaConnector bma_connector: The connector to BMA API @@ -20,6 +20,7 @@ class BlockchainService(QObject): :param sakia.services.TransactionsService transactions_service: The transactions service """ super().__init__() + self.app = app self._blockchain_processor = blockchain_processor self._bma_connector = bma_connector self.currency = currency @@ -36,6 +37,7 @@ class BlockchainService(QObject): blocks = await self._blockchain_processor.blocks(with_identities + with_money, self.currency) await self._identities_service.handle_new_blocks(blocks) await self._transactions_service.handle_new_blocks(blocks) + self.app.db.commit() def current_buid(self): return self._blockchain_processor.current_buid(self.currency) diff --git a/src/sakia/services/identities.py b/src/sakia/services/identities.py index d07451b6f0e3ca24efb546b8f44d6357641c3179..f9e42f26e91993ff76a09bce54632aacf4a23476 100644 --- a/src/sakia/services/identities.py +++ b/src/sakia/services/identities.py @@ -74,7 +74,7 @@ class IdentitiesService(QObject): """ if not identity.written_on: try: - search = await self._bma_connector.get(self.currency, bma.blockchain.Membership, + search = await self._bma_connector.get(self.currency, bma.blockchain.membership, {'search': self.pubkey}) blockstamp = BlockUID.empty() membership_data = None @@ -89,7 +89,7 @@ class IdentitiesService(QObject): identity.membership_type = ms["type"] identity.membership_written_on = ms["written"] await self.refresh_requirements(identity) - self._identities_processor.commit_identity(identity) + self._identities_processor.insert_or_update_identity(identity) except errors.DuniterError as e: logging.debug(str(e)) except NoPeerAvailable as e: @@ -104,15 +104,17 @@ class IdentitiesService(QObject): if not identity.written_on: try: data = await self._bma_connector.get(self.currency, bma.wot.certifiers_of, {'search': identity.pubkey}) - for certified_data in data['certifications']: - cert = Certification(self.currency, data["pubkey"], - certified_data["pubkey"], certified_data["sigDate"]) - cert.block = certified_data["cert_time"]["number"] - cert.timestamp = certified_data["cert_time"]["medianTime"] - if certified_data['written']: - cert.written_on = BlockUID(certified_data['written']['number'], - certified_data['written']['hash']) - self._certs_processor.commit_certification(cert) + for certifier_data in data['certifications']: + cert = Certification(currency=self.currency, + certified=data["pubkey"], + certifier=certifier_data["pubkey"], + block=certifier_data["cert_time"]["block"], + timestamp=certifier_data["cert_time"]["medianTime"], + signature=certifier_data['signature']) + if certifier_data['written']: + cert.written_on = BlockUID(certifier_data['written']['number'], + certifier_data['written']['hash']) + self._certs_processor.insert_or_update_certification(cert) except errors.DuniterError as e: if e.ucode in (errors.NO_MATCHING_IDENTITY, errors.NO_MEMBER_MATCHING_PUB_OR_UID): logging.debug("Certified by error : {0}".format(str(e))) @@ -129,14 +131,16 @@ class IdentitiesService(QObject): try: data = await self._bma_connector.get(self.currency, bma.wot.certified_by, {'search': identity.pubkey}) for certified_data in data['certifications']: - cert = Certification(self.currency, data["pubkey"], - certified_data["pubkey"], certified_data["sigDate"]) - cert.block = certified_data["cert_time"]["number"] - cert.timestamp = certified_data["cert_time"]["medianTime"] + cert = Certification(currency=self.currency, + certifier=data["pubkey"], + certified=certified_data["pubkey"], + block=certified_data["cert_time"]["block"], + timestamp=certified_data["cert_time"]["medianTime"], + signature=certified_data['signature']) if certified_data['written']: cert.written_on = BlockUID(certified_data['written']['number'], certified_data['written']['hash']) - self._certs_processor.commit_certification(cert) + self._certs_processor.insert_or_update_certification(cert) except errors.DuniterError as e: if e.ucode in (errors.NO_MATCHING_IDENTITY, errors.NO_MEMBER_MATCHING_PUB_OR_UID): logging.debug("Certified by error : {0}".format(str(e))) @@ -178,7 +182,7 @@ class IdentitiesService(QObject): written.membership_written_on = block.blockUID written.membership_type = "IN" written.membership_buid = ms.membership_ts - self._identities_processor.commit_identity(written) + self._identities_processor.insert_or_update_identity(written) # If the identity was not member # it can become one if not written.member: @@ -192,7 +196,7 @@ class IdentitiesService(QObject): written.membership_written_on = block.blockUID written.membership_type = "OUT" written.membership_buid = ms.membership_ts - self._identities_processor.commit_identity(written) + self._identities_processor.insert_or_update_identity(written) # If the identity was not member # it can stop to be one if not written.member: @@ -233,12 +237,12 @@ class IdentitiesService(QObject): req_args={'search': identity.pubkey}) identity_data = requirements['identities'][0] identity.uid = identity_data["uid"] - identity.blockstamp = identity["meta"]["timestamp"] - identity.member = identity["membershipExpiresIn"] > 0 and identity["outdistanced"] is False + identity.blockstamp = identity_data["meta"]["timestamp"] + identity.member = identity_data["membershipExpiresIn"] > 0 and identity_data["outdistanced"] is False median_time = self._blockchain_processor.time(self.currency) expiration_time = self._blockchain_processor.parameters(self.currency).ms_validity - identity.membership_timestamp = median_time - (expiration_time - identity["membershipExpiresIn"]) - self._identities_processor.commit_identity(identity) + identity.membership_timestamp = median_time - (expiration_time - identity_data["membershipExpiresIn"]) + self._identities_processor.insert_or_update_identity(identity) except NoPeerAvailable as e: self._logger.debug(str(e)) diff --git a/src/sakia/services/network.py b/src/sakia/services/network.py index 9725b3c3b8327cbd9411e011e51ca3f221d51196..46b7502a324397fa3aeb31a58c6e6a2d55d259b6 100644 --- a/src/sakia/services/network.py +++ b/src/sakia/services/network.py @@ -21,10 +21,11 @@ class NetworkService(QObject): nodes_changed = pyqtSignal() root_nodes_changed = pyqtSignal() - def __init__(self, currency, node_processor, connectors, session, blockchain_service): + def __init__(self, app, currency, node_processor, connectors, session, blockchain_service): """ Constructor of a network + :param sakia.app.Application app: The application :param str currency: The currency name of the community :param sakia.data.processors.NodesProcessor node_processor: the nodes processor for given currency :param list connectors: The connectors to nodes of the network @@ -32,6 +33,7 @@ class NetworkService(QObject): :param sakia.services.BlockchainService blockchain_service: the blockchain service """ super().__init__() + self._app = app self._logger = logging.getLogger('sakia') self._processor = node_processor self._connectors = [] @@ -62,10 +64,11 @@ class NetworkService(QObject): return network @classmethod - def load(cls, currency, node_processor, blockchain_service): + def load(cls, app, currency, node_processor, blockchain_service): """ Create a new network with all known nodes + :param sakia.app.Application app: Sakia application :param str currency: The currency of this service :param sakia.data.processors.NodeProcessor node_processor: The nodes processor :return: @@ -74,7 +77,7 @@ class NetworkService(QObject): session = aiohttp.ClientSession() for node in node_processor.nodes(currency): connectors.append(NodeConnector(node, session)) - network = cls(currency, node_processor, connectors, session, blockchain_service) + network = cls(app, currency, node_processor, connectors, session, blockchain_service) return network def start_coroutines(self): @@ -213,6 +216,8 @@ class NetworkService(QObject): self._logger.debug(str(e)) else: self._processor.update_peer(self.currency, peer) + + self._app.db.commit() except IndexError: await asyncio.sleep(2) diff --git a/src/sakia/services/transactions.py b/src/sakia/services/transactions.py index f45569ce6a1c65d970a06e1e37824c305e0918a9..a3365470d53b36c901dc160dff8dbdd24c6f9360 100644 --- a/src/sakia/services/transactions.py +++ b/src/sakia/services/transactions.py @@ -31,7 +31,6 @@ class TransactionsService(QObject): async def _parse_transaction(self, tx_doc, blockUID, mediantime, txid): """ Parse a transaction - :param sakia.core.Community community: The community :param duniterpy.documents.Transaction tx_doc: The tx json data :param duniterpy.documents.BlockUID blockUID: The block id where we found the tx :param int mediantime: Median time on the network