Bitcoin Core's coin selection algorithms optimizes mostly for the following metrics:
- keep a low utxo count by consolidating regularly
- avoid creating a change output
- when a change output is needed, use an amount equivalent to the payment (for privacy)
This doesn't match what liquidity providers need. Liquidity providers need to:
- keep a large enough utxo pool
- keep a diversity of utxo amounts that matches what we're selling
- use as few inputs as possible when funding transactions
- avoid creating change outputs most of the time
We'll need to either tweak the existing coin selection algorithms to match those goals, or write our own coin selection algorithm. Ideally this will take the form of a branch on top of Bitcoin Core's release branches, that is easy to rebase from one release to the other. Even more ideally this code would be accepted into Bitcoin Core.
We'd like to configure our Bitcoin Core node with a description of our ideal utxo set, which consists of buckets of specific amounts. This would probably be an array of the following form:
[
{
"bucket_start_satoshis": 10000,
"bucket_end_satoshis": 25000,
"target_utxo_count": 150,
},
{
"bucket_start_satoshis": 50000,
"bucket_end_satoshis": 75000,
"target_utxo_count": 50,
},
{
"bucket_start_satoshis": 200000,
"bucket_end_satoshis": 250000,
"target_utxo_count": 20,
},
{
"bucket_start_satoshis": 1000000,
"bucket_end_satoshis": 1400000,
"target_utxo_count": 5,
}
]
Bitcoin Core should try to make our utxo set converge towards that ideal utxo set. That ideal utxo set is crafted by the node operator to ensure that most funding attempts require few inputs for its expected business operations.
Since one of the goals of the coin selection algorithm is to produce transactions that don't have any change output, the buckets will gradually empty themselves. There should be two mechanisms to refill the utxo buckets:
- opportunistic refill
- low-feerate active refill
Whenever we're unable to produce a transaction that doesn't have a change output, we should opportunistically create change outputs that refill the most depleted buckets (even if that means adding more inputs).
If the current mempool feerate is below a configured threshold (bucket_refill_feerate
), we should actively create change outputs to refill depleted buckets (note that it's perfectly fine, and even beneficial to create multiple change outputs in one single transaction).
Otherwise, when we're running too low on utxos in some buckets (with a threshold to be defined), we should force the creation of change outputs, regardless of the current feerate.
We probably don't need an algorithm that finds an optimal solution in terms of fees, since this is a long term game, where creating new change outputs may cost us more now, but save us some money later.
The parameters from the previous section should be persistent, but it would be nice to be able to update them without having to restart bitcoind
.
Not sure how that would work though (maybe bitcoind
could regularly read from a configuration file?).
TODO!