Exemple #1
0
    def check_trustlines():
        """
        Create Stellar transaction for deposit transactions marked as pending
        trust, if a trustline has been created.
        """
        module = sys.modules[__name__]
        transactions = Transaction.objects.filter(
            kind=Transaction.KIND.deposit,
            status=Transaction.STATUS.pending_trust)
        server = settings.HORIZON_SERVER
        for transaction in transactions:
            if module.TERMINATE:
                break
            try:
                account = (server.accounts().account_id(
                    transaction.stellar_account).call())
            except BaseHorizonError:
                logger.warning(
                    f"could not load account {transaction.stellar_account} using provided horizon URL"
                )
                continue
            try:
                balances = account["balances"]
            except KeyError:
                logger.debug(
                    f"horizon account {transaction.stellar_account} response had no balances"
                )
                continue
            for balance in balances:
                if balance.get("asset_type") == "native":
                    continue
                try:
                    asset_code = balance["asset_code"]
                    asset_issuer = balance["asset_issuer"]
                except KeyError:
                    logger.debug(
                        f"horizon balance had no asset_code for account {account['id']}"
                    )
                    continue
                if (asset_code == transaction.asset.code
                        and asset_issuer == transaction.asset.issuer):
                    if check_for_multisig(transaction):
                        # Now we're waiting for signatures to be collected on real deposit transaction
                        logger.info(
                            f"Account {account['id']} has established a trustline for {asset_code}"
                        )
                        continue

                    logger.info(
                        f"Account {account['id']} has established a trustline for {asset_code}, "
                        f"initiating deposit for {transaction.id}")
                    if create_stellar_deposit(transaction,
                                              destination_exists=True):
                        transaction.refresh_from_db()
                        try:
                            rdi.after_deposit(transaction)
                        except Exception:
                            logger.exception(
                                "An unexpected error was raised from "
                                "after_deposit() in check_trustlines")
    def execute_deposit(cls, transaction):
        try:
            _, pending_trust = PendingDeposits.get_or_create_destination_account(
                transaction
            )
        except RuntimeError as e:
            transaction.status = Transaction.STATUS.error
            transaction.status_message = str(e)
            transaction.save()
            logger.error(transaction.status_message)
            maybe_make_callback(transaction)
            return

        if pending_trust and not transaction.claimable_balance_supported:
            logger.info(
                f"destination account is pending_trust for transaction {transaction.id}"
            )
            transaction.status = Transaction.STATUS.pending_trust
            transaction.save()
            maybe_make_callback(transaction)
            return
        if MultiSigTransactions.requires_multisig(transaction):
            MultiSigTransactions.save_as_pending_signatures(transaction)
            return
        if PendingDeposits.submit(transaction):
            transaction.refresh_from_db()
            try:
                rdi.after_deposit(transaction)
            except Exception:
                logger.exception("after_deposit() threw an unexpected exception")
    def execute_deposits(cls):
        module = sys.modules[__name__]
        try:
            ready_transactions = PendingDeposits.get_ready_deposits()
        except Exception:
            logger.exception("poll_pending_deposits() threw an unexpected exception")
            return
        if not isinstance(ready_transactions, list):
            raise CommandError(
                "poll_pending_deposits() did not return a list of transaction objects."
            )
        for transaction in ready_transactions:
            if module.TERMINATE:
                break
            cls.execute_deposit(transaction)

        multisig_transactions = Transaction.objects.filter(
            kind=Transaction.KIND.deposit,
            status=Transaction.STATUS.pending_anchor,
            pending_signatures=False,
            envelope_xdr__isnull=False,
        )
        for transaction in multisig_transactions:
            if PendingDeposits.submit(transaction):
                transaction.refresh_from_db()
                try:
                    rdi.after_deposit(transaction)
                except Exception:
                    logger.exception("after_deposit() threw an unexpected exception")
    def execute_deposits(cls):
        module = sys.modules[__name__]
        try:
            ready_transactions = PendingDeposits.get_ready_deposits()
        except Exception:
            logger.exception(
                "poll_pending_deposits() threw an unexpected exception")
            return
        for i, transaction in enumerate(ready_transactions):
            if module.TERMINATE:
                still_processing_transactions = ready_transactions[i:]
                Transaction.objects.filter(
                    id__in=[t.id
                            for t in still_processing_transactions]).update(
                                pending_execution_attempt=False)
                break
            cls.execute_deposit(transaction)

        with django.db.transaction.atomic():
            multisig_transactions = list(
                Transaction.objects.filter(
                    kind=Transaction.KIND.deposit,
                    status=Transaction.STATUS.pending_anchor,
                    pending_signatures=False,
                    pending_execution_attempt=False,
                ).select_for_update())
            Transaction.objects.filter(
                id__in=[t.id for t in multisig_transactions]).update(
                    pending_execution_attempt=True)

        for i, transaction in enumerate(multisig_transactions):
            if module.TERMINATE:
                still_processing_transactions = ready_transactions[i:]
                Transaction.objects.filter(
                    id__in=[t.id
                            for t in still_processing_transactions]).update(
                                pending_execution_attempt=False)
                break

            try:
                success = PendingDeposits.submit(transaction)
            except Exception as e:
                logger.exception("submit() threw an unexpected exception")
                transaction.status_message = str(e)
                transaction.status = Transaction.STATUS.error
                transaction.pending_execution_attempt = False
                transaction.save()
                maybe_make_callback(transaction)
                continue

            if success:
                transaction.refresh_from_db()
                try:
                    rdi.after_deposit(transaction)
                except Exception:
                    logger.exception(
                        "after_deposit() threw an unexpected exception")
Exemple #5
0
 def check_trustlines():
     """
     Create Stellar transaction for deposit transactions marked as pending trust, if a
     trustline has been created.
     """
     transactions = Transaction.objects.filter(
         kind=Transaction.KIND.deposit,
         status=Transaction.STATUS.pending_trust)
     server = settings.HORIZON_SERVER
     for transaction in transactions:
         try:
             account = (server.accounts().account_id(
                 transaction.stellar_account).call())
         except BaseHorizonError:
             logger.warning(
                 f"could not load account {transaction.stellar_account} using provided horizon URL"
             )
             continue
         try:
             balances = account["balances"]
         except KeyError:
             logger.debug(
                 f"horizon account {transaction.stellar_account} response had no balances"
             )
             continue
         for balance in balances:
             try:
                 asset_code = balance["asset_code"]
                 asset_issuer = balance["asset_issuer"]
             except KeyError:
                 logger.debug(
                     f"Unable to retrieve asset info from balance object: {balance}"
                 )
                 if balance.get("asset_type") != "native":
                     logger.debug(
                         f"horizon balance had no asset_code for account {account['id']}"
                     )
                 continue
             if (asset_code == transaction.asset.code
                     and asset_issuer == transaction.asset.issuer):
                 logger.info(
                     f"Account {account['id']} has established a trustline for {asset_code}, "
                     f"initiating deposit for {transaction.id}")
                 if create_stellar_deposit(transaction.id):
                     transaction.refresh_from_db()
                     try:
                         rdi.after_deposit(transaction)
                     except Exception:
                         logger.exception(
                             "An unexpected error was raised from "
                             "after_deposit() in check_trustlines")
Exemple #6
0
    def handle_submit(cls, transaction: Transaction):
        try:
            success = PendingDeposits.submit(transaction)
        except Exception as e:
            logger.exception("submit() threw an unexpected exception")
            cls.handle_error(transaction, str(e))
            return

        if success:
            transaction.refresh_from_db()
            try:
                rdi.after_deposit(transaction)
            except Exception:
                logger.exception(
                    "after_deposit() threw an unexpected exception")
 def execute_deposit(transaction):
     # Deposit transaction (which may be multisig) is ready to be submitted
     try:
         success = execute_deposit(transaction)
     except ValueError as e:
         logger.error(str(e))
         return
     if success:
         # Get updated status
         transaction.refresh_from_db()
         try:
             rdi.after_deposit(transaction)
         except Exception:  # pragma: no cover
             # Same situation as poll_pending_deposits(), we should assume
             # this won't happen every time, so we don't stop the loop.
             logger.exception("after_deposit() threw an unexpected exception")
    def check_trustlines():
        """
        Create Stellar transaction for deposit transactions marked as pending
        trust, if a trustline has been created.
        """
        module = sys.modules[__name__]
        transactions = Transaction.objects.filter(
            kind=Transaction.KIND.deposit,
            status=Transaction.STATUS.pending_trust)
        server = settings.HORIZON_SERVER
        accounts = {}
        for transaction in transactions:
            if module.TERMINATE:
                break
            if accounts.get(transaction.stellar_account):
                account = accounts[transaction.stellar_account]
            else:
                try:
                    account = (server.accounts().account_id(
                        transaction.stellar_account).call())
                    accounts[transaction.stellar_account] = account
                except BaseRequestError:
                    logger.exception(
                        f"Failed to load account {transaction.stellar_account}"
                    )
                    continue
            for balance in account["balances"]:
                if balance.get("asset_type") == "native":
                    continue
                if (balance["asset_code"] == transaction.asset.code and
                        balance["asset_issuer"] == transaction.asset.issuer):
                    logger.info(
                        f"Account {account['id']} has established a trustline for "
                        f"{balance['asset_code']}:{balance['asset_issuer']}")
                    if MultiSigTransactions.requires_multisig(transaction):
                        MultiSigTransactions.save_as_pending_signatures(
                            transaction)
                        continue

                    if PendingDeposits.submit(transaction):
                        transaction.refresh_from_db()
                        try:
                            rdi.after_deposit(transaction)
                        except Exception:
                            logger.exception(
                                "An unexpected error was raised from "
                                "after_deposit() in check_trustlines")
Exemple #9
0
 def execute_deposits(cls):
     pending_deposits = Transaction.objects.filter(
         kind=Transaction.KIND.deposit,
         status=Transaction.STATUS.pending_user_transfer_start,
     )
     try:
         ready_transactions = rdi.poll_pending_deposits(pending_deposits)
     except NotImplementedError as e:
         raise CommandError(e)
     for transaction in ready_transactions:
         try:
             success = execute_deposit(transaction)
         except ValueError as e:
             logger.error(f"poll_pending_transactions: {str(e)}")
             continue
         if success:
             rdi.after_deposit(transaction)
Exemple #10
0
 def execute_deposits(cls):
     """
     Right now, execute_deposits assumes all pending deposits are SEP-6 or 24
     transactions. This may change in the future if Polaris adds support for
     another SEP that checks for incoming deposits.
     """
     module = sys.modules[__name__]
     pending_deposits = Transaction.objects.filter(
         kind=Transaction.KIND.deposit,
         status=Transaction.STATUS.pending_user_transfer_start,
     )
     try:
         ready_transactions = rri.poll_pending_deposits(pending_deposits)
     except Exception:  # pragma: no cover
         # We don't know if poll_pending_deposits() will raise an exception
         # every time its called, but we're going to assume it was a special
         # case and allow the process to continue running by returning instead
         # of re-raising the error. The anchor should see the log messages and
         # fix the issue if it is reoccurring.
         logger.exception(
             "poll_pending_deposits() threw an unexpected exception")
         return
     if ready_transactions is None:
         raise CommandError(
             "poll_pending_deposits() returned None. "
             "Ensure is returns a list of transaction objects.")
     for transaction in ready_transactions:
         if module.TERMINATE:
             break
         try:
             success = execute_deposit(transaction)
         except ValueError as e:
             logger.error(str(e))
             continue
         if success:
             # Get updated status
             transaction.refresh_from_db()
             try:
                 rdi.after_deposit(transaction)
             except Exception:  # pragma: no cover
                 # Same situation as poll_pending_deposits(), we should assume
                 # this won't happen every time, so we don't stop the loop.
                 logger.exception(
                     "after_deposit() threw an unexpected exception")
 def execute_deposits(cls):
     pending_deposits = Transaction.objects.filter(
         kind=Transaction.KIND.deposit,
         status=Transaction.STATUS.pending_user_transfer_start,
     )
     try:
         ready_transactions = rdi.poll_pending_deposits(pending_deposits)
     except NotImplementedError as e:  # pragma: no cover
         # Let the process crash because the anchor needs to implement the
         # integration function.
         raise CommandError(e)
     except Exception:  # pragma: no cover
         # We don't know if poll_pending_deposits() will raise an exception
         # every time its called, but we're going to assume it was a special
         # case and allow the process to continue running by returning instead
         # of re-raising the error. The anchor should see the log messages and
         # fix the issue if it is reoccuring.
         logger.exception(
             "poll_pending_deposits() threw an unexpected exception")
         return
     for transaction in ready_transactions:
         try:
             success = execute_deposit(transaction)
         except ValueError as e:
             logger.error(str(e))
             continue
         if success:
             # Get updated status
             transaction.refresh_from_db()
             try:
                 rdi.after_deposit(transaction)
             except Exception:  # pragma: no cover
                 # Same situation as poll_pending_deposits(), we should assume
                 # this won't happen every time, so we don't stop the loop.
                 logger.exception(
                     "after_deposit() threw an unexpected exception")
Exemple #12
0
    def check_trustlines():
        """
        Create Stellar transaction for deposit transactions marked as pending
        trust, if a trustline has been created.
        """
        module = sys.modules[__name__]
        with django.db.transaction.atomic():
            transactions = list(
                Transaction.objects.filter(
                    kind=Transaction.KIND.deposit,
                    status=Transaction.STATUS.pending_trust,
                    pending_execution_attempt=False,
                ).select_for_update()
            )
            ids = []
            for t in transactions:
                t.pending_execution_attempt = True
                ids.append(t.id)
            Transaction.objects.filter(id__in=ids).update(
                pending_execution_attempt=True
            )
        server = settings.HORIZON_SERVER
        accounts = {}
        for i, transaction in enumerate(transactions):
            if module.TERMINATE:
                still_process_transactions = transactions[i:]
                Transaction.objects.filter(
                    id__in=[t.id for t in still_process_transactions]
                ).update(pending_execution_attempt=False)
                break
            if accounts.get(transaction.stellar_account):
                account = accounts[transaction.stellar_account]
            else:
                try:
                    account = (
                        server.accounts().account_id(transaction.stellar_account).call()
                    )
                    accounts[transaction.stellar_account] = account
                except BaseRequestError:
                    logger.exception(
                        f"Failed to load account {transaction.stellar_account}"
                    )
                    transaction.pending_execution_attempt = False
                    transaction.save()
                    continue
            for balance in account["balances"]:
                if balance.get("asset_type") == "native":
                    continue
                if (
                    balance["asset_code"] == transaction.asset.code
                    and balance["asset_issuer"] == transaction.asset.issuer
                ):
                    logger.info(
                        f"Account {account['id']} has established a trustline for "
                        f"{balance['asset_code']}:{balance['asset_issuer']}"
                    )
                    try:
                        requires_multisig = PendingDeposits.requires_multisig(
                            transaction
                        )
                    except NotFoundError:
                        PendingDeposits.handle_error(
                            transaction,
                            f"{transaction.asset.code} distribution account "
                            f"{transaction.asset.distribution_account} does not exist",
                        )
                        break
                    except ConnectionError:
                        logger.error("Failed to connect to Horizon")
                        transaction.pending_execution_attempt = False
                        transaction.save()
                        break
                    if requires_multisig:
                        PendingDeposits.save_as_pending_signatures(transaction)
                        break

                    try:
                        success = PendingDeposits.submit(transaction)
                    except Exception as e:
                        logger.exception("submit() threw an unexpected exception")
                        PendingDeposits.handle_error(
                            transaction, f"{e.__class__.__name__}: {str(e)}"
                        )
                        break

                    if success:
                        transaction.refresh_from_db()
                        try:
                            rdi.after_deposit(transaction)
                        except Exception:
                            logger.exception(
                                "after_deposit() threw an unexpected exception"
                            )
            if transaction.pending_execution_attempt:
                transaction.pending_execution_attempt = False
                transaction.save()