mapBlockIndex
lookups with the new LookupBlockIndex()
. In some cases it avoids a second lookup.
mapBlockIndex
lookups with the new LookupBlockIndex()
. In some cases it avoids a second lookup.
210@@ -212,10 +211,11 @@ static bool rest_block(HTTPRequest* req,
211 CBlockIndex* pblockindex = NULL;
212 {
213 LOCK(cs_main);
214- if (mapBlockIndex.count(hash) == 0)
215+ pblockindex = LookupBlockIndex(hash);
216+ if (pblockindex) {
668@@ -669,10 +669,10 @@ UniValue getblockheader(const JSONRPCRequest& request)
669 if (!request.params[1].isNull())
670 fVerbose = request.params[1].get_bool();
671
672- if (mapBlockIndex.count(hash) == 0)
673+ CBlockIndex* pblockindex = LookupBlockIndex(hash);
674+ if (pblockindex == nullptr) {
815@@ -817,7 +816,9 @@ static bool GetUTXOStats(CCoinsView *view, CCoinsStats &stats)
816 stats.hashBlock = pcursor->GetBestBlock();
817 {
818 LOCK(cs_main);
819- stats.nHeight = mapBlockIndex.find(stats.hashBlock)->second->nHeight;
820+ const CBlockIndex* pindex = LookupBlockIndex(stats.hashBlock);
821+ assert(pindex);
905@@ -904,7 +906,7 @@ bool static AlreadyHave(const CInv& inv) EXCLUSIVE_LOCKS_REQUIRED(cs_main)
906 }
907 case MSG_BLOCK:
908 case MSG_WITNESS_BLOCK:
909- return mapBlockIndex.count(inv.hash);
910+ return LookupBlockIndex(inv.hash);
Prefer this?
0return LookupBlockIndex(inv.hash) != nullptr;
424@@ -425,6 +425,12 @@ class CVerifyDB {
425 /** Replay blocks that aren't fully applied to the database. */
426 bool ReplayBlocks(const CChainParams& params, CCoinsView* view);
427
428+inline CBlockIndex* LookupBlockIndex(const uint256& hash)
429+{
430+ BlockMap::const_iterator it = mapBlockIndex.find(hash);
EXCLUSIVE_LOCKS_REQUIRED(cs_main)
too :-)
3790@@ -3793,7 +3791,8 @@ unsigned int CWallet::ComputeTimeSmart(const CWalletTx& wtx) const
3791 {
3792 unsigned int nTimeSmart = wtx.nTimeReceived;
3793 if (!wtx.hashUnset()) {
3794- if (mapBlockIndex.count(wtx.hashBlock)) {
3795+ const CBlockIndex* pindex = LookupBlockIndex(wtx.hashBlock);
3796+ if (pindex) {
In some of these places you could do
0if (const CBlockIndex* pindex = LookupBlockIndex(wtx.hashBlock))
to reduce the scope of the pindex variables.
1433@@ -1434,8 +1434,9 @@ bool AppInitMain(boost::thread_group& threadGroup, CScheduler& scheduler)
1434
1435 // If the loaded chain has a wrong genesis, bail out immediately
1436 // (we're likely using a testnet datadir, or the other way around).
1437- if (!mapBlockIndex.empty() && mapBlockIndex.count(chainparams.GetConsensus().hashGenesisBlock) == 0)
!mapBlockIndex.empty()
.
2279 connman->PushMessage(pfrom, msgMaker.Make(NetMsgType::GETHEADERS, chainActive.GetLocator(pindexBestHeader), uint256()));
2280 return true;
2281 }
2282
2283- if (mapBlockIndex.find(cmpctblock.header.GetHash()) == mapBlockIndex.end()) {
2284+ if (LookupBlockIndex(cmpctblock.header.GetHash())) {
!
This needs rebase. I can do it and adapt the new code if there is interest in merging it quick.
Maybe it should also make BlockMap mapBlockIndex
static?
travis failure:
0Assertion failed: lock cs_main not held in ./validation.h:433; locks held:
166@@ -167,10 +167,7 @@ void TransactionRecord::updateStatus(const CWalletTx &wtx)
167 // Determine transaction status
168
169 // Find the block the tx is in
170- CBlockIndex* pindex = nullptr;
171- BlockMap::iterator mi = mapBlockIndex.find(wtx.hashBlock);
172- if (mi != mapBlockIndex.end())
173- pindex = (*mi).second;
174+ CBlockIndex* pindex = LookupBlockIndex(wtx.hashBlock);
673@@ -674,10 +674,10 @@ UniValue getblockheader(const JSONRPCRequest& request)
674 if (!request.params[1].isNull())
675 fVerbose = request.params[1].get_bool();
676
677- if (mapBlockIndex.count(hash) == 0)
678+ CBlockIndex* pblockindex = LookupBlockIndex(hash);
const CBlockIndex*
?
752@@ -753,12 +753,12 @@ UniValue getblock(const JSONRPCRequest& request)
753 verbosity = request.params[1].get_bool() ? 1 : 0;
754 }
755
756- if (mapBlockIndex.count(hash) == 0)
757+ CBlockIndex* pblockindex = LookupBlockIndex(hash);
const CBlockIndex*
where it’s possible.cs_main
locking changes; can you please explain them? Were locks missing there before, making this a bugfix as well as refactor?I think it would be preferable to use const CBlockIndex* where it’s possible
Agree.
There are some cs_main locking changes; can you please explain them? Were locks missing there before, making this a bugfix as well as refactor?
Yes, for instance FindForkInGlobalIndex
.
I’ll check if adding annotations helps identifying more missing locks. I’ll update accordingly.
20@@ -21,9 +21,9 @@ namespace Checkpoints {
21 for (const MapCheckpoints::value_type& i : reverse_iterate(checkpoints))
22 {
23 const uint256& hash = i.second;
24- BlockMap::const_iterator t = mapBlockIndex.find(hash);
25- if (t != mapBlockIndex.end())
26- return t->second;
27+ if (CBlockIndex* const pindex = LookupBlockIndex(hash)) {
1491@@ -1487,6 +1492,8 @@ bool AppInitMain(boost::thread_group& threadGroup, CScheduler& scheduler)
1492
1493 bool is_coinsview_empty = fReset || fReindexChainState || pcoinsTip->GetBestBlock().IsNull();
1494 if (!is_coinsview_empty) {
1495+ LOCK(cs_main);
258@@ -259,12 +259,12 @@ namespace {
259
260 CBlockIndex* FindForkInGlobalIndex(const CChain& chain, const CBlockLocator& locator)
261 {
262+ LOCK(cs_main);
CreateWalletFromFile
needs cs_main
?
1812@@ -1813,9 +1813,9 @@ bool CChainState::ConnectBlock(const CBlock& block, CValidationState& state, CBl
1813 // relative to a piece of software is an objective fact these defaults can be easily reviewed.
1814 // This setting doesn't force the selection of any particular chain but makes validating some faster by
1815 // effectively caching the result of part of the verification.
1816- BlockMap::const_iterator it = mapBlockIndex.find(hashAssumeValid);
1817- if (it != mapBlockIndex.end()) {
1818- if (it->second->GetAncestor(pindex->nHeight) == pindex &&
1819+ const CBlockIndex* pindex_valid = LookupBlockIndex(hashAssumeValid);
LookupBlockIndex
will loose inline
, so do it then?
have LookupBlockIndex only return const CBlockIndex*es
If you look closely you will see that a lot of function signatures require non-const CBlockIndex*
, although a const should do the work (almost?) everywhere. I’m happy to do that in a follow up and deal with the non-const cases there. At least this PR is complete.
3639@@ -3641,17 +3640,20 @@ CBlockIndex * CChainState::InsertBlockIndex(const uint256& hash)
3640 if (hash.IsNull())
3641 return nullptr;
3642
3643+ LOCK(cs_main);
4244- continue;
4245- }
4246
4247- // process in case the block isn't known yet
4248- if (mapBlockIndex.count(hash) == 0 || (mapBlockIndex[hash]->nStatus & BLOCK_HAVE_DATA) == 0) {
4249+ {
ReadBlockFromDisk
and we want to avoid cs_main lock there right?
2769- BlockMap::iterator it = mapBlockIndex.find(hash);
2770- if (it != mapBlockIndex.end())
2771- return it->second;
2772+ CBlockIndex* pindex = LookupBlockIndex(hash);
2773+ if (pindex) {
2774+ return pindex;
3962@@ -3960,6 +3963,8 @@ CWallet* CWallet::CreateWalletFromFile(const std::string walletFile)
3963 // Try to top up keypool. No-op if the wallet is locked.
3964 walletInstance->TopUpKeyPool();
3965
3966+ LOCK(cs_main);
1407@@ -1408,6 +1408,8 @@ bool AppInitMain(boost::thread_group& threadGroup, CScheduler& scheduler)
1408
1409 uiInterface.InitMessage(_("Loading block index..."));
1410
1411+ LOCK(cs_main);
259@@ -260,12 +260,12 @@ namespace {
260
261 CBlockIndex* FindForkInGlobalIndex(const CChain& chain, const CBlockLocator& locator)
262 {
263+ AssertLockHeld(cs_main);
2777 // Check for duplicate
2778 uint256 hash = block.GetHash();
2779- BlockMap::iterator it = mapBlockIndex.find(hash);
2780- if (it != mapBlockIndex.end())
2781- return it->second;
2782+ CBlockIndex* pindex = LookupBlockIndex(hash);
There is no reason to avoid using mapBlockIndex in CChainState members, that’s what CChainState is there for
At that point there can be CBlockIndex* CChainState::LookupBlockIndex()
?
Again, please do not use LookupBlockIndex here (and a few other places).
As requested, last commit reverts changes to CChainState
. Please review.
400@@ -401,9 +401,8 @@ UniValue getblocktemplate(const JSONRPCRequest& request)
401 throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "Block decode failed");
402
403 uint256 hash = block.GetHash();
404- BlockMap::iterator mi = mapBlockIndex.find(hash);
405- if (mi != mapBlockIndex.end()) {
406- CBlockIndex *pindex = mi->second;
407+ const CBlockIndex *pindex = LookupBlockIndex(hash);
CBlockIndex* pindex
730@@ -732,9 +731,8 @@ UniValue submitblock(const JSONRPCRequest& request)
731 bool fBlockPresent = false;
732 {
733 LOCK(cs_main);
734- BlockMap::iterator mi = mapBlockIndex.find(hash);
735- if (mi != mapBlockIndex.end()) {
736- CBlockIndex *pindex = mi->second;
737+ const CBlockIndex *pindex = LookupBlockIndex(hash);
CBlockIndex* pindex
745@@ -748,9 +746,9 @@ UniValue submitblock(const JSONRPCRequest& request)
746
747 {
748 LOCK(cs_main);
749- BlockMap::iterator mi = mapBlockIndex.find(block.hashPrevBlock);
750- if (mi != mapBlockIndex.end()) {
751- UpdateUncommittedBlockStructures(block, mi->second, Params().GetConsensus());
752+ const CBlockIndex *pindex = LookupBlockIndex(block.hashPrevBlock);
CBlockIndex* pindex
When accessing mapBlockIndex cs_main must be held.
const
qualifier?
3813@@ -3816,7 +3814,12 @@ unsigned int CWallet::ComputeTimeSmart(const CWalletTx& wtx) const
3814 {
3815 unsigned int nTimeSmart = wtx.nTimeReceived;
3816 if (!wtx.hashUnset()) {
3817- if (mapBlockIndex.count(wtx.hashBlock)) {
3818+ const CBlockIndex* pindex = nullptr;
3819+ {
3820+ LOCK(cs_main);
I think this new lock is causing test failures on master. If I run
0./configure --enable-debug
1make -j12 -C src test/test_bitcoin && src/test/test_bitcoin --log_level=test_suite --run_test=wallet_tests/ComputeTimeSmart
I see:
0Entering test case "ComputeTimeSmart"
1test_bitcoin: sync.cpp:100: void potential_deadlock_detected(const std::pair<void*, void*>&, const LockStack&, const LockStack&): Assertion `false' failed.
2unknown location(0): fatal error in "ComputeTimeSmart": signal: SIGABRT (application abort requested)
3wallet/test/wallet_tests.cpp(566): last checkpoint
The problem is that ComputeTimeSmart is called by CWallet::AddToWallet, which only acquires cs_wallet, so cs_main will wind up being acquired after cs_wallet during the test.