Skip to content

Commit

Permalink
Merge bitcoin#13786: refactor: Avoid locking tx pool cs thrice
Browse files Browse the repository at this point in the history
fa5ed4f refactor: Avoid locking tx pool cs thrice (MarcoFalke)

Pull request description:

  `addUnchecked` is (outside the tests) only called by ATMP, which already takes the tx pool read lock. So locking it twice more in both `addUnchecked` methods seems redundant.

  Similarly `CalculateMemPoolAncestors` is (beside once in the wallet) only called in contexts, where the tx pool lock is already taken. So remove the lock there as well.

Tree-SHA512: fcf603b570da0fc529fe6db8add218663eae52845510732bee0d4611263d2429d3d3c9c8ae68493d67287d13504500ed51905ccbe711eb15a0af3b019edad543
  • Loading branch information
MarcoFalke authored and PastaPastaPasta committed Feb 4, 2021
1 parent cc9c470 commit 4a7387f
Show file tree
Hide file tree
Showing 8 changed files with 18 additions and 15 deletions.
3 changes: 2 additions & 1 deletion src/bench/mempool_eviction.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
#include <list>
#include <vector>

static void AddTx(const CTransaction& tx, const CAmount& nFee, CTxMemPool& pool)
static void AddTx(const CTransaction& tx, const CAmount& nFee, CTxMemPool& pool) EXCLUSIVE_LOCKS_REQUIRED(pool.cs)
{
int64_t nTime = 0;
unsigned int nHeight = 1;
Expand Down Expand Up @@ -97,6 +97,7 @@ static void MempoolEviction(benchmark::State& state)
tx7.vout[1].nValue = 10 * COIN;

CTxMemPool pool;
LOCK(pool.cs);

while (state.KeepRunning()) {
AddTx(tx1, 10000LL, pool);
Expand Down
6 changes: 3 additions & 3 deletions src/test/blockencodings_tests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -62,8 +62,8 @@ BOOST_AUTO_TEST_CASE(SimpleRoundTripTest)
TestMemPoolEntryHelper entry;
CBlock block(BuildBlockTestCase());

pool.addUnchecked(block.vtx[2]->GetHash(), entry.FromTx(*block.vtx[2]));
LOCK(pool.cs);
pool.addUnchecked(block.vtx[2]->GetHash(), entry.FromTx(*block.vtx[2]));
BOOST_CHECK_EQUAL(pool.mapTx.find(block.vtx[2]->GetHash())->GetSharedTx().use_count(), SHARED_TX_OFFSET + 0);

// Do a simple ShortTxIDs RT
Expand Down Expand Up @@ -162,8 +162,8 @@ BOOST_AUTO_TEST_CASE(NonCoinbasePreforwardRTTest)
TestMemPoolEntryHelper entry;
CBlock block(BuildBlockTestCase());

pool.addUnchecked(block.vtx[2]->GetHash(), entry.FromTx(*block.vtx[2]));
LOCK(pool.cs);
pool.addUnchecked(block.vtx[2]->GetHash(), entry.FromTx(*block.vtx[2]));
BOOST_CHECK_EQUAL(pool.mapTx.find(block.vtx[2]->GetHash())->GetSharedTx().use_count(), SHARED_TX_OFFSET + 0);

uint256 txhash;
Expand Down Expand Up @@ -229,8 +229,8 @@ BOOST_AUTO_TEST_CASE(SufficientPreforwardRTTest)
TestMemPoolEntryHelper entry;
CBlock block(BuildBlockTestCase());

pool.addUnchecked(block.vtx[1]->GetHash(), entry.FromTx(*block.vtx[1]));
LOCK(pool.cs);
pool.addUnchecked(block.vtx[1]->GetHash(), entry.FromTx(*block.vtx[1]));
BOOST_CHECK_EQUAL(pool.mapTx.find(block.vtx[1]->GetHash())->GetSharedTx().use_count(), SHARED_TX_OFFSET + 0);

uint256 txhash;
Expand Down
7 changes: 5 additions & 2 deletions src/test/mempool_tests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ BOOST_AUTO_TEST_CASE(MempoolRemoveTest)


CTxMemPool testPool;
LOCK(testPool.cs);

// Nothing in pool, remove should do nothing:
unsigned int poolSize = testPool.size();
Expand Down Expand Up @@ -118,6 +119,7 @@ void CheckSort(CTxMemPool &pool, std::vector<std::string> &sortedOrder) EXCLUSIV
BOOST_AUTO_TEST_CASE(MempoolIndexingTest)
{
CTxMemPool pool;
LOCK(pool.cs);
TestMemPoolEntryHelper entry;

/* 3rd highest fee */
Expand Down Expand Up @@ -164,7 +166,6 @@ BOOST_AUTO_TEST_CASE(MempoolIndexingTest)
sortedOrder[2] = tx1.GetHash().ToString(); // 10000
sortedOrder[3] = tx4.GetHash().ToString(); // 15000
sortedOrder[4] = tx2.GetHash().ToString(); // 20000
LOCK(pool.cs);
CheckSort<descendant_score>(pool, sortedOrder);

/* low fee but with high fee child */
Expand Down Expand Up @@ -291,6 +292,7 @@ BOOST_AUTO_TEST_CASE(MempoolIndexingTest)
BOOST_AUTO_TEST_CASE(MempoolAncestorIndexingTest)
{
CTxMemPool pool;
LOCK(pool.cs);
TestMemPoolEntryHelper entry;

/* 3rd highest fee */
Expand Down Expand Up @@ -346,7 +348,6 @@ BOOST_AUTO_TEST_CASE(MempoolAncestorIndexingTest)
}
sortedOrder[4] = tx3.GetHash().ToString(); // 0

LOCK(pool.cs);
CheckSort<ancestor_score>(pool, sortedOrder);

/* low fee parent with high fee child */
Expand Down Expand Up @@ -420,6 +421,7 @@ BOOST_AUTO_TEST_CASE(MempoolAncestorIndexingTest)
BOOST_AUTO_TEST_CASE(MempoolSizeLimitTest)
{
CTxMemPool pool;
LOCK(pool.cs);
TestMemPoolEntryHelper entry;

CMutableTransaction tx1 = CMutableTransaction();
Expand Down Expand Up @@ -595,6 +597,7 @@ BOOST_AUTO_TEST_CASE(MempoolAncestryTests)
size_t ancestors, descendants;

CTxMemPool pool;
LOCK(pool.cs);
TestMemPoolEntryHelper entry;

/* Base transaction */
Expand Down
3 changes: 2 additions & 1 deletion src/test/miner_tests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@ bool TestSequenceLocks(const CTransaction &tx, int flags)
// Test suite for ancestor feerate transaction selection.
// Implemented as an additional function, rather than a separate test case,
// to allow reusing the blockchain created in CreateNewBlock_validity.
void TestPackageSelection(const CChainParams& chainparams, CScript scriptPubKey, std::vector<CTransactionRef>& txFirst)
void TestPackageSelection(const CChainParams& chainparams, const CScript& scriptPubKey, const std::vector<CTransactionRef>& txFirst) EXCLUSIVE_LOCKS_REQUIRED(::mempool.cs)
{
// Disable free transactions, otherwise TX selection is non-deterministic
gArgs.SoftSetArg("-blockprioritysize", "0");
Expand Down Expand Up @@ -271,6 +271,7 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity)

{
LOCK(cs_main);
LOCK(::mempool.cs);

// Just to make sure we can still make simple blocks
BOOST_CHECK(pblocktemplate = AssemblerForTest(chainparams).CreateNewBlock(scriptPubKey));
Expand Down
1 change: 1 addition & 0 deletions src/test/policyestimator_tests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ BOOST_AUTO_TEST_CASE(BlockPolicyEstimates)
{
CBlockPolicyEstimator feeEst;
CTxMemPool mpool(&feeEst);
LOCK(mpool.cs);
TestMemPoolEntryHelper entry;
CAmount basefee(2000);
CAmount deltaFee(100);
Expand Down
4 changes: 0 additions & 4 deletions src/txmempool.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -152,8 +152,6 @@ void CTxMemPool::UpdateTransactionsFromBlock(const std::vector<uint256> &vHashes

bool CTxMemPool::CalculateMemPoolAncestors(const CTxMemPoolEntry &entry, setEntries &setAncestors, uint64_t limitAncestorCount, uint64_t limitAncestorSize, uint64_t limitDescendantCount, uint64_t limitDescendantSize, std::string &errString, bool fSearchForParents /* = true */) const
{
LOCK(cs);

setEntries parentHashes;
const CTransaction &tx = entry.GetTx();

Expand Down Expand Up @@ -364,7 +362,6 @@ bool CTxMemPool::addUnchecked(const uint256& hash, const CTxMemPoolEntry &entry,
// Add to memory pool without checking anything.
// Used by AcceptToMemoryPool(), which DOES do
// all the appropriate checks.
LOCK(cs);
indexed_transaction_set::iterator newit = mapTx.insert(entry).first;
mapLinks.insert(make_pair(newit, TxLinks()));

Expand Down Expand Up @@ -1421,7 +1418,6 @@ int CTxMemPool::Expire(int64_t time) {

bool CTxMemPool::addUnchecked(const uint256&hash, const CTxMemPoolEntry &entry, bool validFeeEstimate)
{
LOCK(cs);
setEntries setAncestors;
uint64_t nNoLimit = std::numeric_limits<uint64_t>::max();
std::string dummy;
Expand Down
6 changes: 3 additions & 3 deletions src/txmempool.h
Original file line number Diff line number Diff line change
Expand Up @@ -563,8 +563,8 @@ class CTxMemPool
// Note that addUnchecked is ONLY called from ATMP outside of tests
// and any other callers may break wallet's in-mempool tracking (due to
// lack of CValidationInterface::TransactionAddedToMempool callbacks).
bool addUnchecked(const uint256& hash, const CTxMemPoolEntry &entry, bool validFeeEstimate = true);
bool addUnchecked(const uint256& hash, const CTxMemPoolEntry &entry, setEntries &setAncestors, bool validFeeEstimate = true);
bool addUnchecked(const uint256& hash, const CTxMemPoolEntry& entry, bool validFeeEstimate = true) EXCLUSIVE_LOCKS_REQUIRED(cs);
bool addUnchecked(const uint256& hash, const CTxMemPoolEntry& entry, setEntries& setAncestors, bool validFeeEstimate = true) EXCLUSIVE_LOCKS_REQUIRED(cs);

void addAddressIndex(const CTxMemPoolEntry &entry, const CCoinsViewCache &view);
bool getAddressIndex(std::vector<std::pair<uint160, int> > &addresses,
Expand Down Expand Up @@ -635,7 +635,7 @@ class CTxMemPool
* fSearchForParents = whether to search a tx's vin for in-mempool parents, or
* look up parents from mapLinks. Must be true for entries not in the mempool
*/
bool CalculateMemPoolAncestors(const CTxMemPoolEntry &entry, setEntries &setAncestors, uint64_t limitAncestorCount, uint64_t limitAncestorSize, uint64_t limitDescendantCount, uint64_t limitDescendantSize, std::string &errString, bool fSearchForParents = true) const;
bool CalculateMemPoolAncestors(const CTxMemPoolEntry& entry, setEntries& setAncestors, uint64_t limitAncestorCount, uint64_t limitAncestorSize, uint64_t limitDescendantCount, uint64_t limitDescendantSize, std::string& errString, bool fSearchForParents = true) const EXCLUSIVE_LOCKS_REQUIRED(cs);

/** Populate setDescendants with all in-mempool descendants of hash.
* Assumes that setDescendants includes all in-mempool descendants of anything
Expand Down
3 changes: 2 additions & 1 deletion src/wallet/wallet.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3997,7 +3997,8 @@ bool CWallet::CreateTransaction(const std::vector<CRecipient>& vecSend, CTransac
size_t nLimitDescendants = gArgs.GetArg("-limitdescendantcount", DEFAULT_DESCENDANT_LIMIT);
size_t nLimitDescendantSize = gArgs.GetArg("-limitdescendantsize", DEFAULT_DESCENDANT_SIZE_LIMIT)*1000;
std::string errString;
if (!mempool.CalculateMemPoolAncestors(entry, setAncestors, nLimitAncestors, nLimitAncestorSize, nLimitDescendants, nLimitDescendantSize, errString)) {
LOCK(::mempool.cs);
if (!::mempool.CalculateMemPoolAncestors(entry, setAncestors, nLimitAncestors, nLimitAncestorSize, nLimitDescendants, nLimitDescendantSize, errString)) {
strFailReason = _("Transaction has too long of a mempool chain");
return false;
}
Expand Down

0 comments on commit 4a7387f

Please sign in to comment.