Seems odd to have code in Bitcoin Core that is unused.
Moreover the function was broken (see #24145) and is brittle, as there is nothing that prevents similar bugs from re-appearing.
Fix both issues by replacing it with C++11 member initializers.
Seems odd to have code in Bitcoin Core that is unused.
Moreover the function was broken (see #24145) and is brittle, as there is nothing that prevents similar bugs from re-appearing.
Fix both issues by replacing it with C++11 member initializers.
mempool.clear()
in UnloadBlockIndex
has been added in commit 51598b26319bf1ee98b399dee8152b902c62891a to clear global state between unit tests. Now that there is no global mempool anymore, this it not needed anymore. Also, I couldn’t find it to be useful for anything else.
761@@ -761,7 +762,7 @@ BOOST_AUTO_TEST_CASE(MempoolAncestryTests)
762 tb = make_tx(/* output_values */ {5 * COIN, 3 * COIN}, /* inputs */ {ta});
763 tc = make_tx(/* output_values */ {2 * COIN}, /* inputs */ {tb}, /* input_indices */ {1});
764 td = make_tx(/* output_values */ {6 * COIN}, /* inputs */ {tb, tc}, /* input_indices */ {0, 0});
765- pool.clear();
766+ pool.clearTxs();
cs
released and the fresh cs
taken, so would be a bit more code
needs the old
cs
released
Why?
pool
is kept the same. Though, it is still a larger diff to instantiate a new mempool pool2
, lock it and replace pool
with pool2
. Happy to do whatever reviewers want, so let me know if I should keep this or change it.
I was just asking. It doesn’t need to be a big change, something like:
0{
1CTxMemPool pool;
2// ...
3}
4
5{
6CTxMemPool pool;
7// ...
8}
5+#ifndef BITCOIN_TEST_UTIL_TXMEMPOOL_H
6+#define BITCOIN_TEST_UTIL_TXMEMPOOL_H
7+
8+#include <txmempool.h>
9+
10+struct TxMemPoolClearable : public CTxMemPool {
TxMemPoolTesting
, as it seems more functions could be added to it.
E.g., a special version of GetTransactionAncestry()
that requires external CTxMemPool::cs
locking, see #19872 (review).
Wrt to preserving recursive locking of CTxMemPool::cs
mind considering the following patch:
0--- a/src/test/txvalidationcache_tests.cpp
1+++ b/src/test/txvalidationcache_tests.cpp
2@@ -73,7 +73,7 @@ BOOST_FIXTURE_TEST_CASE(tx_mempool_block_doublespend, TestChain100Setup)
3 LOCK(cs_main);
4 BOOST_CHECK(::ChainActive().Tip()->GetBlockHash() != block.GetHash());
5 }
6- tx_pool.clearTxs();
7+ WITH_LOCK(tx_pool.cs, tx_pool.clearTxs());
8
9 // Test 3: ... and should be rejected if spend2 is in the memory pool
10 BOOST_CHECK(ToMemPool(spends[1]));
11@@ -82,7 +82,7 @@ BOOST_FIXTURE_TEST_CASE(tx_mempool_block_doublespend, TestChain100Setup)
12 LOCK(cs_main);
13 BOOST_CHECK(::ChainActive().Tip()->GetBlockHash() != block.GetHash());
14 }
15- tx_pool.clearTxs();
16+ WITH_LOCK(tx_pool.cs, tx_pool.clearTxs());
17
18 // Final sanity test: first spend in tx_pool, second in block, that's OK:
19 std::vector<CMutableTransaction> oneSpend;
20diff --git a/src/test/util/txmempool.h b/src/test/util/txmempool.h
21index 7edc6d607..db52377b0 100644
22--- a/src/test/util/txmempool.h
23+++ b/src/test/util/txmempool.h
24@@ -9,9 +9,9 @@
25
26 struct TxMemPoolClearable : public CTxMemPool {
27 /** Clear added transactions */
28- void clearTxs()
29+ void clearTxs() EXCLUSIVE_LOCKS_REQUIRED(cs)
30 {
31- LOCK(cs);
32+ AssertLockHeld(cs);
33 mapTx.clear();
34 mapNextTx.clear();
35 totalTxSize = 0;
?
I’m not very familiar with these tests, so I may be completely off the mark here. However, it seems to me like the purpose of clearTxs
is to reset the mempool without re-instantiating it. I wonder if we shouldn’t consider just re-instantiating the mempool every time we want to clear it, as:
TxMemPoolClearable::clearTxs()
and CTxMemPool
in sync.The
mempool.clear()
inUnloadBlockIndex
has been added in commit 51598b2 to clear global state between unit tests. Now that there is no global mempool anymore, this it not needed anymore. Also, I couldn’t find it to be useful for anything else.
Does the call to UnloadBlockIndex
here: https://github.com/bitcoin/bitcoin/blob/a47e5964861dfb98d61719c9852e12fd6da84c31/src/init.cpp#L1562
Make any difference to the mempool
that we should keep in mind?
Is this refactor important to other work? Having the ability to clear the mempool seems useful to me; even though we’ve never exposed it, I could imagine some situations where invoking the clear() function somehow (say via rpc) might be useful.
Alternatively – and even more speculatively – in thinking about how we update the mempool after a reorg, I’ve wondered if there might be solutions where clearing the mempool and re-adding things back might be better in some scenarios.
I don’t think either of those is pressing though so if there’s some good reason to get rid of it to help with other work in progress, then that’s fine with me, we can always revisit the right design if the functionality I suggest might actually be useful. Just not sure if this might be wasted effort, if there’s no important reason or followup work motivating this change?
The following sections might be updated with supplementary metadata relevant to reviewers and maintainers.
See 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.
Reviewers, 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.
The clear
method as currently implemented doesn’t help with implementing a RPC that clears the mempool, because it also clears the fee estimates. If the method is kept, it should be renamed to ReInit
(or similar), because all it does is (re-)initialize the member variables of the mempool.
Though, according to our release notes, member variables should be initialized inline via C++11 initializers to avoid uninitialized values. (This is what is being done in this pull)
Also, I can not imagine a single use case where clearing the whole mempool over RPC is useful. At most sniping a single tx might be useful. Though even that has been rejected at least twice in the past. Please refer to #15873 and #16523.
If you’re a miner, I could imagine it is possible that clearing the mempool could be helpful in the event of a dos-attack where pathological transaction chains (for example) cause block template creation to be very slow. So a use case could be to empty it and use other rpcs to manually refill it.
That’s just an example, and I don’t know if it is likely we’d support that anytime soon, but I could imagine the use case.
(Your point about fee estimation is a reasonable one, but I believe there is work happening elsewhere to decouple that from the mempool? )
At any rate I don’t feel strongly about this, if removing this function is helpful for other work I am not opposed either.
clear()
, and tests assume that a call to clear()
gives a completely freshly initialized mempool, then the test setup is not testing what we want it to.
I wonder if we shouldn’t consider just re-instantiating the mempool every time we want to clear it, as:
@dongcarl This was also my idea in the discussion here, but there wasn’t really a decision: #19909 (review) @MarcoFalke did you consider this approach? On the face of it, it seems better to reinstantiate a mempool every time you want to clear it rather than having custom test code to reach into the object’s members.
76@@ -77,7 +77,9 @@ BOOST_FIXTURE_TEST_CASE(tx_mempool_block_doublespend, Dersig100Setup)
77 LOCK(cs_main);
78 BOOST_CHECK(m_node.chainman->ActiveChain().Tip()->GetBlockHash() != block.GetHash());
79 }
80- m_node.mempool->clear();
81+ BOOST_CHECK_EQUAL(m_node.mempool->size(), 1U);
82+ WITH_LOCK(m_node.mempool->cs, m_node.mempool->removeRecursive(CTransaction{spends[0]}, MemPoolRemovalReason::CONFLICT));
removeRecursive()
instead of the approach from #25073 / #19909 (comment) of instantiating a new mempool between test cases?
25073 is using a mempool local to the test only (and passing it to the miner). However, here the “global” mempool is used, which is also used by validation. So creating a new mempool would also require updating the pointer in validation.
I don’t think this is worth it, but I am happy to work on this, if reviewers want me to.