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")
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")
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")
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)
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")
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()