diff --git a/requirements.txt b/requirements.txt index 3cebcbba79f4faed16c3c4653f4b4a928daf9754..c303f95f6ce956e8ada00e6599d94365090824f4 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,4 +1,4 @@ -git+https://github.com/Insoleet/quamash.git@sakia +quamash asynctest networkx attrs<=17.2 diff --git a/src/sakia/data/processors/blockchain.py b/src/sakia/data/processors/blockchain.py index 24211187e5640b6fd7aae965a326ec4c9267855e..200eaf5592c4733dc024fa968fbab0ece7605ac4 100644 --- a/src/sakia/data/processors/blockchain.py +++ b/src/sakia/data/processors/blockchain.py @@ -12,7 +12,7 @@ import asyncio @attr.s class BlockchainProcessor: - _repo = attr.ib() # :type sakia.data.repositories.CertificationsRepo + _repo = attr.ib() # :type sakia.data.repositories.BlockchainsRepo _bma_connector = attr.ib() # :type sakia.data.connectors.bma.BmaConnector _logger = attr.ib(default=attr.Factory(lambda: logging.getLogger('sakia'))) @@ -29,11 +29,19 @@ class BlockchainProcessor: def initialized(self, currency): return self._repo.get_one(currency=currency) is not None - async def ud_before(self, currency, block_number): + async def ud_before(self, currency, block_number, udblocks=[]): + """ + + :param currency: + :param block_number: + :param udblocks: /blockchain/ud/history data of given key + :return: + """ try: - udblocks = await self._bma_connector.get(currency, bma.blockchain.ud) - blocks = udblocks['result']['blocks'] - ud_block_number = next(b for b in blocks if b <= block_number) + if not udblocks: + udblocks = await self._bma_connector.get(currency, bma.blockchain.ud) + udblocks = udblocks['result']['blocks'] + ud_block_number = next(b for b in udblocks if b <= block_number) block = await self._bma_connector.get(currency, bma.blockchain.block, {'number': ud_block_number}) return block['dividend'], block['unitbase'] except StopIteration: @@ -257,6 +265,7 @@ class BlockchainProcessor: blockchain.parameters.sig_qty = parameters['sigQty'] blockchain.parameters.sig_period = parameters['sigPeriod'] blockchain.parameters.ud0 = parameters['ud0'] + blockchain.parameters.ud_time_0 = parameters['udTime0'] blockchain.parameters.dt_reeval = parameters['dtReeval'] blockchain.parameters.ud_reeval_time_0 = parameters['udReevalTime0'] blockchain.parameters.xpercent = parameters['xpercent'] diff --git a/src/sakia/data/processors/dividends.py b/src/sakia/data/processors/dividends.py index 9cf9f1cbd2bd8b19f7e3e02d3122bae02bc916c3..908a5a5b496c1ccb118c8dc62ffa67c325d7a492 100644 --- a/src/sakia/data/processors/dividends.py +++ b/src/sakia/data/processors/dividends.py @@ -13,9 +13,11 @@ import asyncio class DividendsProcessor: """ :param sakia.data.repositories.DividendsRepo _repo: the repository of the sources + :param sakia.data.repositories.BlockchainsRepo _blockchain_repo: the repository of the sources :param sakia.data.connectors.bma.BmaConnector _bma_connector: the bma connector """ _repo = attr.ib() + _blockchain_repo = attr.ib() _bma_connector = attr.ib() _logger = attr.ib(default=attr.Factory(lambda: logging.getLogger('sakia'))) @@ -25,7 +27,7 @@ class DividendsProcessor: Instanciate a blockchain processor :param sakia.app.Application app: the app """ - return cls(app.db.dividends_repo, + return cls(app.db.dividends_repo, app.db.blockchains_repo, BmaConnector(NodesProcessor(app.db.nodes_repo), app.parameters)) def commit(self, dividend): @@ -44,6 +46,7 @@ class DividendsProcessor: :param function log_stream: :param function progress: progress callback """ + blockchain = self._blockchain_repo.get_one(currency=connection.currency) history_data = await self._bma_connector.get(connection.currency, bma.ud.history, req_args={'pubkey': connection.pubkey}) log_stream("Found {0} available dividends".format(len(history_data["history"]["history"]))) @@ -70,14 +73,14 @@ class DividendsProcessor: txdoc = Transaction.from_signed_raw(tx.raw) for input in txdoc.inputs: if input.source == "D" and input.origin_id == connection.pubkey and input.index not in block_numbers: - block = await self._bma_connector.get(connection.currency, - bma.blockchain.block, req_args={'number': input.index}) + diff_blocks = blockchain.current_buid.number - input.index + ud_mediantime = blockchain.median_time - diff_blocks*blockchain.parameters.avg_gen_time dividend = Dividend(currency=connection.currency, pubkey=connection.pubkey, block_number=input.index, - timestamp=block["medianTime"], - amount=block["dividend"], - base=block["unitbase"]) + timestamp=ud_mediantime, + amount=input.amount, + base=input.base) log_stream("Dividend of block {0}".format(dividend.block_number)) progress(1/nb_ud_tx) try: diff --git a/src/sakia/gui/sub/transfer/model.py b/src/sakia/gui/sub/transfer/model.py index ee19bcba550bcffc32aaaa35e941c51cfca9538e..eb1c365b157caadc2da81099cc9720718ab3a351 100644 --- a/src/sakia/gui/sub/transfer/model.py +++ b/src/sakia/gui/sub/transfer/model.py @@ -94,10 +94,10 @@ class TransferModel(QObject): result, transactions = await self.app.documents_service.send_money(self.connection, secret_key, password, recipient, amount, amount_base, comment) for transaction in transactions: - self.app.sources_service.parse_transaction(self.connection.pubkey, transaction) + self.app.sources_service.parse_transaction_outputs(self.connection.pubkey, transaction) for conn in self._connections_processor.connections(): if conn.pubkey == recipient: - self.app.sources_service.parse_transaction(recipient, transaction) + self.app.sources_service.parse_transaction_inputs(recipient, transaction) new_tx = self.app.transactions_service.parse_sent_transaction(recipient, transaction) # Not all connections are concerned by chained tx if new_tx: diff --git a/src/sakia/services/sources.py b/src/sakia/services/sources.py index 391e2d5ab82a0acc11a7040dc797b40f007ff5bb..32f25f52af473628fb00d6bb033c18b49f3f2f25 100644 --- a/src/sakia/services/sources.py +++ b/src/sakia/services/sources.py @@ -3,7 +3,7 @@ from duniterpy.api import bma, errors from duniterpy.documents import Transaction as TransactionDoc from duniterpy.documents import BlockUID import logging -from sakia.data.entities import Source, Transaction +from sakia.data.entities import Source, Transaction,Dividend import hashlib @@ -36,7 +36,7 @@ class SourcesServices(QObject): def amount(self, pubkey): return self._sources_processor.amount(self.currency, pubkey) - def parse_transaction(self, pubkey, transaction): + def parse_transaction_outputs(self, pubkey, transaction): """ Parse a transaction :param sakia.data.entities.Transaction transaction: @@ -52,6 +52,13 @@ class SourcesServices(QObject): amount=output.amount, base=output.base) self._sources_processor.insert(source) + + def parse_transaction_inputs(self, pubkey, transaction): + """ + Parse a transaction + :param sakia.data.entities.Transaction transaction: + """ + txdoc = TransactionDoc.from_signed_raw(transaction.raw) for index, input in enumerate(txdoc.inputs): source = Source(currency=self.currency, pubkey=txdoc.issuers[0], @@ -115,54 +122,46 @@ class SourcesServices(QObject): :param int unit_base: the unit base of the destruction. None to look for the past uds :return: the destruction of sources """ - unique_tx = {s.written_block: s for s in transactions} - unique_ud = {u.block_number: u for u in dividends} - sorted_tx = (s for s in sorted(unique_tx.values(), key=lambda t: t.written_block)) - sorted_ud = (u for u in sorted(unique_ud.values(), key=lambda d: d.block_number)) - try: - tx = next(sorted_tx) - block_number = max(tx.written_block, 0) - except StopIteration: - tx = None - block_number = 0 - try: - ud = next(sorted_ud) - block_number = min(block_number, ud.block_number) - except StopIteration: - ud = None + tx_ud_data = {} + for tx in transactions: + try: + tx_ud_data[tx.written_block].append(tx) + except: + tx_ud_data[tx.written_block] = [tx] + for ud in dividends: + try: + tx_ud_data[ud.block_number].append(ud) + except: + tx_ud_data[ud.block_number] = [ud] + + blocks = sorted(b for b in tx_ud_data.keys()) nb_tx_ud = len(transactions) + len(dividends) + udblocks = await self._bma_connector.get(self.currency, bma.blockchain.ud) destructions = [] - while tx or ud: + for block_number in blocks: if log_stream: log_stream("Parsing info ud/tx of {:}".format(block_number)) if progress: progress(1/nb_tx_ud) - if tx and tx.written_block == block_number: - self.parse_transaction(pubkey, tx) - try: - tx = next(sorted_tx) - except StopIteration: - tx = None - if ud and ud.block_number == block_number: - self._parse_ud(pubkey, ud) - try: - ud = next(sorted_ud) - except StopIteration: - ud = None + + for data in tx_ud_data[block_number]: + if isinstance(data, Dividend): + self._parse_ud(pubkey, data) + if isinstance(data, Transaction): + self.parse_transaction_outputs(pubkey, data) + + for data in tx_ud_data[block_number]: + if isinstance(data, Transaction): + self.parse_transaction_inputs(pubkey, data) + if not unit_base: - _, destruction_base = await self._blockchain_processor.ud_before(self.currency, block_number) + _, destruction_base = await self._blockchain_processor.ud_before(self.currency, block_number, udblocks) else: destruction_base = unit_base destruction = await self.check_destruction(pubkey, block_number, destruction_base) if destruction: destructions.append(destruction) - if ud and tx: - block_number = min(ud.block_number, tx.written_block) - elif ud: - block_number = ud.block_number - elif tx: - block_number = tx.written_block return destructions async def refresh_sources(self, connections, transactions, dividends):