-
Notifications
You must be signed in to change notification settings - Fork 36.2k
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
Cluster size 2 package rbf #28984
Cluster size 2 package rbf #28984
Conversation
The following sections might be updated with supplementary metadata relevant to reviewers and maintainers. Code CoverageFor detailed information about the code coverage, see the test coverage report. ReviewsSee the guideline for information on the review process.
If your review is incorrectly listed, please react with 👎 to this comment and the bot will ignore it on the next update. 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. |
38ce2cb
to
5b216db
Compare
Added this to the tracking issue |
57e5fc7
to
56848f9
Compare
56848f9
to
be9d163
Compare
src/policy/rbf.cpp
Outdated
const CFeeRate replacement_miner_score(replacement_fees, replacement_vsize); | ||
|
||
for (const auto& entry : direct_conflicts) { | ||
const bool conflict_is_v3{entry->GetSharedTx()->nVersion == 3}; |
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.
this can't be hit yet; post-v3 it can. I can remove this, or leave a note, or both. It makes some package rbfs more useful
(edit: it's used in #29001 functional tests )
7aee728
to
1d859b0
Compare
So thinking conceptually about this, I'm most concerned by the new I think there are two issues with this approach:
Even though the current RBF logic is broken already, I'd prefer to avoid adding on to that while rolling out the package RBF implementation, just so that users don't get used to some kinds of replacements working that really shouldn't be. So I was wondering, can we deal with this by just restricting the topology of what we allow a package RBF to conflict with? Let's say we allow a replacement if the conflict set consists of either (1) a single transaction with no ancestors (and of course no descendants, since any descendants would be in the conflict set as well), or (2) two transactions that are in a parent-child topology, and that have no other in-mempool ancestors (or descendants, of course). In those situations, the maximum miner score you would have to consider is either the individual feerate of the parent tx or the ancestor feerate of the child, so the new logic should work perfectly. |
After offline discussion with @sdaftuar , I've worked on a set of prospective changes and pushed them to this branch as follow-on commits. Key change is that we will now only allow package RBF when the conflicted transactions are all in "clusters" of up to size 2. This allows us to calculate mining scores for each conflicted transaction, which means that post-cluster mempool, if we did this right, IIUC, the behavior should match with more general package RBF. |
f9ce967
to
385b6ca
Compare
db21a37
to
dd364f9
Compare
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 dd364f9. non-blocking nits that can go in a followup. Also needs a release note.
dd364f9
to
8f2f64c
Compare
Added a release note |
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.
Spent most time reviewing the core commit 612847a so far, which looks correct to me (though I'm not super-familiar with the details of the feerate diagram checks that are used in this PR for the first time in production code). Still planning on looking deeper at the tests and do another full review round. Left some non-blocking nits on the way.
Support package RBF where the conflicting package would result in a mempool cluster of size two, and each of its direct conflicts are also part of an up-to-size-2 mempool cluster. This restricted topology allows for exact calculation of miner scores for each side of the equation, reducing the surface area for new pins, or incentive-incompatible replacements. This allows wallets to create simple CPFP packages that can fee bump other simple CPFP packages. This, leveraged with other restrictions such as V3 transactions, can create pin-resistant applications. Future package RBF relaxations can be considered when appropriate. Co-authored-by: glozow <[email protected]> Co-authored-by: Greg Sanders <[email protected]>
400ad72
to
94ed4fb
Compare
@theStack part of splitting out the diagram stuff to a prep PR is that you can just assume it means "economically rational 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.
reACK 94ed4fb via range-diff
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.
re-ACK 94ed4fb
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.
Code-review ACK 94ed4fb
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 94ed4fb
// Each subpackage is allowed MAX_REPLACEMENT_CANDIDATES replacements (only checking individually here) | ||
if (atmp_result.m_replaced_transactions.size() > MAX_REPLACEMENT_CANDIDATES) { | ||
return strprintf("tx %s result replaced too many transactions", | ||
wtxid.ToString()); | ||
} |
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.
"result replaced" seems like the wrong tense to me, given that the transaction was not accepted. Should this perhaps be:
// Each subpackage is allowed MAX_REPLACEMENT_CANDIDATES replacements (only checking individually here) | |
if (atmp_result.m_replaced_transactions.size() > MAX_REPLACEMENT_CANDIDATES) { | |
return strprintf("tx %s result replaced too many transactions", | |
wtxid.ToString()); | |
} | |
// Each subpackage is allowed MAX_REPLACEMENT_CANDIDATES replacements (only checking individually here) | |
if (atmp_result.m_replaced_transactions.size() > MAX_REPLACEMENT_CANDIDATES) { | |
return strprintf("tx %s would replace too many transactions", | |
wtxid.ToString()); | |
} |
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.
done in follow-up
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 don't agree with this suggestion - we are checking the result of a transaction that was accepted here. So "would replace" is incorrect and "replaced" is correct.
assert_equal(f"package RBF failed: insufficient anti-DoS fees, rejecting replacement {package_txns3[1].rehash()}, not enough additional fees to relay; 0.00 < 0.00000{sum([tx.get_vsize() for tx in package_txns3])}", pkg_results3["package_msg"]) | ||
|
||
self.assert_mempool_contents(expected=package_txns1) | ||
self.generate(node, 1) |
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.
Maybe also add a success case in the end to prove that all the reasons for rejection were enumerated?
self.generate(node, 1) | |
self.log.info("Check non-heavy child with higher absolute fee will replace") | |
package_hex3_1, package_txns3_1 = self.create_simple_package(coin, parent_fee=DEFAULT_FEE, child_fee=DEFAULT_CHILD_FEE + Decimal("0.00000001") ) | |
pkg_results3_1 = node.submitpackage(package_hex3_1) | |
self.assert_mempool_contents(expected=package_txns3_1) | |
self.generate(node, 1) |
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.
wrote a better boundary test in this vein in follow-up, thanks. You actually need incremental added, not 1 sat.
assert 'package RBF failed: package feerate is less than parent feerate' in pkg_results5["package_msg"] | ||
|
||
self.assert_mempool_contents(expected=package_txns4) | ||
self.generate(node, 1) |
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.
self.generate(node, 1) | |
package_hex5_1, package_txns5_1 = self.create_simple_package(coin, parent_fee=DEFAULT_CHILD_FEE, child_fee=DEFAULT_CHILD_FEE) | |
pkg_results5_1 = node.submitpackage(package_hex5_1) | |
self.assert_mempool_contents(expected=package_txns5_1) | |
self.generate(node, 1) |
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.
took as inspiration to make an actual boundary-condition test in follow-up, thanks
opened followup at #30295 |
ACK 94ed4fb |
3f00aae package rbf: cpfp structure requires package > parent feerate (Greg Sanders) ad7f1f6 test package rbf boundary conditions more closely (Greg Sanders) ff4558d doc: reword package RBF documentation (Greg Sanders) de669a8 doc: replace mention of V3 with TRUC (Greg Sanders) Pull request description: Some suggested nits/changes from #28984 ACKs for top commit: glozow: ACK 3f00aae murchandamus: ACK 3f00aae Tree-SHA512: 79434cc8aba25a43e99793298cdc99cad807db2c3a2e780a31953f244b95eecd97b90559abd67fbf30996c00966675fa257253a7812ec4727420226162c629ae
Ported to the CMake-based build system in hebasto#264. |
Allows any 2 transaction package with no in-mempool ancestors to do package RBF when directly conflicting with other mempool clusters of size two or less.
Proposed validation steps:
Post-cluster mempool this will likely be expanded to general package rbf, but this is what we can safely support today.