def test_revert_transaction_conversion(self):
        expected_result = Transaction(
            tx="79283647",
            receivers=[
                TransactionReceiver(address="9782364", amount=0.40),
                TransactionReceiver(address="9782364", amount=0.30)
            ])

        transaction = Transaction(tx="79283647",
                                  receivers=[
                                      TransactionReceiver(address="9782364",
                                                          amount=40),
                                      TransactionReceiver(address="9782364",
                                                          amount=30)
                                  ])

        with patch.object(self._integer_converter, 'revert_amount_conversion'):

            def stub(amount: float):
                return float(amount / 100)

            self._integer_converter.revert_amount_conversion.side_effect = stub

            actual_result = self._integer_converter.revert_transaction_conversion(
                transaction)
            self.assertEqual(actual_result, expected_result)
Exemple #2
0
    def test_iteration_filter_one_transaction(self):
        """Two transactions were given, one should be filtered and the other one not."""
        height_of_highest_block = 30
        last_checked_coin_block_height = height_of_highest_block - self._last_block_distance - 1
        not_filtered_transaction = Transaction(tx="tx", receivers=[self._gateway_managed_address_receiver])
        filtered_transaction = Transaction(tx="khj", receivers=[TransactionReceiver(address="92634867", amount=3425)])

        self._block_height_storage.get_last_checked_block_height.return_value = last_checked_coin_block_height
        self._chain_query_service.get_height_of_highest_block.return_value = height_of_highest_block
        self._polling_state_storage.get_polling_state.return_value = None

        def _get_transactions_of_block_at_height(height: int):
            if height == (last_checked_coin_block_height + 1):
                return [not_filtered_transaction, filtered_transaction]
            else:
                return []

        self._chain_query_service.get_transactions_of_block_at_height.side_effect = _get_transactions_of_block_at_height

        self._transaction_polling_service._iteration()

        self._transaction_consumer.filter_transaction.assert_any_call(not_filtered_transaction)
        self._transaction_consumer.filter_transaction.assert_any_call(filtered_transaction)
        self._transaction_consumer.handle_transaction.assert_called_once_with(not_filtered_transaction)
        self._chain_query_service.get_transactions_of_block_at_height.assert_called_once_with(
            last_checked_coin_block_height + 1)
        self._block_height_storage.set_last_checked_block_height.assert_called_once_with(
            last_checked_coin_block_height + 1)
    def test_convert_transaction_to_int(self):
        transaction = Transaction(tx="79283647",
                                  receivers=[
                                      TransactionReceiver(address="9782364",
                                                          amount=0.40),
                                      TransactionReceiver(address="9782364",
                                                          amount=0.30)
                                  ])

        expected_result = Transaction(
            tx="79283647",
            receivers=[
                TransactionReceiver(address="9782364", amount=40),
                TransactionReceiver(address="9782364", amount=30)
            ])

        with patch.object(self._integer_converter, 'safely_convert_to_int'):

            def stub(amount: float):
                return int(amount * 100)

            self._integer_converter.safely_convert_to_int.side_effect = stub

            actual_result = self._integer_converter.convert_transaction_to_int(
                transaction)
            self.assertEqual(actual_result, expected_result)
            self.assertEqual(
                self._integer_converter.safely_convert_to_int.call_count, 2)
Exemple #4
0
    def test_iteration_handle_one_transaction(self):
        """The TransactionPollingService should process a single transaction that is not filtered."""
        height_of_highest_block = 30
        last_checked_coin_block_height = height_of_highest_block - self._last_block_distance - 1
        transaction = Transaction(tx="tx", receivers=[self._gateway_managed_address_receiver])

        self._block_height_storage.get_last_checked_block_height.return_value = last_checked_coin_block_height
        self._chain_query_service.get_height_of_highest_block.return_value = height_of_highest_block
        self._polling_state_storage.get_polling_state.return_value = None

        def _get_transactions_of_block_at_height(height: int):
            if height == (last_checked_coin_block_height + 1):
                return [transaction]
            else:
                return []

        self._chain_query_service.get_transactions_of_block_at_height.side_effect = _get_transactions_of_block_at_height

        self._transaction_polling_service._iteration()

        self._transaction_consumer.filter_transaction.assert_called_once_with(transaction)
        self._transaction_consumer.handle_transaction.assert_called_once_with(transaction)
        self._chain_query_service.get_transactions_of_block_at_height.assert_called_once_with(
            last_checked_coin_block_height + 1)
        self._block_height_storage.set_last_checked_block_height.assert_called_once_with(
            last_checked_coin_block_height + 1)
Exemple #5
0
    def test_skip_transaction_after_too_many_tries(self):
        self._mock_real_storage()

        height_of_highest_block = 30
        last_checked_coin_block_height = height_of_highest_block - self._last_block_distance - 1
        transaction = Transaction(tx="tx", receivers=[self._gateway_managed_address_receiver])

        def _get_transactions_of_block_at_height(height: int):
            if height == (last_checked_coin_block_height + 1):
                return [transaction]
            else:
                return []

        def mock_handle_transaction(tr: Transaction):
            raise KeyError('failed')

        self._block_height_storage.get_last_checked_block_height.return_value = last_checked_coin_block_height
        self._chain_query_service.get_height_of_highest_block.return_value = height_of_highest_block
        self._transaction_consumer.handle_transaction.side_effect = mock_handle_transaction
        self._chain_query_service.get_transactions_of_block_at_height.side_effect = _get_transactions_of_block_at_height

        with self.assertRaises(KeyError):
            self._transaction_polling_service._iteration()

        self._transaction_polling_service._iteration()

        self._transaction_consumer.handle_transaction.assert_called_once_with(transaction)
        self.assertEqual(self._transaction_consumer.filter_transaction.call_count, 2)
    def test_handle_transaction_multi_receiver(self, mock_datetime: MagicMock):
        now = MagicMock()
        mock_datetime.utcnow.return_value = now
        gateway_coin_address = self._gateway_managed_receiver.address
        dst_waves_address = '039769'
        incoming_transaction = Transaction(
            tx='723968', receivers=[self._gateway_managed_receiver])

        amount_after_fees = self._gateway_managed_receiver.amount - self._coin_standard_fee - self._gateway_fee

        attempts = [
            TransactionAttempt(sender=gateway_coin_address,
                               currency="coin",
                               fee=self._coin_standard_fee,
                               receivers=[
                                   TransactionAttemptReceiver(
                                       address=self._gateway_address,
                                       amount=amount_after_fees),
                                   TransactionAttemptReceiver(
                                       address=self._gateway_owner_address,
                                       amount=self._gateway_fee)
                               ]),
            TransactionAttempt(sender=self._gateway_waves_address,
                               fee=self._waves_standard_fee,
                               currency="waves",
                               receivers=[
                                   TransactionAttemptReceiver(
                                       address=dst_waves_address,
                                       amount=amount_after_fees)
                               ])
        ]

        trigger = AttemptListTrigger(tx=incoming_transaction.tx,
                                     currency="coin",
                                     receiver=0)

        attempt_list = TransactionAttemptList(trigger=trigger,
                                              attempts=attempts,
                                              created_at=now,
                                              last_modified=now)

        self._attempt_list_storage.find_by_trigger.return_value = None
        self._map_storage.get_waves_address_by_coin_address.return_value = dst_waves_address

        self._coin_transaction_consumer_impl.handle_transaction(
            incoming_transaction)

        self._attempt_list_storage.find_by_trigger.assert_any_call(
            AttemptListTrigger(tx=incoming_transaction.tx,
                               receiver=0,
                               currency="coin"))
        self._map_storage.get_waves_address_by_coin_address.assert_called_once_with(
            gateway_coin_address)
        self._attempt_service.continue_transaction_attempt_list.assert_not_called(
        )
        self._attempt_list_storage.safely_save_attempt_list.assert_called_once_with(
            attempt_list)
    def test_filter_transaction_already_exists(self):
        """
        Should not pass a transaction that is existing in one of the attempt lists
        """
        transaction = Transaction(
            tx="78265", receivers=[TransactionReceiver('28734', 7823)])

        self._attempt_list_storage.gateway_transaction_exists.return_value = True
        res = self._waves_transaction_consumer_impl.filter_transaction(
            transaction)
        self.assertFalse(res)
    def test_filter_transaction_by_receiver_failure(self):
        """
        Should not pass a transaction with only one receiver which does not equal the gateway address
        """
        transaction = Transaction(
            tx="78265", receivers=[TransactionReceiver('28734', 7823)])
        self._attempt_list_storage.gateway_transaction_exists.return_value = False

        res = self._waves_transaction_consumer_impl.filter_transaction(
            transaction)
        self._attempt_list_storage.find_by_trigger.assert_not_called()
        self.assertFalse(res)
    def test_get_transactions_of_block_at_height(self,
                                                 mock_requests_get: MagicMock):
        mock_get_result = MagicMock()
        mock_get_result.ok = True

        transactions = [{
            'signature':
            '5Kg1u9AUix8H3xkPGpHBCuFptCJJwMGkYcdRitsCuSd'
            'Zidcf19DoMNMJUKvRrRw2SjF5fGgedZJiJWwZ5DRENM64',
            'id':
            'HR96p2fuceFm2P1wbs8FtxyeoPmGooKjHmV1gHUhZ5U2',
            'assetId':
            self._asset_id,
            'amount':
            110000,
            'feeAsset':
            None,
            'fee':
            100000,
            'recipient':
            'address:3Mxjf6da1ixZD5UzM7H9rLXLWzfv5YXZvVn',
            'attachment':
            'B4GdmuG3Jbxg7DLNWu3YrXiFbdQzPiCYBGqqunsG3',
            'senderPublicKey':
            '3bwjGNumMn4K5Yzt154PFegJN4StPvdQ6HAhzbDnCP1m',
            'timestamp':
            1502026364974,
            'type':
            4,
            'sender':
            '3Mxjf6da1ixZD5UzM7H9rLXLWzfv5YXZvVn'
        }]

        mock_get_result.text = json.dumps({'transactions': transactions})

        mock_requests_get.return_value = mock_get_result

        # self._chain_query_service._get_response_from_node.return_value = {'transactions': transactions}
        transactions = self._chain_query_service.get_transactions_of_block_at_height(
            20)

        expected_transaction = Transaction(
            tx='HR96p2fuceFm2P1wbs8FtxyeoPmGooKjHmV1gHUhZ5U2',
            receivers=[
                TransactionReceiver(
                    address='3Mxjf6da1ixZD5UzM7H9rLXLWzfv5YXZvVn',
                    amount=110000)
            ])

        self.assertEqual(len(transactions), 1)
        self.assertEqual(transactions[0], expected_transaction)
    def test_handle_transaction(self):
        _filter_receivers = MagicMock(return_value=[0])
        _handle_receiver = MagicMock()
        transaction = Transaction(tx="78265",
                                  receivers=[self._gateway_waves_receiver])

        with patch.multiple(self._waves_transaction_consumer_impl,
                            _filter_receivers=_filter_receivers,
                            _handle_receiver=_handle_receiver):
            self._waves_transaction_consumer_impl.handle_transaction(
                transaction)
            _filter_receivers.assert_called_once_with(transaction)
            _handle_receiver.assert_called_once_with(
                transaction.tx, self._gateway_waves_receiver, 0, None)
 def test_filter_transaction_by_receivers_failure(self):
     """
     The filter should ignore transactions with no gateway managed receivers
     """
     self._attempt_list_storage.gateway_transaction_exists.return_value = False
     self._map_storage.coin_address_exists.return_value = False
     transaction = Transaction(
         tx='723968', receivers=[self._not_gateway_managed_receiver])
     res = self._coin_transaction_consumer_impl.filter_transaction(
         transaction)
     self.assertFalse(res)
     self._map_storage.coin_address_exists.assert_called_once_with(
         self._not_gateway_managed_receiver.address)
     self._attempt_list_storage.find_by_trigger.assert_not_called()
 def test_filter_transaction_by_receiver_success(self):
     """
     Should pass a transaction with a receiver that is addressed to the main
     gateway waves address
     """
     transaction = Transaction(tx="78265",
                               receivers=[self._gateway_waves_receiver])
     self._attempt_list_storage.gateway_transaction_exists.return_value = False
     self._attempt_list_storage.find_by_trigger.return_value = None
     res = self._waves_transaction_consumer_impl.filter_transaction(
         transaction)
     self._attempt_list_storage.gateway_transaction_exists.assert_called_once_with(
         transaction.tx)
     self.assertTrue(res)
    def test_filter_transaction_exists(self):
        """
        The filter should not allow transactions to pass which were already processed
        """

        with patch.object(self._coin_transaction_consumer_impl,
                          "_filter_receivers"):
            self._attempt_service.gateway_transaction_exists.return_value = True
            transaction = Transaction(
                tx='723968', receivers=[self._gateway_managed_receiver])
            res = self._coin_transaction_consumer_impl.filter_transaction(
                transaction)
            self.assertFalse(res)
            cast(MagicMock, self._coin_transaction_consumer_impl.
                 _filter_receivers).assert_not_called()
 def test_filter_transaction_block_coin_holder(self):
     """
     The filter should not allow transactions that are addressed to the gateway coin holder
     """
     self._attempt_list_storage.gateway_transaction_exists.return_value = False
     self._map_storage.coin_address_exists.return_value = True
     transaction = Transaction(
         tx='723968', receivers=[self._gateway_coin_holder_receiver])
     res = self._coin_transaction_consumer_impl.filter_transaction(
         transaction)
     self.assertFalse(res)
     self._map_storage.coin_address_exists.assert_called_once_with(
         self._gateway_coin_holder_receiver.address)
     self._attempt_list_storage.gateway_transaction_exists.assert_called_once_with(
         transaction.tx)
    def send_coin(self, attempt: TransactionAttempt, secret: Optional[str]) -> Transaction:
        if attempt.sender != self._gateway_pywaves_address.address:
            raise PyWavesError('Missing secret for sender ' + attempt.sender)

        transaction = self._gateway_pywaves_address.sendAsset(
            recipient=pw.Address(attempt.receivers[0].address),
            asset=self._w_ltc,
            amount=attempt.receivers[0].amount,
            txFee=attempt.fee)

        if transaction is None:
            raise PyWavesError("Encountered an unknown exception while trying to perform waves transaction.")

        return Transaction(
            tx=transaction['id'],
            receivers=[TransactionReceiver(transaction['recipient'], attempt.receivers[0].amount)])
Exemple #16
0
    def test_iteration_do_nothing(self):
        """In the case of a fresh start, the handle_transaction method should not be called."""
        height_of_highest_block = 30
        transaction = Transaction(tx="tx", receivers=[TransactionReceiver("receiver", 6587)])

        self._block_height_storage.get_last_checked_block_height.return_value = None
        self._chain_query_service.get_height_of_highest_block.return_value = height_of_highest_block
        self._chain_query_service.get_transactions_of_block_at_height.return_value = [transaction]
        self._transaction_consumer.filter_transaction.return_value = False
        self._polling_state_storage.get_polling_state.return_value = None

        self._transaction_polling_service._iteration()

        self._transaction_consumer.filter_transaction.assert_not_called()
        self._transaction_consumer.handle_transaction.assert_not_called()
        self._chain_query_service.get_transactions_of_block_at_height.assert_not_called()
        self._block_height_storage.set_last_checked_block_height.assert_called_once_with(height_of_highest_block)
 def test_filter_transaction_by_receivers_success(self):
     """
     The filter should pass a transaction that has not yet been processed and
     contains a gateway managed address
     """
     self._attempt_list_storage.gateway_transaction_exists.return_value = False
     self._map_storage.coin_address_exists.return_value = True
     self._attempt_list_storage.find_by_trigger.return_value = None
     transaction = Transaction(tx='723968',
                               receivers=[self._gateway_managed_receiver])
     res = self._coin_transaction_consumer_impl.filter_transaction(
         transaction)
     self.assertTrue(res)
     self._map_storage.coin_address_exists.assert_called_once_with(
         self._gateway_managed_receiver.address)
     self._attempt_list_storage.find_by_trigger.assert_called_once_with(
         AttemptListTrigger(tx=transaction.tx, receiver=0, currency="coin"))
Exemple #18
0
    def _convert_node_response_to_transaction(self, res: dict) -> Optional[Transaction]:
        if 'assetId' not in res or res['assetId'] != self._asset_id:
            return None

        if res['type'] != 4:
            return None

        try:
            address = res['recipient'].split(':')[1]
        except IndexError:
            address = res['recipient']
        try:
            sender = res['sender'].split(':')[1]
        except IndexError:
            sender = res['sender']

        return Transaction(
            tx=res['id'],
            receivers=[TransactionReceiver(address=address, amount=res['amount'])],
            senders=[TransactionSender(address=sender)])