stellar / django-polaris

An extendable Django app for building modular Stellar services
https://django-polaris.readthedocs.io
Apache License 2.0
94 stars 70 forks source link

Channel Payments Design #596

Open reecexlm opened 2 years ago

reecexlm commented 2 years ago

Purpose: Based on results from load testing deposit transaction submission in Polaris (https://github.com/stellar/django-polaris/issues/589), it can be seen that transaction throughput is currently limited by Polaris only being able to submit one transaction at a time.

With the addition of channel accounts, Polaris will be be able to submit transactions to the Stellar Network in parallel (based on the number of channel accounts used).

Creating / Importing Channel Accounts Into Polaris Channel Accounts will be created/imported into Polaris via a script. The script can be executed similar to existing Django-Polaris commands (examples below). The secret key of the channel accounts will be encrypted in the database the same way distribution seeds are currently encrypted for Assets.

Script Features:

Create N channel accounts on the testnet python manage.py polaris-tool --action create-channel-accounts --count <count> --testnet true Create N channel accounts on the mainnet python manage.py polaris-tool --action create-channel-accounts --count <count> --distribution-seed <distribution_seed> Delete all channel accounts from the database python manage.py polaris-tool --action delete-channel-accounts Create an Asset in Polaris python manage.py polaris-tool --action create-asset --asset-name <asset_name> --issuer <issuer> --<distribution_seed> --sep6-enabled true --deposit-enabled true Delete an Asset in Polaris python manage.py polaris-tool --action delete-asset --asset-name <asset_name>

Polaris changes: Add a polaris_channel_accounts table to the database with public key and secret (encrypted) columns.

Currently, process_pending_deposits.py is the only process that submits transactions to the Stellar Network and this is the case for the foreseeable future. Because of this and for simplicity, it’s proposed that this process will read all the channel accounts into memory at startup and maintain them in memory. process_pending_deposits.py already has a locking mechanism in place that ensures only one instance of it can be running at any given time so we don’t need to worry about another instance using the same channel accounts.

Using Channel Accounts:

Option 1: Bulk Processing Have a task that periodically gets all transactions from the SUBMIT_TRANSACTIONS_QUEUE and create a “submit transaction” task for each one. Each task will also be assigned a channel account to use. This is more of a “polling” model and transaction processing time will be affected by the polling interval but may be better able to handle large bursts of deposit transactions.

Option 2: Pool of Executors (Preferred Option) Spawn N “submit transaction” tasks at startup and assign a channel account to each one. The tasks will all consume from the SUBMIT_TRANSACTIONS_QUEUE (asyncio queue where transactions that are ready to be submitted are put in this queue) and block until there is data. This is an “event driven” model and will be optimal for handling a steady flow of deposit transactions but may not be suited for large bursts of deposit transactions since only N “submit transaction” tasks are spawned at startup.

Paying Transaction Fees:

Option 1: Fund All Channel Accounts Fund all channel accounts with N lumens and have the channel accounts pay transaction fees for the transactions they submit. We will need a way to monitor and maintain the balance of the channel accounts.

Option 2: Fee-Bump (Preferred Option) Utilize Fee-Bumps, we only need to maintain the lumens balance of one account that will be used to pay the transaction fees on behalf of the channel accounts.

“The source account of the transaction pays the fee and consumes a sequence number. You can then use one common account (your base account) to make the payment operation inside each transaction. The various channel accounts will consume their sequence numbers even though the funds are being sent from your base account. You will, of course, have to sign the transaction with both the base account key and the channel account key.”

source: https://developers.stellar.org/docs/glossary/fee-bumps/

JakeUrban commented 2 years ago

@reecexlm this issue belongs in stellar/django-polaris, can you (or @stfung77) move it there?

JakeUrban commented 2 years ago

@stfung77 This is a great write-up.

Command / Script

I'd like to take step back and ask, do we really need this? My gut says "This is what Django's admin UI is for". If you're unfamiliar with the Django Admin UI, check this out.

The reason we haven't used this in the past is because we didn't ever want the login page to be accessible on public instances. But I think it is overly opinionated for Polaris to not provide ModelAdmin. Instead, we should provide these and let anchors decide if / how they want to host the Django Admin UI, where they can create/edit/delete all of Polaris' models.

For example, we could continue running testanchor.stellar.org as-is without any admin UI, but run a private instance of another Django application with Polaris installed that connects to the same database, and this instance could host the admin UI.

Our ops team already has a system we could use for this.

If we do go with the CLI

If we did build this command, I do think we need to redesign the interface.

I suggest we create another command db with the following subcommand / args structure:

I think we should leave creating Asset objects out of scope, because for completeness we should also add the same kind of tool for all relevant models (ex. OffChainAsset).

Channel Accounts

I don't see a reason not to go with option 2.

Paying Transaction Fees

Again, I think option 2 is the clear pick, however using Fee Bump Transactions only pays for tx fees, not for XLM account reserves. If the distribution account also sponsors the channel account's reserves, then each channel account can have 0 XLM.

stfung77 commented 2 years ago

Discussed with @JakeUrban last week and settled on the following: