Skip to content

Commit a99b76f

Browse files
committed
Require no cs_main lock for ProcessNewBlock/ActivateBestChain
This requires the removal of some very liberal (incorrect) cs_mains sprinkled in some tests. It adds some chainActive.Tip() races, but the tests are all single-threaded anyway.
1 parent a734896 commit a99b76f

File tree

4 files changed

+46
-33
lines changed

4 files changed

+46
-33
lines changed

src/test/miner_tests.cpp

Lines changed: 21 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -205,7 +205,6 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity)
205205
entry.nFee = 11;
206206
entry.nHeight = 11;
207207

208-
LOCK(cs_main);
209208
fCheckpointsEnabled = false;
210209

211210
// Simple block creation, nothing special yet:
@@ -218,27 +217,32 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity)
218217
for (unsigned int i = 0; i < sizeof(blockinfo)/sizeof(*blockinfo); ++i)
219218
{
220219
CBlock *pblock = &pblocktemplate->block; // pointer for convenience
221-
pblock->nVersion = 1;
222-
pblock->nTime = chainActive.Tip()->GetMedianTimePast()+1;
223-
CMutableTransaction txCoinbase(*pblock->vtx[0]);
224-
txCoinbase.nVersion = 1;
225-
txCoinbase.vin[0].scriptSig = CScript();
226-
txCoinbase.vin[0].scriptSig.push_back(blockinfo[i].extranonce);
227-
txCoinbase.vin[0].scriptSig.push_back(chainActive.Height());
228-
txCoinbase.vout.resize(1); // Ignore the (optional) segwit commitment added by CreateNewBlock (as the hardcoded nonces don't account for this)
229-
txCoinbase.vout[0].scriptPubKey = CScript();
230-
pblock->vtx[0] = MakeTransactionRef(std::move(txCoinbase));
231-
if (txFirst.size() == 0)
232-
baseheight = chainActive.Height();
233-
if (txFirst.size() < 4)
234-
txFirst.push_back(pblock->vtx[0]);
235-
pblock->hashMerkleRoot = BlockMerkleRoot(*pblock);
236-
pblock->nNonce = blockinfo[i].nonce;
220+
{
221+
LOCK(cs_main);
222+
pblock->nVersion = 1;
223+
pblock->nTime = chainActive.Tip()->GetMedianTimePast()+1;
224+
CMutableTransaction txCoinbase(*pblock->vtx[0]);
225+
txCoinbase.nVersion = 1;
226+
txCoinbase.vin[0].scriptSig = CScript();
227+
txCoinbase.vin[0].scriptSig.push_back(blockinfo[i].extranonce);
228+
txCoinbase.vin[0].scriptSig.push_back(chainActive.Height());
229+
txCoinbase.vout.resize(1); // Ignore the (optional) segwit commitment added by CreateNewBlock (as the hardcoded nonces don't account for this)
230+
txCoinbase.vout[0].scriptPubKey = CScript();
231+
pblock->vtx[0] = MakeTransactionRef(std::move(txCoinbase));
232+
if (txFirst.size() == 0)
233+
baseheight = chainActive.Height();
234+
if (txFirst.size() < 4)
235+
txFirst.push_back(pblock->vtx[0]);
236+
pblock->hashMerkleRoot = BlockMerkleRoot(*pblock);
237+
pblock->nNonce = blockinfo[i].nonce;
238+
}
237239
std::shared_ptr<const CBlock> shared_pblock = std::make_shared<const CBlock>(*pblock);
238240
BOOST_CHECK(ProcessNewBlock(chainparams, shared_pblock, true, nullptr));
239241
pblock->hashPrevBlock = pblock->GetHash();
240242
}
241243

244+
LOCK(cs_main);
245+
242246
// Just to make sure we can still make simple blocks
243247
BOOST_CHECK(pblocktemplate = AssemblerForTest(chainparams).CreateNewBlock(scriptPubKey));
244248

src/test/txvalidationcache_tests.cpp

Lines changed: 11 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,6 @@ BOOST_FIXTURE_TEST_CASE(tx_mempool_block_doublespend, TestChain100Setup)
6666

6767
// Test 1: block with both of those transactions should be rejected.
6868
block = CreateAndProcessBlock(spends, scriptPubKey);
69-
LOCK(cs_main);
7069
BOOST_CHECK(chainActive.Tip()->GetBlockHash() != block.GetHash());
7170

7271
// Test 2: ... and should be rejected if spend1 is in the memory pool
@@ -190,12 +189,12 @@ BOOST_FIXTURE_TEST_CASE(checkinputs_test, TestChain100Setup)
190189
spend_tx.vin[0].scriptSig << vchSig;
191190
}
192191

193-
LOCK(cs_main);
194-
195192
// Test that invalidity under a set of flags doesn't preclude validity
196193
// under other (eg consensus) flags.
197194
// spend_tx is invalid according to DERSIG
198195
{
196+
LOCK(cs_main);
197+
199198
CValidationState state;
200199
PrecomputedTransactionData ptd_spend_tx(spend_tx);
201200

@@ -213,15 +212,17 @@ BOOST_FIXTURE_TEST_CASE(checkinputs_test, TestChain100Setup)
213212
// test later that block validation works fine in the absence of cached
214213
// successes.
215214
ValidateCheckInputsForAllFlags(spend_tx, SCRIPT_VERIFY_DERSIG | SCRIPT_VERIFY_LOW_S | SCRIPT_VERIFY_STRICTENC, false);
215+
}
216216

217-
// And if we produce a block with this tx, it should be valid (DERSIG not
218-
// enabled yet), even though there's no cache entry.
219-
CBlock block;
217+
// And if we produce a block with this tx, it should be valid (DERSIG not
218+
// enabled yet), even though there's no cache entry.
219+
CBlock block;
220220

221-
block = CreateAndProcessBlock({spend_tx}, p2pk_scriptPubKey);
222-
BOOST_CHECK(chainActive.Tip()->GetBlockHash() == block.GetHash());
223-
BOOST_CHECK(pcoinsTip->GetBestBlock() == block.GetHash());
224-
}
221+
block = CreateAndProcessBlock({spend_tx}, p2pk_scriptPubKey);
222+
BOOST_CHECK(chainActive.Tip()->GetBlockHash() == block.GetHash());
223+
BOOST_CHECK(pcoinsTip->GetBestBlock() == block.GetHash());
224+
225+
LOCK(cs_main);
225226

226227
// Test P2SH: construct a transaction that is valid without P2SH, and
227228
// then test validity with P2SH.

src/validation.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2559,6 +2559,7 @@ bool CChainState::ActivateBestChain(CValidationState &state, const CChainParams&
25592559
// far from a guarantee. Things in the P2P/RPC will often end up calling
25602560
// us in the middle of ProcessNewBlock - do not assume pblock is set
25612561
// sanely for performance or correctness!
2562+
AssertLockNotHeld(cs_main);
25622563

25632564
CBlockIndex *pindexMostWork = nullptr;
25642565
CBlockIndex *pindexNewTip = nullptr;
@@ -3383,6 +3384,8 @@ bool CChainState::AcceptBlock(const std::shared_ptr<const CBlock>& pblock, CVali
33833384

33843385
bool ProcessNewBlock(const CChainParams& chainparams, const std::shared_ptr<const CBlock> pblock, bool fForceProcessing, bool *fNewBlock)
33853386
{
3387+
AssertLockNotHeld(cs_main);
3388+
33863389
{
33873390
CBlockIndex *pindex = nullptr;
33883391
if (fNewBlock) *fNewBlock = false;

src/wallet/test/wallet_tests.cpp

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -370,15 +370,15 @@ static void AddKey(CWallet& wallet, const CKey& key)
370370

371371
BOOST_FIXTURE_TEST_CASE(rescan, TestChain100Setup)
372372
{
373-
LOCK(cs_main);
374-
375373
// Cap last block file size, and mine new block in a new block file.
376374
CBlockIndex* const nullBlock = nullptr;
377375
CBlockIndex* oldTip = chainActive.Tip();
378376
GetBlockFileInfo(oldTip->GetBlockPos().nFile)->nSize = MAX_BLOCKFILE_SIZE;
379377
CreateAndProcessBlock({}, GetScriptForRawPubKey(coinbaseKey.GetPubKey()));
380378
CBlockIndex* newTip = chainActive.Tip();
381379

380+
LOCK(cs_main);
381+
382382
// Verify ScanForWalletTransactions picks up transactions in both the old
383383
// and new block files.
384384
{
@@ -447,8 +447,6 @@ BOOST_FIXTURE_TEST_CASE(rescan, TestChain100Setup)
447447
// than or equal to key birthday.
448448
BOOST_FIXTURE_TEST_CASE(importwallet_rescan, TestChain100Setup)
449449
{
450-
LOCK(cs_main);
451-
452450
// Create two blocks with same timestamp to verify that importwallet rescan
453451
// will pick up both blocks, not just the first.
454452
const int64_t BLOCK_TIME = chainActive.Tip()->GetBlockTimeMax() + 5;
@@ -462,6 +460,8 @@ BOOST_FIXTURE_TEST_CASE(importwallet_rescan, TestChain100Setup)
462460
SetMockTime(KEY_TIME);
463461
coinbaseTxns.emplace_back(*CreateAndProcessBlock({}, GetScriptForRawPubKey(coinbaseKey.GetPubKey())).vtx[0]);
464462

463+
LOCK(cs_main);
464+
465465
// Import key into wallet and call dumpwallet to create backup file.
466466
{
467467
CWallet wallet;
@@ -627,10 +627,15 @@ class ListCoinsTestingSetup : public TestChain100Setup
627627
BOOST_CHECK(wallet->CreateTransaction({recipient}, wtx, reservekey, fee, changePos, error, dummy));
628628
CValidationState state;
629629
BOOST_CHECK(wallet->CommitTransaction(wtx, reservekey, nullptr, state));
630+
CMutableTransaction blocktx;
631+
{
632+
LOCK(wallet->cs_wallet);
633+
blocktx = CMutableTransaction(*wallet->mapWallet.at(wtx.GetHash()).tx);
634+
}
635+
CreateAndProcessBlock({CMutableTransaction(blocktx)}, GetScriptForRawPubKey(coinbaseKey.GetPubKey()));
630636
LOCK(wallet->cs_wallet);
631637
auto it = wallet->mapWallet.find(wtx.GetHash());
632638
BOOST_CHECK(it != wallet->mapWallet.end());
633-
CreateAndProcessBlock({CMutableTransaction(*it->second.tx)}, GetScriptForRawPubKey(coinbaseKey.GetPubKey()));
634639
it->second.SetMerkleBranch(chainActive.Tip(), 1);
635640
return it->second;
636641
}
@@ -641,7 +646,6 @@ class ListCoinsTestingSetup : public TestChain100Setup
641646
BOOST_FIXTURE_TEST_CASE(ListCoins, ListCoinsTestingSetup)
642647
{
643648
std::string coinbaseAddress = coinbaseKey.GetPubKey().GetID().ToString();
644-
LOCK2(cs_main, wallet->cs_wallet);
645649

646650
// Confirm ListCoins initially returns 1 coin grouped under coinbaseKey
647651
// address.
@@ -669,6 +673,7 @@ BOOST_FIXTURE_TEST_CASE(ListCoins, ListCoinsTestingSetup)
669673
BOOST_CHECK_EQUAL(available.size(), 2);
670674
for (const auto& group : list) {
671675
for (const auto& coin : group.second) {
676+
LOCK(wallet->cs_wallet);
672677
wallet->LockCoin(COutPoint(coin.tx->GetHash(), coin.i));
673678
}
674679
}

0 commit comments

Comments
 (0)