In this post I’ll discuss the mempool transaction processing in Stacks 2.0 and go over some best-practices and known-issues.
For starters, what is the mempool? From the Bitcoin wiki: “a node’s memory pool contains all 0-confirmation transactions across the entire network that that particular node knows about” (emphasis mine). So, the set of transactions in the mempool might be different for each node. For instance, when you query the mempool endpoints on
stacks-node-api.mainnet.stacks.co, that reflects the set of unconfirmed transactions known to nodes that service the API.
Miners can also employ different heuristics and strategies for deciding 1) which transactions to admit into the mempool and 2) which transactions to pick from the mempool when mining a block. Some transactions might be rejected outright (e.g. if there are insufficient funds at an address) while others might be accepted, but then not get mined indefinitely (e.g. if the fees are too low). Transactions that are admitted in the mempool but not yet mined are said to be “pending”. The current implementation of stacks-blockchain discards pending mempool transactions after 256 blocks.
Nonce: It is crucial that transactions use the correct nonce. Using an incorrect nonce makes it less likely that the transaction will get mined in a timely manner. To determine the correct value, simply query the node that you intend to broadcast your transaction to, e.g.
https://stacks-node-api.mainnet.stacks.co/v2/accounts/SP1V21EG2APTB57VXEM9BK4TFWK1GN8NYW5DB0Q46?proof=0. The value of the “nonce” field is what you should use: it is the next nonce the node expects to consume. Nonce starts at 0, so the very first transaction from an address should set
Transaction chaining: Of course, even when using the correct nonce, transactions might arrive at a node out-of-order. For instance, a transaction with
nonce=0. Stacks nodes admit such out-of-order transactions in the mempool, but up to a limit (25 in the current implementation). So limit any “chain” of unconfirmed transactions from a single address to less than 25. Making this limit higher has downsides, discussed in this issue. If you need to send more than 25 transactions per block, consider using multiple addresses or better, a smart-contract based approach (see this tool for instance, that allows making up to 200 token-transfers within a single transaction).
As usual, Github is the source of truth for all known issues and whether they are fixed. Below are some of the known mempool related issues:
- If too many transactions accumulate in a node’s mempool, some of those transactions might not get re-processed in a timely manner. Right now nodes also don’t synchronize their mempools, so transactions in one node’s mempool might never make it to enough other miners to be mined. A robust way to address this is to introduce an anti-entropy protocol for mempool (GH issue).
- Mitigation: node operators can manually re-push transactions to other nodes using this script.
- There’s an edge case that manifests during short-lived forks on the Stacks chain (GH issue) where some mempool transactions might never get processed; they remain pending until garbage collected.
- Mitigation: re-broadcasting the pending transaction with slightly higher fee should work. Meanwhile, a fix is in-review and would have to be deployed by miners to take effect.
- Mempool transactions are evaluated in “most recent first” order. For chained transactions, it would be better to process them in nonce-order instead (GH issue).
- Mitigation: avoid building very long chains of unconfirmed transactions.
- Prior to the Stacks Wallet for Desktop version 4.0.4, if a user attempted to make a second transaction while one of their previous transactions was still unconfirmed, the second transaction could get stuck due to a conflicting nonce.
- Mitigation: update to version 4.0.4.