Merge #11041: Add LookupBlockIndex

92fabcd44 Add LookupBlockIndex function (João Barbosa)
43a32b739 Add missing cs_lock in CreateWalletFromFile (João Barbosa)
f814a3e8f Fix cs_main lock in LoadExternalBlockFile (João Barbosa)
c651df8b3 Lock cs_main while loading block index in AppInitMain (João Barbosa)
02de6a6bc Assert cs_main is held when accessing mapBlockIndex (João Barbosa)

Pull request description:

  Replace all `mapBlockIndex` lookups with the new `LookupBlockIndex()`. In some cases it avoids a second lookup.

Tree-SHA512: ca31118f028a19721f2191d86f2dd398144d04df345694575a64aeb293be2f85785201480c3c578a0ec99690516205708558c0fd4168b09313378fd4e60a8412
This commit is contained in:
Wladimir J. van der Laan 2018-03-13 19:04:28 +01:00
commit d42a4fe5aa
No known key found for this signature in database
GPG Key ID: 1E4AED62986CD25D
14 changed files with 169 additions and 152 deletions

View File

@ -21,9 +21,10 @@ namespace Checkpoints {
for (const MapCheckpoints::value_type& i : reverse_iterate(checkpoints)) for (const MapCheckpoints::value_type& i : reverse_iterate(checkpoints))
{ {
const uint256& hash = i.second; const uint256& hash = i.second;
BlockMap::const_iterator t = mapBlockIndex.find(hash); CBlockIndex* pindex = LookupBlockIndex(hash);
if (t != mapBlockIndex.end()) if (pindex) {
return t->second; return pindex;
}
} }
return nullptr; return nullptr;
} }

View File

@ -19,7 +19,7 @@ struct CCheckpointData;
namespace Checkpoints namespace Checkpoints
{ {
//! Returns last CBlockIndex* in mapBlockIndex that is a checkpoint //! Returns last CBlockIndex* that is a checkpoint
CBlockIndex* GetLastCheckpoint(const CCheckpointData& data); CBlockIndex* GetLastCheckpoint(const CCheckpointData& data);
} //namespace Checkpoints } //namespace Checkpoints

View File

@ -1424,6 +1424,8 @@ bool AppInitMain()
uiInterface.InitMessage(_("Loading block index...")); uiInterface.InitMessage(_("Loading block index..."));
LOCK(cs_main);
nStart = GetTimeMillis(); nStart = GetTimeMillis();
do { do {
try { try {
@ -1457,8 +1459,9 @@ bool AppInitMain()
// If the loaded chain has a wrong genesis, bail out immediately // If the loaded chain has a wrong genesis, bail out immediately
// (we're likely using a testnet datadir, or the other way around). // (we're likely using a testnet datadir, or the other way around).
if (!mapBlockIndex.empty() && mapBlockIndex.count(chainparams.GetConsensus().hashGenesisBlock) == 0) if (!mapBlockIndex.empty() && !LookupBlockIndex(chainparams.GetConsensus().hashGenesisBlock)) {
return InitError(_("Incorrect or no genesis block found. Wrong datadir for network?")); return InitError(_("Incorrect or no genesis block found. Wrong datadir for network?"));
}
// Check for changed -txindex state // Check for changed -txindex state
if (fTxIndex != gArgs.GetBoolArg("-txindex", DEFAULT_TXINDEX)) { if (fTxIndex != gArgs.GetBoolArg("-txindex", DEFAULT_TXINDEX)) {
@ -1532,16 +1535,13 @@ bool AppInitMain()
MIN_BLOCKS_TO_KEEP); MIN_BLOCKS_TO_KEEP);
} }
{ CBlockIndex* tip = chainActive.Tip();
LOCK(cs_main); RPCNotifyBlockChange(true, tip);
CBlockIndex* tip = chainActive.Tip(); if (tip && tip->nTime > GetAdjustedTime() + 2 * 60 * 60) {
RPCNotifyBlockChange(true, tip); strLoadError = _("The block database contains a block which appears to be from the future. "
if (tip && tip->nTime > GetAdjustedTime() + 2 * 60 * 60) { "This may be due to your computer's date and time being set incorrectly. "
strLoadError = _("The block database contains a block which appears to be from the future. " "Only rebuild the block database if you are sure that your computer's date and time are correct");
"This may be due to your computer's date and time being set incorrectly. " break;
"Only rebuild the block database if you are sure that your computer's date and time are correct");
break;
}
} }
if (!CVerifyDB().VerifyDB(chainparams, pcoinsdbview.get(), gArgs.GetArg("-checklevel", DEFAULT_CHECKLEVEL), if (!CVerifyDB().VerifyDB(chainparams, pcoinsdbview.get(), gArgs.GetArg("-checklevel", DEFAULT_CHECKLEVEL),

View File

@ -374,10 +374,11 @@ void ProcessBlockAvailability(NodeId nodeid) {
assert(state != nullptr); assert(state != nullptr);
if (!state->hashLastUnknownBlock.IsNull()) { if (!state->hashLastUnknownBlock.IsNull()) {
BlockMap::iterator itOld = mapBlockIndex.find(state->hashLastUnknownBlock); const CBlockIndex* pindex = LookupBlockIndex(state->hashLastUnknownBlock);
if (itOld != mapBlockIndex.end() && itOld->second->nChainWork > 0) { if (pindex && pindex->nChainWork > 0) {
if (state->pindexBestKnownBlock == nullptr || itOld->second->nChainWork >= state->pindexBestKnownBlock->nChainWork) if (state->pindexBestKnownBlock == nullptr || pindex->nChainWork >= state->pindexBestKnownBlock->nChainWork) {
state->pindexBestKnownBlock = itOld->second; state->pindexBestKnownBlock = pindex;
}
state->hashLastUnknownBlock.SetNull(); state->hashLastUnknownBlock.SetNull();
} }
} }
@ -390,11 +391,12 @@ void UpdateBlockAvailability(NodeId nodeid, const uint256 &hash) {
ProcessBlockAvailability(nodeid); ProcessBlockAvailability(nodeid);
BlockMap::iterator it = mapBlockIndex.find(hash); const CBlockIndex* pindex = LookupBlockIndex(hash);
if (it != mapBlockIndex.end() && it->second->nChainWork > 0) { if (pindex && pindex->nChainWork > 0) {
// An actually better block was announced. // An actually better block was announced.
if (state->pindexBestKnownBlock == nullptr || it->second->nChainWork >= state->pindexBestKnownBlock->nChainWork) if (state->pindexBestKnownBlock == nullptr || pindex->nChainWork >= state->pindexBestKnownBlock->nChainWork) {
state->pindexBestKnownBlock = it->second; state->pindexBestKnownBlock = pindex;
}
} else { } else {
// An unknown block was announced; just assume that the latest one is the best one. // An unknown block was announced; just assume that the latest one is the best one.
state->hashLastUnknownBlock = hash; state->hashLastUnknownBlock = hash;
@ -1015,7 +1017,7 @@ bool static AlreadyHave(const CInv& inv) EXCLUSIVE_LOCKS_REQUIRED(cs_main)
} }
case MSG_BLOCK: case MSG_BLOCK:
case MSG_WITNESS_BLOCK: case MSG_WITNESS_BLOCK:
return mapBlockIndex.count(inv.hash); return LookupBlockIndex(inv.hash) != nullptr;
} }
// Don't know what it is, just say we already got one // Don't know what it is, just say we already got one
return true; return true;
@ -1082,11 +1084,10 @@ void static ProcessGetBlockData(CNode* pfrom, const Consensus::Params& consensus
bool need_activate_chain = false; bool need_activate_chain = false;
{ {
LOCK(cs_main); LOCK(cs_main);
BlockMap::iterator mi = mapBlockIndex.find(inv.hash); const CBlockIndex* pindex = LookupBlockIndex(inv.hash);
if (mi != mapBlockIndex.end()) if (pindex) {
{ if (pindex->nChainTx && !pindex->IsValid(BLOCK_VALID_SCRIPTS) &&
if (mi->second->nChainTx && !mi->second->IsValid(BLOCK_VALID_SCRIPTS) && pindex->IsValid(BLOCK_VALID_TREE)) {
mi->second->IsValid(BLOCK_VALID_TREE)) {
// If we have the block and all of its parents, but have not yet validated it, // If we have the block and all of its parents, but have not yet validated it,
// we might be in the middle of connecting it (ie in the unlock of cs_main // we might be in the middle of connecting it (ie in the unlock of cs_main
// before ActivateBestChain but after AcceptBlock). // before ActivateBestChain but after AcceptBlock).
@ -1102,9 +1103,9 @@ void static ProcessGetBlockData(CNode* pfrom, const Consensus::Params& consensus
} }
LOCK(cs_main); LOCK(cs_main);
BlockMap::iterator mi = mapBlockIndex.find(inv.hash); const CBlockIndex* pindex = LookupBlockIndex(inv.hash);
if (mi != mapBlockIndex.end()) { if (pindex) {
send = BlockRequestAllowed(mi->second, consensusParams); send = BlockRequestAllowed(pindex, consensusParams);
if (!send) { if (!send) {
LogPrint(BCLog::NET, "%s: ignoring request from peer=%i for old block that isn't in the main chain\n", __func__, pfrom->GetId()); LogPrint(BCLog::NET, "%s: ignoring request from peer=%i for old block that isn't in the main chain\n", __func__, pfrom->GetId());
} }
@ -1112,7 +1113,7 @@ void static ProcessGetBlockData(CNode* pfrom, const Consensus::Params& consensus
const CNetMsgMaker msgMaker(pfrom->GetSendVersion()); const CNetMsgMaker msgMaker(pfrom->GetSendVersion());
// disconnect node in case we have reached the outbound limit for serving historical blocks // disconnect node in case we have reached the outbound limit for serving historical blocks
// never disconnect whitelisted nodes // never disconnect whitelisted nodes
if (send && connman->OutboundTargetReached(true) && ( ((pindexBestHeader != nullptr) && (pindexBestHeader->GetBlockTime() - mi->second->GetBlockTime() > HISTORICAL_BLOCK_AGE)) || inv.type == MSG_FILTERED_BLOCK) && !pfrom->fWhitelisted) if (send && connman->OutboundTargetReached(true) && ( ((pindexBestHeader != nullptr) && (pindexBestHeader->GetBlockTime() - pindex->GetBlockTime() > HISTORICAL_BLOCK_AGE)) || inv.type == MSG_FILTERED_BLOCK) && !pfrom->fWhitelisted)
{ {
LogPrint(BCLog::NET, "historical block serving limit reached, disconnect peer=%d\n", pfrom->GetId()); LogPrint(BCLog::NET, "historical block serving limit reached, disconnect peer=%d\n", pfrom->GetId());
@ -1122,7 +1123,7 @@ void static ProcessGetBlockData(CNode* pfrom, const Consensus::Params& consensus
} }
// Avoid leaking prune-height by never sending blocks below the NODE_NETWORK_LIMITED threshold // Avoid leaking prune-height by never sending blocks below the NODE_NETWORK_LIMITED threshold
if (send && !pfrom->fWhitelisted && ( if (send && !pfrom->fWhitelisted && (
(((pfrom->GetLocalServices() & NODE_NETWORK_LIMITED) == NODE_NETWORK_LIMITED) && ((pfrom->GetLocalServices() & NODE_NETWORK) != NODE_NETWORK) && (chainActive.Tip()->nHeight - mi->second->nHeight > (int)NODE_NETWORK_LIMITED_MIN_BLOCKS + 2 /* add two blocks buffer extension for possible races */) ) (((pfrom->GetLocalServices() & NODE_NETWORK_LIMITED) == NODE_NETWORK_LIMITED) && ((pfrom->GetLocalServices() & NODE_NETWORK) != NODE_NETWORK) && (chainActive.Tip()->nHeight - pindex->nHeight > (int)NODE_NETWORK_LIMITED_MIN_BLOCKS + 2 /* add two blocks buffer extension for possible races */) )
)) { )) {
LogPrint(BCLog::NET, "Ignore block request below NODE_NETWORK_LIMITED threshold from peer=%d\n", pfrom->GetId()); LogPrint(BCLog::NET, "Ignore block request below NODE_NETWORK_LIMITED threshold from peer=%d\n", pfrom->GetId());
@ -1132,15 +1133,15 @@ void static ProcessGetBlockData(CNode* pfrom, const Consensus::Params& consensus
} }
// Pruned nodes may have deleted the block, so check whether // Pruned nodes may have deleted the block, so check whether
// it's available before trying to send. // it's available before trying to send.
if (send && (mi->second->nStatus & BLOCK_HAVE_DATA)) if (send && (pindex->nStatus & BLOCK_HAVE_DATA))
{ {
std::shared_ptr<const CBlock> pblock; std::shared_ptr<const CBlock> pblock;
if (a_recent_block && a_recent_block->GetHash() == (*mi).second->GetBlockHash()) { if (a_recent_block && a_recent_block->GetHash() == pindex->GetBlockHash()) {
pblock = a_recent_block; pblock = a_recent_block;
} else { } else {
// Send block from disk // Send block from disk
std::shared_ptr<CBlock> pblockRead = std::make_shared<CBlock>(); std::shared_ptr<CBlock> pblockRead = std::make_shared<CBlock>();
if (!ReadBlockFromDisk(*pblockRead, (*mi).second, consensusParams)) if (!ReadBlockFromDisk(*pblockRead, pindex, consensusParams))
assert(!"cannot load block from disk"); assert(!"cannot load block from disk");
pblock = pblockRead; pblock = pblockRead;
} }
@ -1182,8 +1183,8 @@ void static ProcessGetBlockData(CNode* pfrom, const Consensus::Params& consensus
// instead we respond with the full, non-compact block. // instead we respond with the full, non-compact block.
bool fPeerWantsWitness = State(pfrom->GetId())->fWantsCmpctWitness; bool fPeerWantsWitness = State(pfrom->GetId())->fWantsCmpctWitness;
int nSendFlags = fPeerWantsWitness ? 0 : SERIALIZE_TRANSACTION_NO_WITNESS; int nSendFlags = fPeerWantsWitness ? 0 : SERIALIZE_TRANSACTION_NO_WITNESS;
if (CanDirectFetch(consensusParams) && mi->second->nHeight >= chainActive.Height() - MAX_CMPCTBLOCK_DEPTH) { if (CanDirectFetch(consensusParams) && pindex->nHeight >= chainActive.Height() - MAX_CMPCTBLOCK_DEPTH) {
if ((fPeerWantsWitness || !fWitnessesPresentInARecentCompactBlock) && a_recent_compact_block && a_recent_compact_block->header.GetHash() == mi->second->GetBlockHash()) { if ((fPeerWantsWitness || !fWitnessesPresentInARecentCompactBlock) && a_recent_compact_block && a_recent_compact_block->header.GetHash() == pindex->GetBlockHash()) {
connman->PushMessage(pfrom, msgMaker.Make(nSendFlags, NetMsgType::CMPCTBLOCK, *a_recent_compact_block)); connman->PushMessage(pfrom, msgMaker.Make(nSendFlags, NetMsgType::CMPCTBLOCK, *a_recent_compact_block));
} else { } else {
CBlockHeaderAndShortTxIDs cmpctblock(*pblock, fPeerWantsWitness); CBlockHeaderAndShortTxIDs cmpctblock(*pblock, fPeerWantsWitness);
@ -1323,7 +1324,7 @@ bool static ProcessHeadersMessage(CNode *pfrom, CConnman *connman, const std::ve
// don't connect before giving DoS points // don't connect before giving DoS points
// - Once a headers message is received that is valid and does connect, // - Once a headers message is received that is valid and does connect,
// nUnconnectingHeaders gets reset back to 0. // nUnconnectingHeaders gets reset back to 0.
if (mapBlockIndex.find(headers[0].hashPrevBlock) == mapBlockIndex.end() && nCount < MAX_BLOCKS_TO_ANNOUNCE) { if (!LookupBlockIndex(headers[0].hashPrevBlock) && nCount < MAX_BLOCKS_TO_ANNOUNCE) {
nodestate->nUnconnectingHeaders++; nodestate->nUnconnectingHeaders++;
connman->PushMessage(pfrom, msgMaker.Make(NetMsgType::GETHEADERS, chainActive.GetLocator(pindexBestHeader), uint256())); connman->PushMessage(pfrom, msgMaker.Make(NetMsgType::GETHEADERS, chainActive.GetLocator(pindexBestHeader), uint256()));
LogPrint(BCLog::NET, "received header %s: missing prev block %s, sending getheaders (%d) to end (peer=%d, nUnconnectingHeaders=%d)\n", LogPrint(BCLog::NET, "received header %s: missing prev block %s, sending getheaders (%d) to end (peer=%d, nUnconnectingHeaders=%d)\n",
@ -1353,7 +1354,7 @@ bool static ProcessHeadersMessage(CNode *pfrom, CConnman *connman, const std::ve
// If we don't have the last header, then they'll have given us // If we don't have the last header, then they'll have given us
// something new (if these headers are valid). // something new (if these headers are valid).
if (mapBlockIndex.find(hashLastBlock) == mapBlockIndex.end()) { if (!LookupBlockIndex(hashLastBlock)) {
received_new_header = true; received_new_header = true;
} }
} }
@ -1369,7 +1370,7 @@ bool static ProcessHeadersMessage(CNode *pfrom, CConnman *connman, const std::ve
} else { } else {
LogPrint(BCLog::NET, "peer=%d: invalid header received\n", pfrom->GetId()); LogPrint(BCLog::NET, "peer=%d: invalid header received\n", pfrom->GetId());
} }
if (punish_duplicate_invalid && mapBlockIndex.find(first_invalid_header.GetHash()) != mapBlockIndex.end()) { if (punish_duplicate_invalid && LookupBlockIndex(first_invalid_header.GetHash())) {
// Goal: don't allow outbound peers to use up our outbound // Goal: don't allow outbound peers to use up our outbound
// connection slots if they are on incompatible chains. // connection slots if they are on incompatible chains.
// //
@ -2050,13 +2051,13 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr
LOCK(cs_main); LOCK(cs_main);
BlockMap::iterator it = mapBlockIndex.find(req.blockhash); const CBlockIndex* pindex = LookupBlockIndex(req.blockhash);
if (it == mapBlockIndex.end() || !(it->second->nStatus & BLOCK_HAVE_DATA)) { if (!pindex || !(pindex->nStatus & BLOCK_HAVE_DATA)) {
LogPrint(BCLog::NET, "Peer %d sent us a getblocktxn for a block we don't have", pfrom->GetId()); LogPrint(BCLog::NET, "Peer %d sent us a getblocktxn for a block we don't have", pfrom->GetId());
return true; return true;
} }
if (it->second->nHeight < chainActive.Height() - MAX_BLOCKTXN_DEPTH) { if (pindex->nHeight < chainActive.Height() - MAX_BLOCKTXN_DEPTH) {
// If an older block is requested (should never happen in practice, // If an older block is requested (should never happen in practice,
// but can happen in tests) send a block response instead of a // but can happen in tests) send a block response instead of a
// blocktxn response. Sending a full block response instead of a // blocktxn response. Sending a full block response instead of a
@ -2074,7 +2075,7 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr
} }
CBlock block; CBlock block;
bool ret = ReadBlockFromDisk(block, it->second, chainparams.GetConsensus()); bool ret = ReadBlockFromDisk(block, pindex, chainparams.GetConsensus());
assert(ret); assert(ret);
SendBlockTransactions(block, req, pfrom, connman); SendBlockTransactions(block, req, pfrom, connman);
@ -2098,10 +2099,10 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr
if (locator.IsNull()) if (locator.IsNull())
{ {
// If locator is null, return the hashStop block // If locator is null, return the hashStop block
BlockMap::iterator mi = mapBlockIndex.find(hashStop); pindex = LookupBlockIndex(hashStop);
if (mi == mapBlockIndex.end()) if (!pindex) {
return true; return true;
pindex = (*mi).second; }
if (!BlockRequestAllowed(pindex, chainparams.GetConsensus())) { if (!BlockRequestAllowed(pindex, chainparams.GetConsensus())) {
LogPrint(BCLog::NET, "%s: ignoring request from peer=%i for old block header that isn't in the main chain\n", __func__, pfrom->GetId()); LogPrint(BCLog::NET, "%s: ignoring request from peer=%i for old block header that isn't in the main chain\n", __func__, pfrom->GetId());
@ -2340,14 +2341,14 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr
{ {
LOCK(cs_main); LOCK(cs_main);
if (mapBlockIndex.find(cmpctblock.header.hashPrevBlock) == mapBlockIndex.end()) { if (!LookupBlockIndex(cmpctblock.header.hashPrevBlock)) {
// Doesn't connect (or is genesis), instead of DoSing in AcceptBlockHeader, request deeper headers // Doesn't connect (or is genesis), instead of DoSing in AcceptBlockHeader, request deeper headers
if (!IsInitialBlockDownload()) if (!IsInitialBlockDownload())
connman->PushMessage(pfrom, msgMaker.Make(NetMsgType::GETHEADERS, chainActive.GetLocator(pindexBestHeader), uint256())); connman->PushMessage(pfrom, msgMaker.Make(NetMsgType::GETHEADERS, chainActive.GetLocator(pindexBestHeader), uint256()));
return true; return true;
} }
if (mapBlockIndex.find(cmpctblock.header.GetHash()) == mapBlockIndex.end()) { if (!LookupBlockIndex(cmpctblock.header.GetHash())) {
received_new_header = true; received_new_header = true;
} }
} }
@ -3329,9 +3330,8 @@ bool PeerLogicValidation::SendMessages(CNode* pto, std::atomic<bool>& interruptM
// then send all headers past that one. If we come across any // then send all headers past that one. If we come across any
// headers that aren't on chainActive, give up. // headers that aren't on chainActive, give up.
for (const uint256 &hash : pto->vBlockHashesToAnnounce) { for (const uint256 &hash : pto->vBlockHashesToAnnounce) {
BlockMap::iterator mi = mapBlockIndex.find(hash); const CBlockIndex* pindex = LookupBlockIndex(hash);
assert(mi != mapBlockIndex.end()); assert(pindex);
const CBlockIndex *pindex = mi->second;
if (chainActive[pindex->nHeight] != pindex) { if (chainActive[pindex->nHeight] != pindex) {
// Bail out if we reorged away from this block // Bail out if we reorged away from this block
fRevertToInv = true; fRevertToInv = true;
@ -3422,9 +3422,8 @@ bool PeerLogicValidation::SendMessages(CNode* pto, std::atomic<bool>& interruptM
// in the past. // in the past.
if (!pto->vBlockHashesToAnnounce.empty()) { if (!pto->vBlockHashesToAnnounce.empty()) {
const uint256 &hashToAnnounce = pto->vBlockHashesToAnnounce.back(); const uint256 &hashToAnnounce = pto->vBlockHashesToAnnounce.back();
BlockMap::iterator mi = mapBlockIndex.find(hashToAnnounce); const CBlockIndex* pindex = LookupBlockIndex(hashToAnnounce);
assert(mi != mapBlockIndex.end()); assert(pindex);
const CBlockIndex *pindex = mi->second;
// Warn if we're announcing a block that is not on the main chain. // Warn if we're announcing a block that is not on the main chain.
// This should be very rare and could be optimized out. // This should be very rare and could be optimized out.

View File

@ -167,10 +167,7 @@ void TransactionRecord::updateStatus(const CWalletTx &wtx)
// Determine transaction status // Determine transaction status
// Find the block the tx is in // Find the block the tx is in
CBlockIndex* pindex = nullptr; const CBlockIndex* pindex = LookupBlockIndex(wtx.hashBlock);
BlockMap::iterator mi = mapBlockIndex.find(wtx.hashBlock);
if (mi != mapBlockIndex.end())
pindex = (*mi).second;
// Sort order, unrecorded transactions sort to the top // Sort order, unrecorded transactions sort to the top
status.sortKey = strprintf("%010d-%01d-%010u-%03d", status.sortKey = strprintf("%010d-%01d-%010u-%03d",

View File

@ -147,8 +147,7 @@ static bool rest_headers(HTTPRequest* req,
headers.reserve(count); headers.reserve(count);
{ {
LOCK(cs_main); LOCK(cs_main);
BlockMap::const_iterator it = mapBlockIndex.find(hash); const CBlockIndex* pindex = LookupBlockIndex(hash);
const CBlockIndex *pindex = (it != mapBlockIndex.end()) ? it->second : nullptr;
while (pindex != nullptr && chainActive.Contains(pindex)) { while (pindex != nullptr && chainActive.Contains(pindex)) {
headers.push_back(pindex); headers.push_back(pindex);
if (headers.size() == (unsigned long)count) if (headers.size() == (unsigned long)count)
@ -212,10 +211,11 @@ static bool rest_block(HTTPRequest* req,
CBlockIndex* pblockindex = nullptr; CBlockIndex* pblockindex = nullptr;
{ {
LOCK(cs_main); LOCK(cs_main);
if (mapBlockIndex.count(hash) == 0) pblockindex = LookupBlockIndex(hash);
if (!pblockindex) {
return RESTERR(req, HTTP_NOT_FOUND, hashStr + " not found"); return RESTERR(req, HTTP_NOT_FOUND, hashStr + " not found");
}
pblockindex = mapBlockIndex[hash];
if (fHavePruned && !(pblockindex->nStatus & BLOCK_HAVE_DATA) && pblockindex->nTx > 0) if (fHavePruned && !(pblockindex->nStatus & BLOCK_HAVE_DATA) && pblockindex->nTx > 0)
return RESTERR(req, HTTP_NOT_FOUND, hashStr + " not available (pruned data)"); return RESTERR(req, HTTP_NOT_FOUND, hashStr + " not available (pruned data)");

View File

@ -709,10 +709,10 @@ UniValue getblockheader(const JSONRPCRequest& request)
if (!request.params[1].isNull()) if (!request.params[1].isNull())
fVerbose = request.params[1].get_bool(); fVerbose = request.params[1].get_bool();
if (mapBlockIndex.count(hash) == 0) const CBlockIndex* pblockindex = LookupBlockIndex(hash);
if (!pblockindex) {
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Block not found"); throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Block not found");
}
CBlockIndex* pblockindex = mapBlockIndex[hash];
if (!fVerbose) if (!fVerbose)
{ {
@ -788,12 +788,12 @@ UniValue getblock(const JSONRPCRequest& request)
verbosity = request.params[1].get_bool() ? 1 : 0; verbosity = request.params[1].get_bool() ? 1 : 0;
} }
if (mapBlockIndex.count(hash) == 0) const CBlockIndex* pblockindex = LookupBlockIndex(hash);
if (!pblockindex) {
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Block not found"); throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Block not found");
}
CBlock block; CBlock block;
CBlockIndex* pblockindex = mapBlockIndex[hash];
if (fHavePruned && !(pblockindex->nStatus & BLOCK_HAVE_DATA) && pblockindex->nTx > 0) if (fHavePruned && !(pblockindex->nStatus & BLOCK_HAVE_DATA) && pblockindex->nTx > 0)
throw JSONRPCError(RPC_MISC_ERROR, "Block not available (pruned data)"); throw JSONRPCError(RPC_MISC_ERROR, "Block not available (pruned data)");
@ -858,7 +858,7 @@ static bool GetUTXOStats(CCoinsView *view, CCoinsStats &stats)
stats.hashBlock = pcursor->GetBestBlock(); stats.hashBlock = pcursor->GetBestBlock();
{ {
LOCK(cs_main); LOCK(cs_main);
stats.nHeight = mapBlockIndex.find(stats.hashBlock)->second->nHeight; stats.nHeight = LookupBlockIndex(stats.hashBlock)->nHeight;
} }
ss << stats.hashBlock; ss << stats.hashBlock;
uint256 prevkey; uint256 prevkey;
@ -1041,8 +1041,7 @@ UniValue gettxout(const JSONRPCRequest& request)
} }
} }
BlockMap::iterator it = mapBlockIndex.find(pcoinsTip->GetBestBlock()); const CBlockIndex* pindex = LookupBlockIndex(pcoinsTip->GetBestBlock());
CBlockIndex *pindex = it->second;
ret.pushKV("bestblock", pindex->GetBlockHash().GetHex()); ret.pushKV("bestblock", pindex->GetBlockHash().GetHex());
if (coin.nHeight == MEMPOOL_HEIGHT) { if (coin.nHeight == MEMPOOL_HEIGHT) {
ret.pushKV("confirmations", 0); ret.pushKV("confirmations", 0);
@ -1436,10 +1435,10 @@ UniValue preciousblock(const JSONRPCRequest& request)
{ {
LOCK(cs_main); LOCK(cs_main);
if (mapBlockIndex.count(hash) == 0) pblockindex = LookupBlockIndex(hash);
if (!pblockindex) {
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Block not found"); throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Block not found");
}
pblockindex = mapBlockIndex[hash];
} }
CValidationState state; CValidationState state;
@ -1472,10 +1471,11 @@ UniValue invalidateblock(const JSONRPCRequest& request)
{ {
LOCK(cs_main); LOCK(cs_main);
if (mapBlockIndex.count(hash) == 0) CBlockIndex* pblockindex = LookupBlockIndex(hash);
if (!pblockindex) {
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Block not found"); throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Block not found");
}
CBlockIndex* pblockindex = mapBlockIndex[hash];
InvalidateBlock(state, Params(), pblockindex); InvalidateBlock(state, Params(), pblockindex);
} }
@ -1510,10 +1510,11 @@ UniValue reconsiderblock(const JSONRPCRequest& request)
{ {
LOCK(cs_main); LOCK(cs_main);
if (mapBlockIndex.count(hash) == 0) CBlockIndex* pblockindex = LookupBlockIndex(hash);
if (!pblockindex) {
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Block not found"); throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Block not found");
}
CBlockIndex* pblockindex = mapBlockIndex[hash];
ResetBlockFailureFlags(pblockindex); ResetBlockFailureFlags(pblockindex);
} }
@ -1560,11 +1561,10 @@ UniValue getchaintxstats(const JSONRPCRequest& request)
} else { } else {
uint256 hash = uint256S(request.params[1].get_str()); uint256 hash = uint256S(request.params[1].get_str());
LOCK(cs_main); LOCK(cs_main);
auto it = mapBlockIndex.find(hash); pindex = LookupBlockIndex(hash);
if (it == mapBlockIndex.end()) { if (!pindex) {
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Block not found"); throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Block not found");
} }
pindex = it->second;
if (!chainActive.Contains(pindex)) { if (!chainActive.Contains(pindex)) {
throw JSONRPCError(RPC_INVALID_PARAMETER, "Block is not in main chain"); throw JSONRPCError(RPC_INVALID_PARAMETER, "Block is not in main chain");
} }

View File

@ -396,9 +396,8 @@ UniValue getblocktemplate(const JSONRPCRequest& request)
throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "Block decode failed"); throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "Block decode failed");
uint256 hash = block.GetHash(); uint256 hash = block.GetHash();
BlockMap::iterator mi = mapBlockIndex.find(hash); const CBlockIndex* pindex = LookupBlockIndex(hash);
if (mi != mapBlockIndex.end()) { if (pindex) {
CBlockIndex *pindex = mi->second;
if (pindex->IsValid(BLOCK_VALID_SCRIPTS)) if (pindex->IsValid(BLOCK_VALID_SCRIPTS))
return "duplicate"; return "duplicate";
if (pindex->nStatus & BLOCK_FAILED_MASK) if (pindex->nStatus & BLOCK_FAILED_MASK)
@ -727,9 +726,8 @@ UniValue submitblock(const JSONRPCRequest& request)
bool fBlockPresent = false; bool fBlockPresent = false;
{ {
LOCK(cs_main); LOCK(cs_main);
BlockMap::iterator mi = mapBlockIndex.find(hash); const CBlockIndex* pindex = LookupBlockIndex(hash);
if (mi != mapBlockIndex.end()) { if (pindex) {
CBlockIndex *pindex = mi->second;
if (pindex->IsValid(BLOCK_VALID_SCRIPTS)) { if (pindex->IsValid(BLOCK_VALID_SCRIPTS)) {
return "duplicate"; return "duplicate";
} }
@ -743,9 +741,9 @@ UniValue submitblock(const JSONRPCRequest& request)
{ {
LOCK(cs_main); LOCK(cs_main);
BlockMap::iterator mi = mapBlockIndex.find(block.hashPrevBlock); const CBlockIndex* pindex = LookupBlockIndex(block.hashPrevBlock);
if (mi != mapBlockIndex.end()) { if (pindex) {
UpdateUncommittedBlockStructures(block, mi->second, Params().GetConsensus()); UpdateUncommittedBlockStructures(block, pindex, Params().GetConsensus());
} }
} }

View File

@ -48,9 +48,8 @@ void TxToJSON(const CTransaction& tx, const uint256 hashBlock, UniValue& entry)
if (!hashBlock.IsNull()) { if (!hashBlock.IsNull()) {
entry.pushKV("blockhash", hashBlock.GetHex()); entry.pushKV("blockhash", hashBlock.GetHex());
BlockMap::iterator mi = mapBlockIndex.find(hashBlock); CBlockIndex* pindex = LookupBlockIndex(hashBlock);
if (mi != mapBlockIndex.end() && (*mi).second) { if (pindex) {
CBlockIndex* pindex = (*mi).second;
if (chainActive.Contains(pindex)) { if (chainActive.Contains(pindex)) {
entry.pushKV("confirmations", 1 + chainActive.Height() - pindex->nHeight); entry.pushKV("confirmations", 1 + chainActive.Height() - pindex->nHeight);
entry.pushKV("time", pindex->GetBlockTime()); entry.pushKV("time", pindex->GetBlockTime());
@ -160,11 +159,10 @@ UniValue getrawtransaction(const JSONRPCRequest& request)
if (!request.params[2].isNull()) { if (!request.params[2].isNull()) {
uint256 blockhash = ParseHashV(request.params[2], "parameter 3"); uint256 blockhash = ParseHashV(request.params[2], "parameter 3");
BlockMap::iterator it = mapBlockIndex.find(blockhash); blockindex = LookupBlockIndex(blockhash);
if (it == mapBlockIndex.end()) { if (!blockindex) {
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Block hash not found"); throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Block hash not found");
} }
blockindex = it->second;
in_active_chain = chainActive.Contains(blockindex); in_active_chain = chainActive.Contains(blockindex);
} }
@ -238,9 +236,10 @@ UniValue gettxoutproof(const JSONRPCRequest& request)
if (!request.params[1].isNull()) if (!request.params[1].isNull())
{ {
hashBlock = uint256S(request.params[1].get_str()); hashBlock = uint256S(request.params[1].get_str());
if (!mapBlockIndex.count(hashBlock)) pblockindex = LookupBlockIndex(hashBlock);
if (!pblockindex) {
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Block not found"); throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Block not found");
pblockindex = mapBlockIndex[hashBlock]; }
} else { } else {
// Loop through txids and try to find which block they're in. Exit loop once a block is found. // Loop through txids and try to find which block they're in. Exit loop once a block is found.
for (const auto& tx : setTxids) { for (const auto& tx : setTxids) {
@ -257,9 +256,10 @@ UniValue gettxoutproof(const JSONRPCRequest& request)
CTransactionRef tx; CTransactionRef tx;
if (!GetTransaction(oneTxid, tx, Params().GetConsensus(), hashBlock, false) || hashBlock.IsNull()) if (!GetTransaction(oneTxid, tx, Params().GetConsensus(), hashBlock, false) || hashBlock.IsNull())
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Transaction not yet in block"); throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Transaction not yet in block");
if (!mapBlockIndex.count(hashBlock)) pblockindex = LookupBlockIndex(hashBlock);
if (!pblockindex) {
throw JSONRPCError(RPC_INTERNAL_ERROR, "Transaction index corrupt"); throw JSONRPCError(RPC_INTERNAL_ERROR, "Transaction index corrupt");
pblockindex = mapBlockIndex[hashBlock]; }
} }
CBlock block; CBlock block;
@ -306,8 +306,10 @@ UniValue verifytxoutproof(const JSONRPCRequest& request)
LOCK(cs_main); LOCK(cs_main);
if (!mapBlockIndex.count(merkleBlock.header.GetHash()) || !chainActive.Contains(mapBlockIndex[merkleBlock.header.GetHash()])) const CBlockIndex* pindex = LookupBlockIndex(merkleBlock.header.GetHash());
if (!pindex || !chainActive.Contains(pindex)) {
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Block not found in chain"); throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Block not found in chain");
}
for (const uint256& hash : vMatch) for (const uint256& hash : vMatch)
res.push_back(hash.GetHex()); res.push_back(hash.GetHex());

View File

@ -260,12 +260,12 @@ namespace {
CBlockIndex* FindForkInGlobalIndex(const CChain& chain, const CBlockLocator& locator) CBlockIndex* FindForkInGlobalIndex(const CChain& chain, const CBlockLocator& locator)
{ {
AssertLockHeld(cs_main);
// Find the first block the caller has in the main chain // Find the first block the caller has in the main chain
for (const uint256& hash : locator.vHave) { for (const uint256& hash : locator.vHave) {
BlockMap::iterator mi = mapBlockIndex.find(hash); CBlockIndex* pindex = LookupBlockIndex(hash);
if (mi != mapBlockIndex.end()) if (pindex) {
{
CBlockIndex* pindex = (*mi).second;
if (chain.Contains(pindex)) if (chain.Contains(pindex))
return pindex; return pindex;
if (pindex->GetAncestor(chain.Height()) == chain.Tip()) { if (pindex->GetAncestor(chain.Height()) == chain.Tip()) {
@ -1316,7 +1316,7 @@ bool CScriptCheck::operator()() {
int GetSpendHeight(const CCoinsViewCache& inputs) int GetSpendHeight(const CCoinsViewCache& inputs)
{ {
LOCK(cs_main); LOCK(cs_main);
CBlockIndex* pindexPrev = mapBlockIndex.find(inputs.GetBestBlock())->second; CBlockIndex* pindexPrev = LookupBlockIndex(inputs.GetBestBlock());
return pindexPrev->nHeight + 1; return pindexPrev->nHeight + 1;
} }
@ -2826,6 +2826,8 @@ bool ResetBlockFailureFlags(CBlockIndex *pindex) {
CBlockIndex* CChainState::AddToBlockIndex(const CBlockHeader& block) CBlockIndex* CChainState::AddToBlockIndex(const CBlockHeader& block)
{ {
AssertLockHeld(cs_main);
// Check for duplicate // Check for duplicate
uint256 hash = block.GetHash(); uint256 hash = block.GetHash();
BlockMap::iterator it = mapBlockIndex.find(hash); BlockMap::iterator it = mapBlockIndex.find(hash);
@ -3272,7 +3274,6 @@ bool CChainState::AcceptBlockHeader(const CBlockHeader& block, CValidationState&
BlockMap::iterator miSelf = mapBlockIndex.find(hash); BlockMap::iterator miSelf = mapBlockIndex.find(hash);
CBlockIndex *pindex = nullptr; CBlockIndex *pindex = nullptr;
if (hash != chainparams.GetConsensus().hashGenesisBlock) { if (hash != chainparams.GetConsensus().hashGenesisBlock) {
if (miSelf != mapBlockIndex.end()) { if (miSelf != mapBlockIndex.end()) {
// Block header is already known. // Block header is already known.
pindex = miSelf->second; pindex = miSelf->second;
@ -3706,6 +3707,8 @@ fs::path GetBlockPosFilename(const CDiskBlockPos &pos, const char *prefix)
CBlockIndex * CChainState::InsertBlockIndex(const uint256& hash) CBlockIndex * CChainState::InsertBlockIndex(const uint256& hash)
{ {
AssertLockHeld(cs_main);
if (hash.IsNull()) if (hash.IsNull())
return nullptr; return nullptr;
@ -3833,6 +3836,8 @@ bool static LoadBlockIndexDB(const CChainParams& chainparams)
bool LoadChainTip(const CChainParams& chainparams) bool LoadChainTip(const CChainParams& chainparams)
{ {
AssertLockHeld(cs_main);
if (chainActive.Tip() && chainActive.Tip()->GetBlockHash() == pcoinsTip->GetBestBlock()) return true; if (chainActive.Tip() && chainActive.Tip()->GetBlockHash() == pcoinsTip->GetBestBlock()) return true;
if (pcoinsTip->GetBestBlock().IsNull() && mapBlockIndex.size() == 1) { if (pcoinsTip->GetBestBlock().IsNull() && mapBlockIndex.size() == 1) {
@ -3846,10 +3851,11 @@ bool LoadChainTip(const CChainParams& chainparams)
} }
// Load pointer to end of best chain // Load pointer to end of best chain
BlockMap::iterator it = mapBlockIndex.find(pcoinsTip->GetBestBlock()); CBlockIndex* pindex = LookupBlockIndex(pcoinsTip->GetBestBlock());
if (it == mapBlockIndex.end()) if (!pindex) {
return false; return false;
chainActive.SetTip(it->second); }
chainActive.SetTip(pindex);
g_chainstate.PruneBlockIndexCandidates(); g_chainstate.PruneBlockIndexCandidates();
@ -4296,26 +4302,31 @@ bool LoadExternalBlockFile(const CChainParams& chainparams, FILE* fileIn, CDiskB
blkdat >> block; blkdat >> block;
nRewind = blkdat.GetPos(); nRewind = blkdat.GetPos();
// detect out of order blocks, and store them for later
uint256 hash = block.GetHash(); uint256 hash = block.GetHash();
if (hash != chainparams.GetConsensus().hashGenesisBlock && mapBlockIndex.find(block.hashPrevBlock) == mapBlockIndex.end()) { {
LogPrint(BCLog::REINDEX, "%s: Out of order block %s, parent %s not known\n", __func__, hash.ToString(),
block.hashPrevBlock.ToString());
if (dbp)
mapBlocksUnknownParent.insert(std::make_pair(block.hashPrevBlock, *dbp));
continue;
}
// process in case the block isn't known yet
if (mapBlockIndex.count(hash) == 0 || (mapBlockIndex[hash]->nStatus & BLOCK_HAVE_DATA) == 0) {
LOCK(cs_main); LOCK(cs_main);
CValidationState state; // detect out of order blocks, and store them for later
if (g_chainstate.AcceptBlock(pblock, state, chainparams, nullptr, true, dbp, nullptr)) if (hash != chainparams.GetConsensus().hashGenesisBlock && !LookupBlockIndex(block.hashPrevBlock)) {
nLoaded++; LogPrint(BCLog::REINDEX, "%s: Out of order block %s, parent %s not known\n", __func__, hash.ToString(),
if (state.IsError()) block.hashPrevBlock.ToString());
break; if (dbp)
} else if (hash != chainparams.GetConsensus().hashGenesisBlock && mapBlockIndex[hash]->nHeight % 1000 == 0) { mapBlocksUnknownParent.insert(std::make_pair(block.hashPrevBlock, *dbp));
LogPrint(BCLog::REINDEX, "Block Import: already had block %s at height %d\n", hash.ToString(), mapBlockIndex[hash]->nHeight); continue;
}
// process in case the block isn't known yet
CBlockIndex* pindex = LookupBlockIndex(hash);
if (!pindex || (pindex->nStatus & BLOCK_HAVE_DATA) == 0) {
CValidationState state;
if (g_chainstate.AcceptBlock(pblock, state, chainparams, nullptr, true, dbp, nullptr)) {
nLoaded++;
}
if (state.IsError()) {
break;
}
} else if (hash != chainparams.GetConsensus().hashGenesisBlock && pindex->nHeight % 1000 == 0) {
LogPrint(BCLog::REINDEX, "Block Import: already had block %s at height %d\n", hash.ToString(), pindex->nHeight);
}
} }
// Activate the genesis block so normal node progress can continue // Activate the genesis block so normal node progress can continue

View File

@ -428,6 +428,13 @@ public:
/** Replay blocks that aren't fully applied to the database. */ /** Replay blocks that aren't fully applied to the database. */
bool ReplayBlocks(const CChainParams& params, CCoinsView* view); bool ReplayBlocks(const CChainParams& params, CCoinsView* view);
inline CBlockIndex* LookupBlockIndex(const uint256& hash)
{
AssertLockHeld(cs_main);
BlockMap::const_iterator it = mapBlockIndex.find(hash);
return it == mapBlockIndex.end() ? nullptr : it->second;
}
/** Find the last common block between the parameter chain and a locator. */ /** Find the last common block between the parameter chain and a locator. */
CBlockIndex* FindForkInGlobalIndex(const CChain& chain, const CBlockLocator& locator); CBlockIndex* FindForkInGlobalIndex(const CChain& chain, const CBlockLocator& locator);

View File

@ -350,9 +350,10 @@ UniValue importprunedfunds(const JSONRPCRequest& request)
if (merkleBlock.txn.ExtractMatches(vMatch, vIndex) == merkleBlock.header.hashMerkleRoot) { if (merkleBlock.txn.ExtractMatches(vMatch, vIndex) == merkleBlock.header.hashMerkleRoot) {
LOCK(cs_main); LOCK(cs_main);
const CBlockIndex* pindex = LookupBlockIndex(merkleBlock.header.GetHash());
if (!mapBlockIndex.count(merkleBlock.header.GetHash()) || !chainActive.Contains(mapBlockIndex[merkleBlock.header.GetHash()])) if (!pindex || !chainActive.Contains(pindex)) {
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Block not found in chain"); throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Block not found in chain");
}
std::vector<uint256>::const_iterator it; std::vector<uint256>::const_iterator it;
if ((it = std::find(vMatch.begin(), vMatch.end(), hashTx))==vMatch.end()) { if ((it = std::find(vMatch.begin(), vMatch.end(), hashTx))==vMatch.end()) {

View File

@ -95,7 +95,7 @@ void WalletTxToJSON(const CWalletTx& wtx, UniValue& entry)
{ {
entry.pushKV("blockhash", wtx.hashBlock.GetHex()); entry.pushKV("blockhash", wtx.hashBlock.GetHex());
entry.pushKV("blockindex", wtx.nIndex); entry.pushKV("blockindex", wtx.nIndex);
entry.pushKV("blocktime", mapBlockIndex[wtx.hashBlock]->GetBlockTime()); entry.pushKV("blocktime", LookupBlockIndex(wtx.hashBlock)->GetBlockTime());
} else { } else {
entry.pushKV("trusted", wtx.IsTrusted()); entry.pushKV("trusted", wtx.IsTrusted());
} }
@ -2043,11 +2043,10 @@ UniValue listsinceblock(const JSONRPCRequest& request)
uint256 blockId; uint256 blockId;
blockId.SetHex(request.params[0].get_str()); blockId.SetHex(request.params[0].get_str());
BlockMap::iterator it = mapBlockIndex.find(blockId); paltindex = pindex = LookupBlockIndex(blockId);
if (it == mapBlockIndex.end()) { if (!pindex) {
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Block not found"); throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Block not found");
} }
paltindex = pindex = it->second;
if (chainActive[pindex->nHeight] != pindex) { if (chainActive[pindex->nHeight] != pindex) {
// the block being asked for is a part of a deactivated chain; // the block being asked for is a part of a deactivated chain;
// we don't want to depend on its perceived height in the block // we don't want to depend on its perceived height in the block

View File

@ -1147,11 +1147,9 @@ void CWallet::MarkConflicted(const uint256& hashBlock, const uint256& hashTx)
LOCK2(cs_main, cs_wallet); LOCK2(cs_main, cs_wallet);
int conflictconfirms = 0; int conflictconfirms = 0;
if (mapBlockIndex.count(hashBlock)) { CBlockIndex* pindex = LookupBlockIndex(hashBlock);
CBlockIndex* pindex = mapBlockIndex[hashBlock]; if (pindex && chainActive.Contains(pindex)) {
if (chainActive.Contains(pindex)) { conflictconfirms = -(chainActive.Height() - pindex->nHeight + 1);
conflictconfirms = -(chainActive.Height() - pindex->nHeight + 1);
}
} }
// If number of conflict confirms cannot be determined, this means // If number of conflict confirms cannot be determined, this means
// that the block is still unknown or not yet part of the main chain, // that the block is still unknown or not yet part of the main chain,
@ -3767,10 +3765,10 @@ void CWallet::GetKeyBirthTimes(std::map<CTxDestination, int64_t> &mapKeyBirth) c
for (const auto& entry : mapWallet) { for (const auto& entry : mapWallet) {
// iterate over all wallet transactions... // iterate over all wallet transactions...
const CWalletTx &wtx = entry.second; const CWalletTx &wtx = entry.second;
BlockMap::const_iterator blit = mapBlockIndex.find(wtx.hashBlock); CBlockIndex* pindex = LookupBlockIndex(wtx.hashBlock);
if (blit != mapBlockIndex.end() && chainActive.Contains(blit->second)) { if (pindex && chainActive.Contains(pindex)) {
// ... which are already in a block // ... which are already in a block
int nHeight = blit->second->nHeight; int nHeight = pindex->nHeight;
for (const CTxOut &txout : wtx.tx->vout) { for (const CTxOut &txout : wtx.tx->vout) {
// iterate over all their outputs // iterate over all their outputs
CAffectedKeysVisitor(*this, vAffected).Process(txout.scriptPubKey); CAffectedKeysVisitor(*this, vAffected).Process(txout.scriptPubKey);
@ -3778,7 +3776,7 @@ void CWallet::GetKeyBirthTimes(std::map<CTxDestination, int64_t> &mapKeyBirth) c
// ... and all their affected keys // ... and all their affected keys
std::map<CKeyID, CBlockIndex*>::iterator rit = mapKeyFirstBlock.find(keyid); std::map<CKeyID, CBlockIndex*>::iterator rit = mapKeyFirstBlock.find(keyid);
if (rit != mapKeyFirstBlock.end() && nHeight < rit->second->nHeight) if (rit != mapKeyFirstBlock.end() && nHeight < rit->second->nHeight)
rit->second = blit->second; rit->second = pindex;
} }
vAffected.clear(); vAffected.clear();
} }
@ -3815,7 +3813,12 @@ unsigned int CWallet::ComputeTimeSmart(const CWalletTx& wtx) const
{ {
unsigned int nTimeSmart = wtx.nTimeReceived; unsigned int nTimeSmart = wtx.nTimeReceived;
if (!wtx.hashUnset()) { if (!wtx.hashUnset()) {
if (mapBlockIndex.count(wtx.hashBlock)) { const CBlockIndex* pindex = nullptr;
{
LOCK(cs_main);
pindex = LookupBlockIndex(wtx.hashBlock);
}
if (pindex) {
int64_t latestNow = wtx.nTimeReceived; int64_t latestNow = wtx.nTimeReceived;
int64_t latestEntry = 0; int64_t latestEntry = 0;
@ -3846,7 +3849,7 @@ unsigned int CWallet::ComputeTimeSmart(const CWalletTx& wtx) const
} }
} }
int64_t blocktime = mapBlockIndex[wtx.hashBlock]->GetBlockTime(); int64_t blocktime = pindex->GetBlockTime();
nTimeSmart = std::max(latestEntry, std::min(blocktime, latestNow)); nTimeSmart = std::max(latestEntry, std::min(blocktime, latestNow));
} else { } else {
LogPrintf("%s: found %s in block %s not in index\n", __func__, wtx.GetHash().ToString(), wtx.hashBlock.ToString()); LogPrintf("%s: found %s in block %s not in index\n", __func__, wtx.GetHash().ToString(), wtx.hashBlock.ToString());
@ -4016,6 +4019,8 @@ CWallet* CWallet::CreateWalletFromFile(const std::string& name, const fs::path&
// Try to top up keypool. No-op if the wallet is locked. // Try to top up keypool. No-op if the wallet is locked.
walletInstance->TopUpKeyPool(); walletInstance->TopUpKeyPool();
LOCK(cs_main);
CBlockIndex *pindexRescan = chainActive.Genesis(); CBlockIndex *pindexRescan = chainActive.Genesis();
if (!gArgs.GetBoolArg("-rescan", false)) if (!gArgs.GetBoolArg("-rescan", false))
{ {
@ -4159,10 +4164,7 @@ int CMerkleTx::GetDepthInMainChain(const CBlockIndex* &pindexRet) const
AssertLockHeld(cs_main); AssertLockHeld(cs_main);
// Find the block it claims to be in // Find the block it claims to be in
BlockMap::iterator mi = mapBlockIndex.find(hashBlock); CBlockIndex* pindex = LookupBlockIndex(hashBlock);
if (mi == mapBlockIndex.end())
return 0;
CBlockIndex* pindex = (*mi).second;
if (!pindex || !chainActive.Contains(pindex)) if (!pindex || !chainActive.Contains(pindex))
return 0; return 0;