-
Notifications
You must be signed in to change notification settings - Fork 390
feat(wallet): add TxBuilder::replace_tx
#1799
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ConceptACK, ApproachACK.
Just need to make sure we don't use descendant outputs from tx we are trying to replace.
It's out of the scope of this PR, the inability to set both feerate/fee amount constraints together really bothers me. We should probably switch to the bdk_coin_select
crate soon.
1e9caf4
to
3acc39b
Compare
3acc39b
to
f753f5e
Compare
I made a few small changes including a test for unspendable descendants. I'm still open to discussing the right UX for |
f753f5e
to
f4c6960
Compare
Since still some open ux design questions I removed this from the 1.1 milestone. |
affd516
to
5166785
Compare
5166785
to
ab4c3dc
Compare
ab4c3dc
to
dae5d73
Compare
Since |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
utACK dae5d73
My 2 sats on adding replace_tx_input
is it should wait until if/when someone has a need for it.
tACK dae5d73 nit: When the discussion is finalized, it would be great to consider adding a test case for |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
utACK dae5d73
@evanlinjin your above comments were addressed ok to resolve those comments so we can merge this one in 1.2? |
- Add method `TxBuilder::previous_fee` for getting the previous fee / feerate of the replaced tx.
dae5d73
to
8c01a67
Compare
Looks pretty good to me on a first glance. I'll double check over it tomorrow to make sure and I'll ACK/merge. |
// the output should be unspent unless we're doing a RBF | ||
if self.params.bumping_fee.is_none() && output.is_spent { | ||
return Err(AddUtxoError::UnknownUtxo(*outpoint)); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I guess we changed this so that we can call it in replace_tx
without having it return an error?
However, when we do RBF, it doesn't mean we want to be able to replace every spend.
To avoid this potential footgun, the ideal approach would be to use something like CanonicalizationParams::assume_not_canonical
in #1809 (which is not helpful here).
Another idea would be to NOT modify add_utxos
and use something custom for replace_tx
.
However, add_utxos
is problematic anyway because "these have priority over the unspendable utxos". So we can still create txs that selects "outputs of the replaced tx as inputs to the replacement".
Would it make more sense to change our logic to make "unspendables" have precedence? It does seem to be safer in this regard.
Ideally, we want to change add_utxos
to disregard the is_spent
of outputs that are inputs of the tx-to-replace. We can do this by observing the "unspendables" list and if the output is spent by something of the unspendables, we consider it unspent. We can do this by keeping track of the spends of the tx-to-replace.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We can do this by keeping track of the spends of the tx-to-replace.
I went with this idea and pushed an update f1f57d4.
…outputs Having `params.bumping_fee` mediate replaceability was too broad in that it would allow selecting any previously spent output regardless of whether we opted into replacing the original tx. Instead we introduce `TxParams::replacing` member to keep track of the outpoints that may be re-selected for an RBF. The implementation of `replace_tx` is changed to populate the `replacing` set with all of the original outpoints. This signals to the TxBuilder that any of the original inputs may be replaced, although we still only pick one as the argument to `add_utxo`.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There are still a bunch of issues with this implementation that may result in footguns for the caller. However, I'm not sure if it is worth tackling here because the users really want this now and the only way to solve everything correctly is to use CanonicalizationParams
which will not be available until bdk_wallet 2.0
. Let me list them out below:
Given 2 unconfirmed txs (A, B)
, where B
spends A
. If the caller does replace_tx(A)
, then calls add_utxo(some-output-of-B)
, we will create a tx that simultaneously replaces A
and spends from a descendant of A
.
Given 2 unconfirmed txs (A, B)
, where B
spends A
. If the caller does replace_tx
on both A
and B
, we will be creating a replacement of A
& B
that tries to spend from A
.
Doing this logic in TxBuilder
means introducing more footguns.
I would prefer if we just create a no-bdk-wallet dependency function that takes in a bunch of params to create an RBF tx. create_rbf(params: RBFParams) -> Result<Psbt, Error>
. This way this feature is release-agnostic, does not introduce footguns and can be used without a bdk_wallet
dependency.
I created a some proposed specifications for this create_rbf
function.
I’m glad to see this getting solid attention in review and and hope we find a good API for users (good meaning usable with minimal footguns, but also existing!). I am, however, hesitant about shelving an approach that has working code and could be immediately useful, especially in favour of an alternative that, while promising on paper, currently has:
I’m not trying to block progress or be antagonistic—I just want to advocate a bit for users of bdk_wallet. They form our biggest user base, and shipping something that’s imperfect but works today often ends up being more valuable for them than waiting on something ideal that might still be quite a ways off. |
@thunderbiscuit there is a working implementation. I did this in a single day. Check We won't need to wait until v2.0 to have this since it lives outside of In terms of tests, a bunch of the heavy lifting is in The old codebase is a mess and is hard to reason about. I spent half a day reviewing this PR. I prefer putting my time into fixing it up for good. |
I want to give an update for anyone following this PR/thread. I had a really good offline conversation with @evanlinjin, and it gave me an idea of what the next steps are for me. The gist of my hesitation above revolves around the giving up of a useful feature that's ready to go (this PR) in exchange for an alternative for which I don't have a clear understanding of "readiness". Are we at the design phase? The hammering the details phase? How probable is it that users could leverage it in the 1.3/1.4 timeline? (June/August respectively). This new crate (bdk-tx) has 2 PRs. It's fairly new. But also super promising. Doing away with code that is hard to reason about and leveraging the lessons we've learned over the past 4 years of using the TxBuilder is very appealing. I want to be on board, at least to understand better where this is going. Here is what I think is missing at this point for bdk-tx to make a strong case for itself:
Here is what I commit to:
|
This PR adds a new method
TxBuilder::replace_tx
that offers a simple way of creating replacements without relying on the mechanics ofbuild_fee_bump
. See #1374 for context and motivating discussion.In summary, there are a few limitations with the current
build_fee_bump
:In contrast
replace_tx
is useful when we only need to create a conflict and flexible enough to further tweak the parameters as desired.Notes to the reviewers
TxBuilder::add_utxos
is modified to look for potentially spent outputs, provided that the given outpoint exists in the replaceable set.Changelog notice
TxBuilder::replace_tx
TxBuilder::previous_fee
Checklists
All Submissions:
cargo fmt
andcargo clippy
before committingNew Features: