-
Notifications
You must be signed in to change notification settings - Fork 38.7k
policy/rbf: don't return "incorrect" replaceability status #22665
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
mjdietzx
left a comment
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 like the simplification this PR provides and think it's nicely done. But, my main concern is that existing applications/users might currently rely on bip125-replaceable for this type of behavior:
// Applications relying on first-seen mempool behavior should
// check all unconfirmed ancestors; otherwise an opt-in ancestor
// might be replaced, causing removal of this descendant.
which after this PR won't be the case.
Based on the description of bip125-replaceable:
Whether this transaction could be replaced due to BIP125 (replace-by-fee)
even though the transaction can't be directly replaced in the mempool, it can effectively be replaced by replacing one of its ancestors that does explicitly signal RBF.
What are your thoughts on this? I'm just wondering what direction this PR moves us in long-term as I saw some good discussion/ideas from @ariard and @ajtowns in #21946
|
The following sections might be updated with supplementary metadata relevant to reviewers and maintainers. ConflictsReviewers, this pull request conflicts with the following ones:
If you consider this pull request important, please also help to review the conflicting pull requests. Ideally, start with the one that should be merged first. |
If they rely on this, then they are already broken (as demonstrated by CVE-2021-31876). This is the point of this PR actually, and i would argue it is actually a bugfix. |
I'm specifically referring to this comment in
Before your PR, applications could do this check by just reading the result of But after your PR, this is no longer the case. I see that your PR fixes the bug from the perspective of "I know I can replace this transaction based on the value of |
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.
Concept ACK. Technically, we are returning the correct BIP125 replaceability of a transaction, but it's not useful for a client to get this information since it doesn't actually reflect what would happen in their mempool. I also agree with the cleanup of RBFTransactionState and other no-longer-used code.
I think it would be better to add a new RPC field "replaceable" (since it's not really BIP125) to return this as a bool result, and remove "bip125-replaceable" or make it an alias of "replaceable" and remove it later.
|
Is this commit message: |
eba9666 to
a50a332
Compare
glozow
left a comment
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.
Approach ACK
have a few tiny nits 😅 could also use a functional test for the deprecation behavior, e.g. something like this
maflcko
left a comment
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.
Funny that this bugfix removes more than 100 lines of code
The approach that Core would be taking to address the discrepancy between the BIP and the Core implementation surely wasn't? |
Under the assumption that Core will maintain its current mempool behavior (versus changing it to meet the BIP wording because that is deemed superior logic) I agree it isn't tricky. But making that assumption in the first place seems tricky to me. A short term stopgap with minimal code changes in anticipation of full RBF or a more invasive code change for what some deem superior logic in the meantime as full RBF might never land. (I think that's where we are anyway). Let's at least be transparent about that rather than glossing over it. |
|
Does it really fix #22209? The new |
The
The newly added one is a subset of the removed one here, so i'm not sure to get how having both would help. |
I know that the new field doesn't do that. My point was that with the old field, you could see |
2280b31 to
7ead459
Compare
|
Fixed the bad english in the |
|
I think the discussion on the Approach (N)ACK part of this PR and comparing the approaches of #22665 versus #22698 has been weak and almost dismissive (the BIP isn't a standard etc). In my view @mjdietzx @rajarshimaitra have a valid perspective including in @mjdietzx's case coding up and opening an alternative PR. @laanwj said on IRC:
From the above I'm an Approach ACK on this PR meeting shorter term user needs and think a rebased #22698 can/should be considered post the merging of this PR. But my gosh, unless we want to ditch the Concept ACK, Approach ACK part of the PR review process I'd hope we can do better in these kinds of scenarios where someone presents a competing PR.... |
|
Great comment too earlier from @glozow on this PR (which was deleted but I don't think it should have been)
|
As disclosed by CVE-2021-31876, the mempool acceptance logic doesn't implement BIP125's inheritance rule. However, we were still mistakenly reporting transactions that don't explicitly signal for RBF as being replaceable. Signed-off-by: Antoine Poinsot <[email protected]>
The enum was only needed for the "unknown" RBF state of a transaction when we can't fetch its ancestors. Since we don't actually implement inherited RBF signaling, the replaceability of a transaction is only a function of itself and cannot be unknown. This also does a bit of cleanup, as there is no need for the RBF check to be part of the node interface since we don't need the mempool anymore.. Signed-off-by: Antoine Poinsot <[email protected]>
To avoid linking against server. For example, using it to deprecate an RPC in wallet/rpcwallet would require libbitcoin_wallet to link against rpc/server and all its dependencies. Signed-off-by: Antoine Poinsot <[email protected]>
This doesn't need to be a string anymore. And mentioning BIP125 is confusing, as we technically don't return the replaceability as defined by BIP125 (which includes the inheritance rule). Signed-off-by: Antoine Poinsot <[email protected]>
Signed-off-by: Antoine Poinsot <[email protected]>
7ead459 to
cc091fa
Compare
|
Rebased after #22796 merge. |
glozow
left a comment
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.
ACK cc091fa
My assumption was that this RPC result would be used to see if the inputs can be used in an RBF transaction (I don't think anything can be expected to stay in the mempool)? And since a transaction can always be evicted due to higher fee transactions squeezing it out of the mempool, I thought of replaceable as "does this transaction signal for rbf" rather than "can this transaction be replaced" which is always yes.
I can also see how replaceable could naturally be defined as "can this transaction be evicted due to RBF," so maybe calling the result "signals-rbf" would be more accurate. @MarcoFalke's suggestion of an enum of reasons makes sense to me too.
| entry.pushKV("bip125-replaceable", rbfStatus); | ||
| const bool signals_rbf = confirms <= 0 && SignalsOptInRBF(*wtx.tx); | ||
| entry.pushKV("replaceable", signals_rbf); | ||
| if (IsDeprecatedRPCEnabled("bip125")) { |
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.
In 26c7fc0 rpc: deprecate 'bip125-replaceable' in favour of 'replaceable'
Could you grab this via the Chain interface, i.e. call chain.rpcEnableDeprecated("bip125") instead of moving IsDeprecatedRPCEnabled() to util? Or is it better to do it this way and take the opportunity to remove rpcEnableDeprecated by changing this one too? (maybe scope creepish, sorry)
|
I think there is a difference between "This tx can be evicted due to mempool size if there are 300 MB worth of txs on top of it" and "This tx can be replaced by a single tx that pays a higher fee than the tx(s) it evicts". I think it makes sense to distinguish the mempool removal reasons, as it is done internally in the code as well: enum class MemPoolRemovalReason {
EXPIRY, //!< Expired from mempool
SIZELIMIT, //!< Removed in size limiting
REORG, //!< Removed for reorganization
BLOCK, //!< Removed for block
CONFLICT, //!< Removed for conflict with in-block transaction
REPLACED, //!< Removed for replacement
};NACK from me on the changes here. |
|
Sigh. Removal reason has nothing to do with this PR. I have no intention to continue tweaking the RPC code nor keeping up with your nitpicks, i initially picked this up because the current interface is wrong and misleading hence potentially dangerous for downstream users. But as you wish, i guess. |
|
Thanks to everyone who helped moving this forward. This is up for grabs, i guess. |
This was a reply to the previous comment (#22665 (review)), which mentioned that txs can be evicted from the mempool for reaching the size limit.
I hope you didn't close this pull request because I left a comment with a concern (which is not a nitpick). I want to apologise for leaving nitpicks before reviewing the concept of the pull.
I agree. Though, I also think that the interface proposed in this pull request isn't crystal clear about the fee replacability status of the tx, which is why I raised the concern. |
|
@MarcoFalke sorry for overreacting.
Ok, then we could go for the minimal fix (which i initially proposed, to stop returning Regarding the interface, you proposed:
I think of those only So, how about going first going for the minimal fix here and then proceed with something like #16490 to deprecate |
The rule isn't implemented fully, but surely is implemented partially in Bitcoin Core. Bitcoin Core simply has the additional requirement that an rbf-signalling parent must be replaced in the same instance. Not implementing the rule (or rather implementing the inverse of the rule) would mean: A non-signalling child tx could remove the signalling status from a parent, and thus prevent replacement. This is what a plain |
|
For the benefit of reviewers this PR was NACKed by @MarcoFalke and it appears that @glozow is now comfortable with the approach taken in #22698 which was earlier seen as a competing PR. This PR is currently closed but I think it is more important we get the approach right than just blindly picking whichever PR is kept open by its author. However, it does seem that @MarcoFalke, @glozow @mjdietzx @ariard etc are comfortable with the approach taken in #22698. Thanks for the work on this @darosior, sorry for the frustration you've experienced. I've certainly wavered on this and seems like others have been unsure too. |
We were still reporting transactions that inherited signaling as being replaceable in
IsRBFOptIn.In addition, the second commits does a bunch of refactoring by getting rid of
IsRBFOptInentirely and removing the check for RBF from the node interface since we actually don't need access to the mempool.Related to #22209, kinda followup of #21946.