Skip to content

Commit fb97aab

Browse files
committed
Give mapBlockIndex its own lock.
Declare mapBlockIndex to be protected by cs_mapblockindex. Move a lot of generic lookups to LookupBlockIndex, while other more complex uses (e.g. atomic lookup+insert) are left alone. Make sure the lock is taken everywhere necessary (places found with clang thread-safety warnings) and only as tightly as possible to avoid potential lock cycles (detectable by tsan). Many uses of cs_main are replaced by cs_mapblockindex if they were only protecting mapBlockIndex, or removed (LookupBlockIndex taking the lock itself), or moved to after LookupBlockIndex calls.
1 parent 6e8a420 commit fb97aab

20 files changed

+318
-319
lines changed

src/index/base.cpp

+1-5
Original file line numberDiff line numberDiff line change
@@ -194,11 +194,7 @@ void BaseIndex::ChainStateFlushed(const CBlockLocator& locator)
194194
}
195195

196196
const uint256& locator_tip_hash = locator.vHave.front();
197-
const CBlockIndex* locator_tip_index;
198-
{
199-
LOCK(cs_main);
200-
locator_tip_index = LookupBlockIndex(locator_tip_hash);
201-
}
197+
const CBlockIndex* locator_tip_index = LookupBlockIndex(locator_tip_hash);
202198

203199
if (!locator_tip_index) {
204200
FatalError("%s: First block (hash=%s) in locator was not found",

src/init.cpp

+9-8
Original file line numberDiff line numberDiff line change
@@ -1602,10 +1602,13 @@ bool AppInitMain()
16021602
break;
16031603
}
16041604

1605-
// If the loaded chain has a wrong genesis, bail out immediately
1606-
// (we're likely using a testnet datadir, or the other way around).
1607-
if (!mapBlockIndex.empty() && !LookupBlockIndex(chainparams.GetConsensus().hashGenesisBlock)) {
1608-
return InitError(_("Incorrect or no genesis block found. Wrong datadir for network?"));
1605+
{
1606+
LOCK(cs_mapblockindex);
1607+
// If the loaded chain has a wrong genesis, bail out immediately
1608+
// (we're likely using a testnet datadir, or the other way around).
1609+
if (!mapBlockIndex.empty() && !LookupBlockIndex(chainparams.GetConsensus().hashGenesisBlock)) {
1610+
return InitError(_("Incorrect or no genesis block found. Wrong datadir for network?"));
1611+
}
16091612
}
16101613

16111614
// Check for changed -prune state. What we are concerned about is a user who has pruned blocks
@@ -1835,14 +1838,12 @@ bool AppInitMain()
18351838

18361839
// ********************************************************* Step 12: start node
18371840

1838-
int chain_active_height;
1839-
18401841
//// debug print
18411842
{
1842-
LOCK(cs_main);
1843+
LOCK(cs_mapblockindex);
18431844
LogPrintf("mapBlockIndex.size() = %u\n", mapBlockIndex.size());
1844-
chain_active_height = chainActive.Height();
18451845
}
1846+
int chain_active_height = chainActive.Height();
18461847
LogPrintf("nBestHeight = %d\n", chain_active_height);
18471848

18481849
if (gArgs.GetBoolArg("-listenonion", DEFAULT_LISTEN_ONION))

src/interfaces/wallet.cpp

+2-4
Original file line numberDiff line numberDiff line change
@@ -237,8 +237,7 @@ WalletTxStatus MakeWalletTxStatus(const CWalletTx& wtx)
237237
{
238238
LOCK(cs_main);
239239
WalletTxStatus result;
240-
auto mi = ::mapBlockIndex.find(wtx.hashBlock);
241-
CBlockIndex* block = mi != ::mapBlockIndex.end() ? mi->second : nullptr;
240+
CBlockIndex* block = LookupBlockIndex(wtx.hashBlock);
242241
result.block_height = (block ? block->nHeight : std::numeric_limits<int>::max());
243242
result.blocks_to_maturity = wtx.GetBlocksToMaturity();
244243
result.depth_in_main_chain = wtx.GetDepthInMainChain();
@@ -256,9 +255,8 @@ WalletTxStatus MakeWalletTxStatus(const CWalletTx& wtx)
256255
WalletTxStatus MakeWalletTxStatus(AnonWallet* pAnonWallet, const uint256 &hash, const CTransactionRecord &rtx)
257256
{
258257
WalletTxStatus result;
259-
auto mi = ::mapBlockIndex.find(rtx.blockHash);
260258
261-
CBlockIndex* block = mi != ::mapBlockIndex.end() ? mi->second : nullptr;
259+
CBlockIndex* block = LookupBlockIndex(rtx.blockHash);
262260
result.block_height = (block ? block->nHeight : std::numeric_limits<int>::max()),
263261
264262
result.blocks_to_maturity = 0;

src/miner.cpp

+6-6
Original file line numberDiff line numberDiff line change
@@ -168,13 +168,13 @@ std::unique_ptr<CBlockTemplate> BlockAssembler::CreateNewBlock(const CScript& sc
168168

169169
CMutableTransaction txCoinStake;
170170
CBlockIndex* pindexPrev;
171+
//Do not pass in the chain tip, because it can change. Instead pass the blockindex directly from mapblockindex, which is const.
172+
auto pindexTip = chainActive.Tip();
173+
if (!pindexTip)
174+
return nullptr;
175+
auto hashBest = pindexTip->GetBlockHash();
171176
{
172-
LOCK(cs_main);
173-
//Do not pass in the chain tip, because it can change. Instead pass the blockindex directly from mapblockindex, which is const.
174-
auto pindexTip = chainActive.Tip();
175-
if (!pindexTip)
176-
return nullptr;
177-
auto hashBest = pindexTip->GetBlockHash();
177+
LOCK(cs_mapblockindex);
178178
pindexPrev = mapBlockIndex.at(hashBest);
179179
}
180180
if (fProofOfStake && pindexPrev->nHeight + 1 >= Params().HeightPoSStart()) {

src/net_processing.cpp

+22-23
Original file line numberDiff line numberDiff line change
@@ -1156,30 +1156,29 @@ void static ProcessGetBlockData(CNode* pfrom, const CChainParams& chainparams, c
11561156
}
11571157

11581158
bool need_activate_chain = false;
1159-
{
1160-
LOCK(cs_main);
1161-
const CBlockIndex* pindex = LookupBlockIndex(inv.hash);
1162-
if (pindex) {
1163-
if (pindex->nChainTx && !pindex->IsValid(BLOCK_VALID_SCRIPTS) &&
1164-
pindex->IsValid(BLOCK_VALID_TREE)) {
1165-
// If we have the block and all of its parents, but have not yet validated it,
1166-
// we might be in the middle of connecting it (ie in the unlock of cs_main
1167-
// before ActivateBestChain but after AcceptBlock).
1168-
// In this case, we need to run ActivateBestChain prior to checking the relay
1169-
// conditions below.
1170-
need_activate_chain = true;
1171-
}
1159+
1160+
const CBlockIndex* pindex = LookupBlockIndex(inv.hash);
1161+
if (pindex) {
1162+
if (pindex->nChainTx && !pindex->IsValid(BLOCK_VALID_SCRIPTS) &&
1163+
pindex->IsValid(BLOCK_VALID_TREE)) {
1164+
// If we have the block and all of its parents, but have not yet validated it,
1165+
// we might be in the middle of connecting it
1166+
// (ie before ActivateBestChain but after AcceptBlock).
1167+
// In this case, we need to run ActivateBestChain prior to checking the relay
1168+
// conditions below.
1169+
need_activate_chain = true;
11721170
}
1173-
} // release cs_main before calling ActivateBestChain
1171+
}
11741172
if (need_activate_chain) {
11751173
CValidationState state;
11761174
if (!ActivateBestChain(state, Params(), a_recent_block)) {
11771175
LogPrint(BCLog::NET, "failed to activate chain (%s)\n", FormatStateMessage(state));
11781176
}
11791177
}
11801178

1179+
pindex = LookupBlockIndex(inv.hash);
1180+
11811181
LOCK(cs_main);
1182-
const CBlockIndex* pindex = LookupBlockIndex(inv.hash);
11831182
if (pindex) {
11841183
send = BlockRequestAllowed(pindex, consensusParams);
11851184
if (!send) {
@@ -1577,7 +1576,10 @@ void ProcessStaging()
15771576
continue;
15781577
}
15791578

1580-
fProcessNext = mapBlockIndex.at(pblockStaged->hashPrevBlock)->nChainTx > 0;
1579+
{
1580+
LOCK(cs_mapblockindex);
1581+
fProcessNext = mapBlockIndex.at(pblockStaged->hashPrevBlock)->nChainTx > 0;
1582+
}
15811583

15821584
if (!fProcessNext) {
15831585
MilliSleep(100);
@@ -2447,14 +2449,14 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr
24472449
return true;
24482450
}
24492451

2450-
LOCK(cs_main);
2451-
24522452
const CBlockIndex* pindex = LookupBlockIndex(req.blockhash);
24532453
if (!pindex || !(pindex->nStatus & BLOCK_HAVE_DATA)) {
24542454
LogPrint(BCLog::NET, "Peer %d sent us a getblocktxn for a block we don't have\n", pfrom->GetId());
24552455
return true;
24562456
}
24572457

2458+
LOCK(cs_main);
2459+
24582460
if (pindex->nHeight < chainActive.Height() - MAX_BLOCKTXN_DEPTH) {
24592461
// If an older block is requested (should never happen in practice,
24602462
// but can happen in tests) send a block response instead of a
@@ -2776,10 +2778,8 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr
27762778

27772779
bool received_new_header = false;
27782780

2779-
{
2780-
LOCK(cs_main);
2781-
27822781
if (!LookupBlockIndex(cmpctblock.header.hashPrevBlock)) {
2782+
LOCK(cs_main);
27832783
// Doesn't connect (or is genesis), instead of DoSing in AcceptBlockHeader, request deeper headers
27842784
if (!IsInitialBlockDownload())
27852785
connman->PushMessage(pfrom, msgMaker.Make(NetMsgType::GETHEADERS, chainActive.GetLocator(pindexBestHeader), uint256()));
@@ -2789,7 +2789,6 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr
27892789
if (!LookupBlockIndex(cmpctblock.header.GetHash())) {
27902790
received_new_header = true;
27912791
}
2792-
}
27932792

27942793
const CBlockIndex *pindex = nullptr;
27952794
CValidationState state;
@@ -3105,7 +3104,7 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr
31053104
int nHeightNext = 0;
31063105
const uint256 hash(pblock->GetHash());
31073106
{
3108-
LOCK(cs_main);
3107+
LOCK2(cs_main, cs_mapblockindex);
31093108
// Also always process if we requested the block explicitly, as we may
31103109
// need it even though it is not a candidate for a new best tip.
31113110
forceProcessing |= MarkBlockAsReceived(hash);

src/qt/coincontroldialog.cpp

+15-14
Original file line numberDiff line numberDiff line change
@@ -565,14 +565,15 @@ void CoinControlDialog::updateLabels(WalletModel *model, QDialog* dialog)
565565
uint256 hashBlock;
566566
if (!GetTransaction(txid, txRef, Params().GetConsensus(), hashBlock, true))
567567
continue;
568-
auto it = mapBlockIndex.find(hashBlock);
569-
if (it == mapBlockIndex.end())
568+
569+
CBlockIndex* block = LookupBlockHash(hashBlock);
570+
if (block == nullptr)
570571
continue;
571572

572-
if (!chainActive.Contains(it->second))
573+
if (!chainActive.Contains(block))
573574
continue;
574575

575-
nDepth = chainActive.Height() - it->second->nHeight + 1;
576+
nDepth = chainActive.Height() - block->nHeight + 1;
576577
}
577578

578579
if (nDepth < 1)
@@ -888,15 +889,15 @@ void CoinControlDialog::updateView(int nCoinType)
888889
if (!GetTransaction(txid, txRef, Params().GetConsensus(), hashBlock, true))
889890
continue;
890891

891-
auto it = mapBlockIndex.find(hashBlock);
892-
if (it == mapBlockIndex.end())
892+
CBlockIndex* block = LookupBlockHash(hashBlock);
893+
if (block == nullptr)
893894
continue;
894895

895-
if (!chainActive.Contains(it->second))
896+
if (!chainActive.Contains(block))
896897
continue;
897898

898-
nDepth = chainActive.Height() - it->second->nHeight + 1;
899-
nTimeTx = it->second->GetBlockTime();
899+
nDepth = chainActive.Height() - block->nHeight + 1;
900+
nTimeTx = block->GetBlockTime();
900901
}
901902

902903
for (unsigned int i = 0; i < txRecord.vout.size(); i++) {
@@ -1062,15 +1063,15 @@ void CoinControlDialog::updateView(int nCoinType)
10621063
if (!GetTransaction(mint.txid, txRef, Params().GetConsensus(), hashBlock, true))
10631064
continue;
10641065

1065-
auto it = mapBlockIndex.find(hashBlock);
1066-
if (it == mapBlockIndex.end())
1066+
CBlockIndex* block = LookupBlockHash(hashBlock);
1067+
if (block == nullptr)
10671068
continue;
10681069

1069-
if (!chainActive.Contains(it->second))
1070+
if (!chainActive.Contains(block))
10701071
continue;
10711072

1072-
nDepth = chainActive.Height() - it->second->nHeight + 1;
1073-
nTimeTx = it->second->GetBlockTime();
1073+
nDepth = chainActive.Height() - block->nHeight + 1;
1074+
nTimeTx = block->GetBlockTime();
10741075
}
10751076

10761077
// increase the count for each denom we see

src/rest.cpp

+17-24
Original file line numberDiff line numberDiff line change
@@ -147,16 +147,14 @@ static bool rest_headers(HTTPRequest* req,
147147
const CBlockIndex* tip = nullptr;
148148
std::vector<const CBlockIndex *> headers;
149149
headers.reserve(count);
150-
{
151-
LOCK(cs_main);
152-
tip = chainActive.Tip();
153-
const CBlockIndex* pindex = LookupBlockIndex(hash);
154-
while (pindex != nullptr && chainActive.Contains(pindex)) {
155-
headers.push_back(pindex);
156-
if (headers.size() == (unsigned long)count)
157-
break;
158-
pindex = chainActive.Next(pindex);
159-
}
150+
151+
tip = chainActive.Tip();
152+
const CBlockIndex* pindex = LookupBlockIndex(hash);
153+
while (pindex != nullptr && chainActive.Contains(pindex)) {
154+
headers.push_back(pindex);
155+
if (headers.size() == (unsigned long)count)
156+
break;
157+
pindex = chainActive.Next(pindex);
160158
}
161159

162160
CDataStream ssHeader(SER_NETWORK, PROTOCOL_VERSION);
@@ -210,22 +208,17 @@ static bool rest_block(HTTPRequest* req,
210208
return RESTERR(req, HTTP_BAD_REQUEST, "Invalid hash: " + hashStr);
211209

212210
CBlock block;
213-
CBlockIndex* pblockindex = nullptr;
214-
CBlockIndex* tip = nullptr;
215-
{
216-
LOCK(cs_main);
217-
tip = chainActive.Tip();
218-
pblockindex = LookupBlockIndex(hash);
219-
if (!pblockindex) {
220-
return RESTERR(req, HTTP_NOT_FOUND, hashStr + " not found");
221-
}
211+
CBlockIndex* tip = chainActive.Tip();
212+
CBlockIndex* pblockindex = LookupBlockIndex(hash);
213+
if (!pblockindex) {
214+
return RESTERR(req, HTTP_NOT_FOUND, hashStr + " not found");
215+
}
222216

223-
if (IsBlockPruned(pblockindex))
224-
return RESTERR(req, HTTP_NOT_FOUND, hashStr + " not available (pruned data)");
217+
if (IsBlockPruned(pblockindex))
218+
return RESTERR(req, HTTP_NOT_FOUND, hashStr + " not available (pruned data)");
225219

226-
if (!ReadBlockFromDisk(block, pblockindex, Params().GetConsensus()))
227-
return RESTERR(req, HTTP_NOT_FOUND, hashStr + " not found");
228-
}
220+
if (!ReadBlockFromDisk(block, pblockindex, Params().GetConsensus()))
221+
return RESTERR(req, HTTP_NOT_FOUND, hashStr + " not found");
229222

230223
CDataStream ssBlock(SER_NETWORK, PROTOCOL_VERSION | RPCSerializationFlags());
231224
ssBlock << block;

0 commit comments

Comments
 (0)