bitcoinerlab / coinselect

A TypeScript library for Bitcoin transaction management, based on Bitcoin Descriptors for defining inputs and outputs. It facilitates optimal UTXO selection and transaction size calculation.
9 stars 3 forks source link

CPFP #3

Open louneskmt opened 8 months ago

louneskmt commented 8 months ago

Hey! I'm trying to use this to build a transaction that CPFP another one. It could be useful to have an option to specify the previous transaction fee rate, so the algorithm can take it into account. I can add this, but would need to check with you @landabaso the best way to do it. We need to know the previous transaction fee rate, so we can compute a new fee rate from the given fee rate and the previous one: newFeeRate = 2 * feeRate - previousFeeRate (with feeRate > previousFeeRate otherwise it wouldn't bump anything). Then use that new fee rate as replacement of the input fee rate in the algos.

louneskmt commented 8 months ago

Now that I think about it, I can definitely do this calculation outside of the library haha.

louneskmt commented 8 months ago

But I still need a way to coinselect for only one output: the change. maxFunds doesn't do any coin selection and coinselect validates that targets is not empty. And to force specific utxos (the anchor) to be selected as well.

landabaso commented 8 months ago

Thank you for your message. I would need to make sure I fully undestand the approach you're planning to implement outside of the library. Regarding maxFunds, your understanding is right - it's indeed set up to use all available UTXOs. And coinselect is designed to validate that the targets array is not empty. This validation ensures there's at least one output for the transaction.

I would need a more detailed explanation of your specific requirements.

louneskmt commented 8 months ago

The goal is to bump a previous transaction fee using Child Pay For Parent. So, I need to build a transaction that spends given (unconfirmed) UTXOs to a single change target.

The current coinselect:

What would be necessary to do a proper CPFP:

What we could do would be:

Thinking about it, we could even replace maxFunds by that selfPayment function if we give it no UTXOs to select, and only fixed UTXOs to always include.

Is that clearer?

landabaso commented 8 months ago

add another function like maxFunds but for a self-payment, that would take no target, only a change

That's the part I don't understand. You can already use maxFunds with an empty array of targets. And then pass your change to remainder.

See, for example: https://github.com/bitcoinerlab/coinselect/blob/b568bf81e1a0d5eb9347a4d90c2132474a2ac95d/test/fixtures/maxFunds.json#L41

louneskmt commented 8 months ago

Sure but it doesn't select UTXOs, it spends all of them. For example, I have a 1000 sats anchor output I want to spend to bump the transaction fees. 1000 sats isn't enough to pay for the high fees, so I need to add some UTXOs to the inputs, and I need to select these UTXOs.

landabaso commented 8 months ago

I see. So this is a tx you want to unstuck by sending it back completely to yourself. Right?

What about using coinselect with a SegWit remainder, even if you end up not utilizing it? After running coinselect, you'll have two targets: the real one and the remainder.

You could add the values of these two targets together. Then, build a transaction using only the real target address but using the sum of the 2 targets as value.

Of course, coinselect will have computed the transaction assuming an extra output, so you'll actually be paying a slightly higher fee to the miner.

If desired, you can adjust this by adding back the excess fee to the real output, with something like this: realTargetValue = realTargetValue + remainingTargetValue + (feeRate * remainingOutput.outputWeight() / 4). Does this approach make sense?

louneskmt commented 8 months ago

What about the extra input for the anchor?

I'm sure I could get it done with some tricky workarounds (like I am currently doing), but it feels like it would be nice to get this natively? If we settle on an API, I can make a PR 👍