diff --git a/src/cutecoin/core/transfer.py b/src/cutecoin/core/transfer.py index 5a78b7c2a5d5be8f113ce730bafff5cdf410708d..c53680dcdf61e775a8b9fed7d5c684b03fd509e2 100644 --- a/src/cutecoin/core/transfer.py +++ b/src/cutecoin/core/transfer.py @@ -75,7 +75,7 @@ class Transfer(QObject): (TransferState.AWAITING, (bool, Block)): (self._found_in_block, self._be_validating, TransferState.VALIDATING), - (TransferState.AWAITING, (bool, Block, int)): + (TransferState.AWAITING, (bool, Block, int, int)): (self._not_found_in_blockchain, None, TransferState.REFUSED), (TransferState.VALIDATING, (bool, Block, int)): @@ -146,12 +146,13 @@ class Transfer(QObject): """ return self._metadata - def _not_found_in_blockchain(self, rollback, block, mediantime_target): + def _not_found_in_blockchain(self, rollback, block, mediantime_target, mediantime_blocks): """ Check if the transaction could not be found in the blockchain :param bool rollback: True if we are in a rollback procedure :param ucoinpy.documents.Block block: The block to look for the tx :param int mediantime_target: The mediantime to mine a block in the community parameters + :param int mediantime_blocks: The number of block used to derive the mediantime :return: True if the transaction could not be found in a given time :rtype: bool """ @@ -159,7 +160,7 @@ class Transfer(QObject): for tx in block.transactions: if tx.hash == self.sha_hash: return False - if block.time > self.metadata['time'] + mediantime_target*10: + if block.time > self.metadata['time'] + mediantime_target*mediantime_blocks: return True return False @@ -205,8 +206,11 @@ class Transfer(QObject): :param ucoinpy.documents.Block block: The block to check for the transaction :return: True if the transfer is not found in the block """ - if rollback and block.blockid == self.blockid: - return self.sha_hash not in [t.hash for t in block.transactions] + if rollback: + if not block or block.blockid != self.blockid: + return True + else: + return self.sha_hash not in [t.hash for t in block.transactions] return False def _rollback_still_present(self, rollback, block): diff --git a/src/cutecoin/core/txhistory.py b/src/cutecoin/core/txhistory.py index 13c5fb87d87ea897e4d1e16c666714af80d91af5..f3a8896dc56e2477cc5f8426d0324544ecf03c49 100644 --- a/src/cutecoin/core/txhistory.py +++ b/src/cutecoin/core/txhistory.py @@ -231,6 +231,8 @@ class TxHistory(): :param cutecoin.core.Community community: The community :param list received_list: List of transactions received """ + new_transfers = [] + new_dividends = [] try: logging.debug("Refresh from : {0} to {1}".format(block_number_from, self._block_to['number'])) dividends = yield from self.request_dividends(community, block_number_from) @@ -238,11 +240,6 @@ class TxHistory(): members_pubkeys = yield from community.members_pubkeys() fork_window = community.network.fork_window(members_pubkeys) blocks_with_tx = with_tx_data['result']['blocks'] - new_transfers = [] - new_dividends = [] - # Lets look if transactions took too long to be validated - awaiting = [t for t in self._transfers - if t.state == TransferState.AWAITING] while block_number_from <= self._block_to['number']: udid = 0 for d in [ud for ud in dividends if ud['block_number'] == block_number_from]: @@ -284,10 +281,9 @@ class TxHistory(): self.latest_block = block_number_from parameters = yield from community.parameters() - for transfer in awaiting: - transfer.check_refused(self._block_to['medianTime'], - parameters['avgGenTime'], - parameters['medianTimeBlocks']) + for transfer in [t for t in self._transfers if t.state == TransferState.AWAITING]: + transfer.run_state_transitions((False, self._block_to, + parameters['avgGenTime'], parameters['medianTimeBlocks'])) except NoPeerAvailable as e: logging.debug(str(e)) self.wallet.refresh_finished.emit([]) @@ -298,6 +294,57 @@ class TxHistory(): self.wallet.refresh_finished.emit(received_list) + @asyncio.coroutine + def _check_block(self, block_number, community): + """ + Parse a block + :param cutecoin.core.Community community: The community + :param cutecoin.core.Transfer transfer: The transfer to check the presence + """ + block = None + block_doc = None + tries = 0 + while block is None and tries < 3: + try: + block = yield from community.bma_access.future_request(bma.blockchain.Block, + req_args={'number': block_number}) + signed_raw = "{0}{1}\n".format(block['raw'], + block['signature']) + try: + block_doc = Block.from_signed_raw(signed_raw) + except TypeError: + logging.debug("Error in {0}".format(block_number)) + block = None + tries += 1 + except ValueError as e: + if '404' in str(e): + block = None + tries += 1 + for transfer in [t for t in self._transfers + if t.state in (TransferState.VALIDATING, TransferState.VALIDATED)]: + return not transfer.run_state_transitions((True, block_doc)) + + @asyncio.coroutine + def _rollback(self, community): + """ + Rollback last transactions until we find one still present + in the main blockchain + + :param cutecoin.core.Community community: The community + """ + try: + logging.debug("Rollback from : {0}".format(self._block_to['number'])) + # We look for the block goal to check for rollback, + # depending on validating and validated transfers... + tx_blocks = [tx.blockid.number for tx in self._transfers + if tx.state in (TransferState.VALIDATED, TransferState.VALIDATING) \ + and tx.blockid is not None] + for block_number in tx_blocks: + if (yield from self._check_block(community, block_number)): + return + except NoPeerAvailable: + logging.debug("No peer available") + @asyncio.coroutine def refresh(self, community, received_list): # We update the block goal @@ -331,4 +378,4 @@ class TxHistory(): except ValueError as e: logging.debug("Block not found") except NoPeerAvailable: - logging.debug("No peer available") \ No newline at end of file + logging.debug("No peer available")