diff --git a/src/sakia/services/sources.py b/src/sakia/services/sources.py index 9c6b47ae6d8354168c2823404bbd1dbeca643d63..7c8be058aaff485dfa08ae4bf71177d1e5d7106e 100644 --- a/src/sakia/services/sources.py +++ b/src/sakia/services/sources.py @@ -1,6 +1,7 @@ from PyQt5.QtCore import QObject from duniterpy.api import bma, errors from duniterpy.documents import Transaction as TransactionDoc +from duniterpy.grammars import output from duniterpy.grammars.output import Condition from duniterpy.documents import BlockUID import logging @@ -106,25 +107,10 @@ class SourcesServices(QObject): self.currency, bma.tx.sources, req_args={"pubkey": pubkey} ) nb_sources = len(sources_data["sources"]) - for i, s in enumerate(sources_data["sources"]): - log_stream("Parsing source ud/tx {:}/{:}".format(i, nb_sources)) + for index, source in enumerate(sources_data["sources"]): + log_stream("Parsing source ud/tx {:}/{:}".format(index, nb_sources)) progress(1 / nb_sources) - conditions = pypeg2.parse(s["conditions"], Condition) - if conditions.left.pubkey == pubkey: - try: - if conditions.left.pubkey == pubkey: - source = Source( - currency=self.currency, - pubkey=pubkey, - identifier=s["identifier"], - type=s["type"], - noffset=s["noffset"], - amount=s["amount"], - base=s["base"], - ) - self._sources_processor.insert(source) - except AttributeError as e: - self._logger.error(str(e)) + self.add_source(pubkey, source) async def check_destruction(self, pubkey, block_number, unit_base): amount = self._sources_processor.amount(self.currency, pubkey) @@ -177,23 +163,8 @@ class SourcesServices(QObject): self.currency, bma.tx.sources, req_args={"pubkey": pubkey} ) self._sources_processor.drop_all_of(self.currency, pubkey) - for i, s in enumerate(sources_data["sources"]): - conditions = pypeg2.parse(s["conditions"], Condition) - if conditions.left.pubkey == pubkey: - try: - if conditions.left.pubkey == pubkey: - source = Source( - currency=self.currency, - pubkey=pubkey, - identifier=s["identifier"], - type=s["type"], - noffset=s["noffset"], - amount=s["amount"], - base=s["base"], - ) - self._sources_processor.insert(source) - except AttributeError as e: - self._logger.error(str(e)) + for source in sources_data["sources"]: + self.add_source(pubkey, source) async def refresh_sources(self, connections): """ @@ -241,3 +212,48 @@ class SourcesServices(QObject): ) if source.pubkey == pubkey: self._sources_processor.insert(source) + + def find_signature_in_condition(self, _condition, pubkey, result=False): + """ + Recursive function to find a SIG(pubkey) in a Condition object + + :param output.Condition _condition: Condition instance + :param str pubkey: Pubkey to find + :param bool result: True if found + :return: + """ + if isinstance(_condition.left, output.Condition): + result |= self.find_signature_in_condition(_condition.left, pubkey, result) + if isinstance(_condition.right, output.Condition): + result |= self.find_signature_in_condition(_condition.right, pubkey, result) + if ( + isinstance(_condition.left, output.SIG) + and _condition.left.pubkey == pubkey + or isinstance(_condition.right, output.SIG) + and _condition.right.pubkey == pubkey + ): + result |= True + return result + + def add_source(self, pubkey, source): + """ + Add a new source for the pubkey + + :param str pubkey: Pubkey concerned + :param dict source: Source dict from api + :return: + """ + try: + entity = Source( + currency=self.currency, + pubkey=pubkey, + identifier=source["identifier"], + type=source["type"], + noffset=source["noffset"], + amount=source["amount"], + base=source["base"], + conditions=source["conditions"], + ) + self._sources_processor.insert(entity) + except AttributeError as e: + self._logger.error(str(e)) diff --git a/tests/unit/services/test_sources.py b/tests/unit/services/test_sources.py new file mode 100644 index 0000000000000000000000000000000000000000..3d62b9d6b910d58d5275ff5b9abd8e57868dae49 --- /dev/null +++ b/tests/unit/services/test_sources.py @@ -0,0 +1,64 @@ +import pytest +from duniterpy.documents.transaction import output + + +def test_parse_source_condition(application_with_one_connection, alice, bob): + application_with_one_connection.instanciate_services() + + issuer = alice.key.pubkey + receiver = bob.key.pubkey + condition = output.Condition.token( + output.SIG.token(receiver), + output.Operator.token("||"), + output.Condition.token( + output.SIG.token(issuer), + output.Operator.token("&&"), + output.CSV.token(604800), + ), + ) + assert ( + application_with_one_connection.sources_service.find_signature_in_condition( + condition, receiver + ) + is True + ) + assert ( + application_with_one_connection.sources_service.find_signature_in_condition( + condition, issuer + ) + is True + ) + assert ( + application_with_one_connection.sources_service.find_signature_in_condition( + condition, "badpubkey" + ) + is False + ) + condition = output.Condition.token( + output.Condition.token( + output.CSV.token(604800), + output.Operator.token("&&"), + output.SIG.token(issuer), + ), + output.Operator.token("||"), + output.SIG.token(receiver), + ) + + assert ( + application_with_one_connection.sources_service.find_signature_in_condition( + condition, receiver + ) + is True + ) + assert ( + application_with_one_connection.sources_service.find_signature_in_condition( + condition, issuer + ) + is True + ) + assert ( + application_with_one_connection.sources_service.find_signature_in_condition( + condition, "badpubkey" + ) + is False + )