Blog Article
Author
Marta Lokhava
Publishing date
Transaction submission
TL;DR
We’re proposing an update to stellar-core to allow 1 transaction per source account per ledger. This means that if a Stellar node is currently processing a transaction from account A, any new transaction from A will be rejected, and will need to be re-submitted later. “Processing” refers to the time period between a transaction entering the transaction queue and being applied to the ledger or dropped. Core will accept new subsequent transactions as soon as the previous transaction is either confirmed or dropped due to surge pricing.
Users should not see any impact to fee bump functionality. That is, if a fee-bump transaction arrives with the same or different fee source and the inner transaction is already present in the transaction queue, the new transaction will not be rejected, and instead will replace the previous transaction (assuming that fee bump is valid, of course). In addition, the same account is allowed to pay for multiple fee bumps per ledger (assuming that bumped transactions have different source accounts).
Users utilizing channel accounts are unaffected, assuming the same channel account does not submit multiple transactions per ledger. Furthermore, using channel accounts is our recommended solution for transaction scaling (more on this below).
This change would introduce some restrictions to the Stellar network, but we believe that this is a positive change that will improve the experience of interacting with the network because:
Several examples below illustrate the challenges around scaling transaction throughput with multiple-transactions-per-account mechanism.
Stellar-core drops transactions that arrive out of order (with “bad sequence number” error). Horizon tries to protect against that by reordering transactions in-memory, but there are caveats:
*This isn’t always true, as sometimes Horizon reports timeouts on transactions that aren’t _actually_ dropped by the network.
The current behavior makes transaction submission results quite unpredictable when the network is experiencing surge pricing* (which occurs frequently on the network). Specifically, if account A submits T1..TN to the queue, while the network is in surge pricing, all new transactions will be stuck until T1 is included in the ledger (even if T2…TN have very high fees). Even worse, if T1 is dropped, all subsequent transactions have to be dropped and re-submitted. If the user wants to fee-bump some transactions, they’ll need to fee-bump all transactions ahead for fee bumps to have any effect.
*surge pricing is an event when there are more transactions wanting to get into the block than the network allows, causing the network to prioritize transactions with highest fees
In addition to the reasons above, this change is necessary to safely support Soroban. Soroban transactions are quite different from current transactions: they are potentially much bigger in size, and use a multi-dimensional fee model. Stellar-core has various built-in security features, and SDF works with the broader ecosystem to suggest improvements that help ensure the network is robust and resilient. Switching to 1 transaction/account limit allows propagating Soroban transactions in a way that protects against denial of service attacks.
Because the same source accounts pay fees for both Stellar and Soroban transactions, and due to limitations/complexity of the stellar-core implementation, this solution applies to all transactions submitted to stellar-core.
Before suggesting this change, we took a look at historical data which suggests that the number of accounts with multiple transactions per ledger is very low. For impacted users, channel accounts are the recommended solution for submitting transactions to the network at a high rate because:
The new limit is needed for Protocol 20, which introduces Soroban support, to function correctly. That is, the limit needs to be enforced network-wide before nodes vote to upgrade to Protocol 20. The proposed timeline is as follows:
Is your experience different from what’s described above? Do you think this isn’t the right change? Let us know! We want to understand your use case, and help you find the best solution.