cluster mempool: Implement changeset interface for mempool#31122
Conversation
|
The following sections might be updated with supplementary metadata relevant to reviewers and maintainers. Code Coverage & BenchmarksFor details see: https://corecheck.dev/bitcoin/bitcoin/pulls/31122. 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. |
|
🚧 At least one of the CI tasks failed. HintsTry to run the tests locally, according to the documentation. However, a CI failure may still
Leave a comment here, if you need help tracking down a confusing failure. |
c04c3bd to
bb7b43b
Compare
bb7b43b to
aeefd31
Compare
ismaelsadeeq
left a comment
There was a problem hiding this comment.
Concept ACK
The changes are straightforward to understand, and the large diff is primarily due to changes in the error message and the removal of addUnchecked.
aeefd31 to
a4d0275
Compare
|
Thanks @glozow and @ismaelsadeeq for the review; I've incorporated some of the comments. If you have suggestions for how the logging can be improved in the package RBF case (and how the USDT tracing messages can be improved, similarly) please let me know your thoughts. Also, I wanted to flag that the locking is a bit of a mess in this branch. Initially, I tried to add lock annotations to the |
32ac5cd to
a981f07
Compare
|
🚧 At least one of the CI tasks failed. HintsTry to run the tests locally, according to the documentation. However, a CI failure may still
Leave a comment here, if you need help tracking down a confusing failure. |
instagibbs
left a comment
There was a problem hiding this comment.
first pass through, concept ACK
c85990d to
57a0356
Compare
|
Just rebased this on master -- @0xB10C thanks for the note on the tracepoint change. @instagibbs I think I could rewrite the @naumenkogs Thanks for looking at the validation change relating to consensus-invalid packages. Someone should probably test that logic by changing the policy checks to NOT be a strict superset of the consensus checks and verify that the logic I'm introducing here actually does what I think it does. I intend to do that myself but haven't gotten to it yet. EDIT: I hacked up the validation logic to trigger this currently unreachable block of code -- ie to make the |
instagibbs
left a comment
There was a problem hiding this comment.
ACK 5736d1d
Picks up TRACEPOINT and ephemeral dust stuff.
via git range-diff master 0ca1e05d8bcbc42892156c15f128a5f829e9e48e 5736d1ddacc4019101e7a5170dd25efbc63b622a
I had a little doubt that it will remove the transactions... Instead I was worried about evictions (i can't think of other side effects) of add/remove invalid stuff. Doesn't this allow to clear the victims mempool for free? |
Just to be clear, in case anyone has lost track: we're specifically talking about a codepath we believe is not possible to trigger, namely one where the In this event, I actually don't think the mempool could be directly drained, because we don't call If it were simple to just re-add the just-removed transactions, I'd try to include that here as well, but it would take some additional work to topologically sort the removed transactions so they can be re-added. Given that this logic is unreachable and already difficult-to-test as a result, I don't think it makes sense to add any significant complexity, at least for now -- this may be simpler to think about post-cluster-mempool. |
|
ACK 5736d1d My concern above was related to LimitMempoolSize(), but indeed it's easy to see it doesn't happen between the two For the RBF transactions i agree it's probably not worth complicating the code. |
glozow
left a comment
There was a problem hiding this comment.
Still working on review. I've skimmed through the commits and reviewed the end state of MemPoolAccept so far.
| // If not found, try to have the mempool calculate it, and cache | ||
| // for later. | ||
| LOCK(m_pool->cs); | ||
| auto ret{m_pool->CalculateMemPoolAncestors(*tx, limits)}; | ||
| if (ret) m_ancestors.try_emplace(tx, *ret); | ||
| return ret; |
There was a problem hiding this comment.
This is maybe a TxGraph question, but will we get to the point where CMPA and CheckPackageLimits can do the calculations using all staged changes? For example, if it looks like I would bust cluster limits using current mempool, but my parent's RBF is breaking up the cluster / removing things from it.
I'm wondering if we could easily align our multi-testmempoolaccept interface with the ProcessNewPackage interface to support package CPFP and RBF by pointing testmempoolaccept down the same codepath, with some if (test_accept) conditions to skip submission and retain changeset + coinsview state.
There was a problem hiding this comment.
TxGraph will be able reason about cluster count limits using arbitrary staged changes (so any combination of transaction deletions, transaction additions, and added dependencies).
These operations are always ordered as (1) tx additions (2) tx deletions (3) dep additions, even if they are invoked in a different order. So if you first add dependencies which - if applied - would violate the limit, and then delete some transactions in the cluster such that the result breaks up again and stays below the limit, that is fine.
There was a problem hiding this comment.
I also have a goal of eliminating the need to invoke CMPA on a changeset anyway. In #28676, I believe the only place that CMPA is used in a changeset is for determining whether an RBF might be replacing something it depends on. I think it should be straightforward to have the changeset logic directly test for that condition and return failure if a dependency is being added to something that is slated for removal, which would then allow us to remove the method altogether.
glozow
left a comment
There was a problem hiding this comment.
ACK 5736d1d
I really like how ChangeSet codifies the concept of an atomic changeset of additions and removals, and how CalculateChunksForRBF and ImprovesFeerateDiagram operate on changesets. It's like the mempool interface is moving towards it being more responsible for itself.
| } | ||
|
|
||
| size_t GetTxCount() const { return m_entry_vec.size(); } | ||
| const CTransaction& GetAddedTxn(size_t index) const { return m_entry_vec.at(index)->GetTx(); } |
There was a problem hiding this comment.
nitty, but I wondered why not CTransactionRef here?
| const CTransaction& GetAddedTxn(size_t index) const { return m_entry_vec.at(index)->GetTx(); } | |
| CTransactionRef GetAddedTxn(size_t index) const { return m_entry_vec.at(index)->GetSharedTx(); } |
| // to track size/count of descendant transactions. First version of | ||
| // addNewTransaction can be used to have it call CalculateMemPoolAncestors(), and | ||
| // then invoke the second version. |
There was a problem hiding this comment.
I misunderstood this comment initially, thinking it meant that you would call both addNewTransactions, but it actually means that one is a wrapper for the other, with a prepended CMPA. Callers should use one or the other.
|
|
||
| void CTxMemPool::TrimToSize(size_t sizelimit, std::vector<COutPoint>* pvNoSpendsRemaining) { | ||
| AssertLockHeld(cs); | ||
| Assume(!m_have_changeset); |
| const auto tx2_size = entry2->GetTxSize(); | ||
|
|
||
| // conflicting transactions | ||
| const auto tx1_conflict = make_tx(/*inputs=*/ {m_coinbase_txns[0], m_coinbase_txns[2]}, /*output_values=*/ {10 * COIN}); |
part of cluster mempool: #30289
It became clear while working on cluster mempool that it would be helpful for transaction validation if we could consider a full set of proposed changes to the mempool -- consisting of a set of transactions to add, and a set of transactions (ie conflicts) to simultaneously remove -- and perform calculations on what the mempool would look like if the proposed changes were to be applied. Two specific examples of where we'd like to do this:
In preparation for cluster mempool, I have pulled this reworking of the mempool interface out of #28676 so it can be reviewed on its own. I have not re-implemented ancestor/descendant limits to be run through the changeset, since with cluster mempool those limits will be going away, so this seems like wasted effort. However, I have rebased #28676 on top of this branch so reviewers can see what the new mempool interface could look like in the cluster mempool setting.
There are some minor behavior changes here, which I believe are inconsequential:
ConsensusScriptChecks()are run. In theory,ConsensusScriptChecks()should always pass if thePolicyScriptChecks()have passed and it's just a belt-and-suspenders for us, but if somehow they were to diverge then there could be some small behavior change from adding transactions and then removing them, versus never adding them at all.CheckConflictTopology()has slightly changed due to no longer distinguishing between direct conflicts and indirect conflicts. I believe this should be entirely inconsequential because there shouldn't be a logical difference between those two ideas from the perspective of this function, but I did have to update some error strings in some tests.TXPACKAGEScategory has been updated as well to include the package hash, so that it's possible to see which specific set of transactions are being referenced by that package hash.