diff --git a/src/sakia/data/processors/dividends.py b/src/sakia/data/processors/dividends.py index 7c5b44cfe6fcbfab4676ea31ed7b1e8b861288f6..abe284a25db5b8c46dca968eaa015e85c977d9c9 100644 --- a/src/sakia/data/processors/dividends.py +++ b/src/sakia/data/processors/dividends.py @@ -3,9 +3,8 @@ import logging from ..entities import Dividend from .nodes import NodesProcessor from ..connectors import BmaConnector -from duniterpy.api import bma, errors +from duniterpy.api import bma from duniterpy.documents import Transaction -import asyncio import sqlite3 @@ -31,8 +30,10 @@ class DividendsProcessor: def commit(self, dividend): try: self._repo.insert(dividend) + return True except sqlite3.IntegrityError: self._logger.debug("Dividend already in db") + return False async def initialize_dividends(self, identity, transactions, log_stream): """ diff --git a/src/sakia/data/repositories/meta.sql b/src/sakia/data/repositories/meta.sql index 99c5c898197ddfc16a10c6e6a20342f91ad02e6d..96e87dd3d4727b087e72c58b7e8cdf2296df6916 100644 --- a/src/sakia/data/repositories/meta.sql +++ b/src/sakia/data/repositories/meta.sql @@ -34,7 +34,6 @@ CREATE TABLE IF NOT EXISTS blockchains ( median_time_blocks INT, avg_gen_time INT, dt_diff_eval INT, - blocks_rot INT, percent_rot FLOAT(1, 6), current_buid INT, current_members_count INT, diff --git a/src/sakia/services/blockchain.py b/src/sakia/services/blockchain.py index 239b3a1757d9ae259f912b6ed974fd7188b9d7e1..b05dfd35467d2020920816eb2d01a613d4bf28b2 100644 --- a/src/sakia/services/blockchain.py +++ b/src/sakia/services/blockchain.py @@ -41,19 +41,19 @@ class BlockchainService(QObject): with_money = await self._blockchain_processor.new_blocks_with_money(self.currency) blocks = await self._blockchain_processor.blocks(with_identities + with_money + [network_blockstamp.number], self.currency) - identities = await self._identities_service.handle_new_blocks(blocks) - transfers_changed, new_transfers, new_dividends = self._transactions_service.handle_new_blocks(blocks) - self._blockchain_processor.handle_new_blocks(self.currency, blocks) - self.app.db.commit() - for tx in transfers_changed: - self.app.transaction_state_changed.emit(tx) - for tx in new_transfers: - self.app.new_transfer.emit(tx) - for ud in new_dividends: - self.app.new_dividend.emit(ud) - - for idty in identities: - self.app.identity_changed.emit(idty) + if len(blocks) > 0: + identities = await self._identities_service.handle_new_blocks(blocks) + changed_tx, new_tx, new_dividends = await self._transactions_service.handle_new_blocks(blocks) + self._blockchain_processor.handle_new_blocks(self.currency, blocks) + self.app.db.commit() + for tx in changed_tx: + self.app.transaction_state_changed.emit(tx) + for tx in new_tx: + self.app.new_transfer.emit(tx) + for ud in new_dividends: + self.app.new_dividend.emit(ud) + for idty in identities: + self.app.identity_changed.emit(idty) except (NoPeerAvailable, DuniterError) as e: self._logger.debug(str(e)) diff --git a/src/sakia/services/transactions.py b/src/sakia/services/transactions.py index 32f720c2869df2696c0a3daeb95ade91eb61a673..dafae7b738cfb431ccd2829ec4efd66eafb15cef 100644 --- a/src/sakia/services/transactions.py +++ b/src/sakia/services/transactions.py @@ -1,8 +1,10 @@ from PyQt5.QtCore import QObject from sakia.data.entities.transaction import parse_transaction_doc -from duniterpy.documents import SimpleTransaction +from duniterpy.documents import Transaction as TransactionDoc from sakia.data.entities import Dividend +from duniterpy.api import bma import logging +import sqlite3 class TransactionsService(QObject): @@ -40,7 +42,6 @@ class TransactionsService(QObject): """ transfers_changed = [] new_transfers = [] - new_dividends = [] for tx in [t for t in self._transactions_processor.awaiting(self.currency)]: if self._transactions_processor.run_state_transitions(tx, block_doc): transfers_changed.append(tx) @@ -50,16 +51,6 @@ class TransactionsService(QObject): and SimpleTransaction.is_simple(t)] connections_pubkeys = [c.pubkey for c in self._connections_processor.connections_to(self.currency)] for pubkey in connections_pubkeys: - if block_doc.ud: - dividend = Dividend(currency=self.currency, - pubkey=pubkey, - block_number=block_doc.number, - timestamp=block_doc.mediantime, - amount=block_doc.ud, - base=block_doc.unit_base) - new_dividends.append(dividend) - self._dividends_processor.commit(dividend) - for (i, tx_doc) in enumerate(new_transactions): tx = parse_transaction_doc(tx_doc, pubkey, block_doc.blockUID.number, block_doc.mediantime, txid+i) if tx: @@ -68,9 +59,9 @@ class TransactionsService(QObject): else: logging.debug("Error during transfer parsing") - return transfers_changed, new_transfers, new_dividends + return transfers_changed, new_transfers - def handle_new_blocks(self, blocks): + async def handle_new_blocks(self, blocks): """ Refresh last transactions @@ -79,16 +70,57 @@ class TransactionsService(QObject): self._logger.debug("Refresh transactions") transfers_changed = [] new_transfers = [] - new_dividends = [] txid = 0 for block in blocks: - changes, new_tx, new_ud = self._parse_block(block, txid) + changes, new_tx = self._parse_block(block, txid) txid += len(new_tx) transfers_changed += changes new_transfers += new_tx - new_dividends += new_ud + new_dividends = await self.parse_dividends_history(blocks, new_transfers) return transfers_changed, new_transfers, new_dividends + async def parse_dividends_history(self, blocks, transactions): + """ + Request transactions from the network to initialize data for a given pubkey + :param List[duniterpy.documents.Block] blocks: the list of transactions found by tx parsing + :param List[sakia.data.entities.Transaction] transactions: the list of transactions found by tx parsing + """ + connections_pubkeys = [c.pubkey for c in self._connections_processor.connections_to(self.currency)] + min_block_number = blocks[0].number + dividends = [] + for pubkey in connections_pubkeys: + history_data = await self._bma_connector.get(self.currency, bma.ud.history, + req_args={'pubkey': pubkey}) + block_numbers = [] + for ud_data in history_data["history"]["history"]: + dividend = Dividend(currency=self.currency, + pubkey=pubkey, + block_number=ud_data["block_number"], + timestamp=ud_data["time"], + amount=ud_data["amount"], + base=ud_data["base"]) + if dividend.block_number > min_block_number: + self._logger.debug("Dividend of block {0}".format(dividend.block_number)) + block_numbers.append(dividend.block_number) + if self._dividends_processor.commit(dividend): + dividends.append(dividend) + + for tx in transactions: + txdoc = TransactionDoc.from_signed_raw(tx.raw) + for input in txdoc.inputs: + if input.source == "D" and input.origin_id == pubkey and input.index not in block_numbers: + block = next((b for b in blocks if b.number == input.index)) + dividend = Dividend(currency=self.currency, + pubkey=pubkey, + block_number=input.index, + timestamp=block.mediantime, + amount=block.ud, + base=block.unit_base) + self._logger.debug("Dividend of block {0}".format(dividend.block_number)) + if self._dividends_processor.commit(dividend): + dividends.append(dividend) + return dividends + def transfers(self, pubkey): """ Get all transfers from or to a given pubkey diff --git a/src/sakia/tests/technical/test_transactions_service.py b/src/sakia/tests/technical/test_transactions_service.py index 54d1edcab0fba05c8867bbffb0bf83e422903d95..60adbe225f40118504014f8b90821becc117683a 100644 --- a/src/sakia/tests/technical/test_transactions_service.py +++ b/src/sakia/tests/technical/test_transactions_service.py @@ -38,7 +38,6 @@ async def test_receive_tx(application_with_one_connection, fake_server, bob, ali await fake_server.close() - @pytest.mark.asyncio async def test_issue_dividend(application_with_one_connection, fake_server, bob): dividends_before_send = application_with_one_connection.transactions_services[fake_server.forge.currency].dividends(bob.key.pubkey) @@ -50,7 +49,7 @@ async def test_issue_dividend(application_with_one_connection, fake_server, bob) fake_server.forge.forge_block() fake_server.forge.forge_block() new_blocks = fake_server.forge.blocks[-5:] - application_with_one_connection.transactions_services[fake_server.forge.currency].handle_new_blocks(new_blocks) + await application_with_one_connection.transactions_services[fake_server.forge.currency].handle_new_blocks(new_blocks) dividends_after_parse = application_with_one_connection.transactions_services[fake_server.forge.currency].dividends(bob.key.pubkey) assert len(dividends_before_send) + 2 == len(dividends_after_parse) await fake_server.close()