Skip to content

Commit 5c1eb67

Browse files
committed
merge bitcoin#24050: Give m_block_index ownership of CBlockIndexes
1 parent c440304 commit 5c1eb67

File tree

11 files changed

+69
-77
lines changed

11 files changed

+69
-77
lines changed

src/node/blockstorage.cpp

Lines changed: 27 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -37,35 +37,40 @@ static FILE* OpenUndoFile(const FlatFilePos& pos, bool fReadOnly = false);
3737
static FlatFileSeq BlockFileSeq();
3838
static FlatFileSeq UndoFileSeq();
3939

40-
CBlockIndex* BlockManager::LookupBlockIndex(const uint256& hash) const
40+
CBlockIndex* BlockManager::LookupBlockIndex(const uint256& hash)
41+
{
42+
AssertLockHeld(cs_main);
43+
BlockMap::iterator it = m_block_index.find(hash);
44+
return it == m_block_index.end() ? nullptr : &it->second;
45+
}
46+
47+
const CBlockIndex* BlockManager::LookupBlockIndex(const uint256& hash) const
4148
{
4249
AssertLockHeld(cs_main);
4350
BlockMap::const_iterator it = m_block_index.find(hash);
44-
return it == m_block_index.end() ? nullptr : it->second;
51+
return it == m_block_index.end() ? nullptr : &it->second;
4552
}
4653

4754
CBlockIndex* BlockManager::AddToBlockIndex(const CBlockHeader& block, const uint256& hash, enum BlockStatus nStatus)
4855
{
4956
assert(!(nStatus & BLOCK_FAILED_MASK)); // no failed blocks allowed
5057
AssertLockHeld(cs_main);
5158

52-
// Check for duplicate
53-
BlockMap::iterator it = m_block_index.find(hash);
54-
if (it != m_block_index.end()) {
55-
return it->second;
59+
auto [mi, inserted] = m_block_index.try_emplace(hash, block);
60+
if (!inserted) {
61+
return &mi->second;
5662
}
63+
CBlockIndex* pindexNew = &(*mi).second;
5764

58-
// Construct new block index object
59-
CBlockIndex* pindexNew = new CBlockIndex(block);
6065
// We assign the sequence id to blocks only when the full data is available,
6166
// to avoid miners withholding blocks but broadcasting headers, to get a
6267
// competitive advantage.
6368
pindexNew->nSequenceId = 0;
64-
BlockMap::iterator mi = m_block_index.insert(std::make_pair(hash, pindexNew)).first;
69+
6570
pindexNew->phashBlock = &((*mi).first);
6671
BlockMap::iterator miPrev = m_block_index.find(block.hashPrevBlock);
6772
if (miPrev != m_block_index.end()) {
68-
pindexNew->pprev = (*miPrev).second;
73+
pindexNew->pprev = &(*miPrev).second;
6974
pindexNew->nHeight = pindexNew->pprev->nHeight + 1;
7075
pindexNew->BuildSkip();
7176
}
@@ -96,8 +101,8 @@ void BlockManager::PruneOneBlockFile(const int fileNumber)
96101
AssertLockHeld(cs_main);
97102
LOCK(cs_LastBlockFile);
98103

99-
for (const auto& entry : m_block_index) {
100-
CBlockIndex* pindex = entry.second;
104+
for (auto& entry : m_block_index) {
105+
CBlockIndex* pindex = &entry.second;
101106
if (pindex->nFile == fileNumber) {
102107
pindex->nStatus &= ~BLOCK_HAVE_DATA;
103108
pindex->nStatus &= ~BLOCK_HAVE_UNDO;
@@ -215,18 +220,13 @@ CBlockIndex* BlockManager::InsertBlockIndex(const uint256& hash)
215220
return nullptr;
216221
}
217222

218-
// Return existing
219-
BlockMap::iterator mi = m_block_index.find(hash);
220-
if (mi != m_block_index.end()) {
221-
return (*mi).second;
223+
// Return existing or create new
224+
auto [mi, inserted] = m_block_index.try_emplace(hash);
225+
CBlockIndex* pindex = &(*mi).second;
226+
if (inserted) {
227+
pindex->phashBlock = &((*mi).first);
222228
}
223-
224-
// Create new
225-
CBlockIndex* pindexNew = new CBlockIndex();
226-
mi = m_block_index.insert(std::make_pair(hash, pindexNew)).first;
227-
pindexNew->phashBlock = &((*mi).first);
228-
229-
return pindexNew;
229+
return pindex;
230230
}
231231

232232
bool BlockManager::LoadBlockIndex(
@@ -240,8 +240,8 @@ bool BlockManager::LoadBlockIndex(
240240
// Calculate nChainWork
241241
std::vector<std::pair<int, CBlockIndex*>> vSortedByHeight;
242242
vSortedByHeight.reserve(m_block_index.size());
243-
for (const std::pair<const uint256, CBlockIndex*>& item : m_block_index) {
244-
CBlockIndex* pindex = item.second;
243+
for (auto& [_, block_index] : m_block_index) {
244+
CBlockIndex* pindex = &block_index;
245245
vSortedByHeight.push_back(std::make_pair(pindex->nHeight, pindex));
246246

247247
// build m_blockman.m_prev_block_index
@@ -348,10 +348,6 @@ void BlockManager::Unload()
348348
{
349349
m_blocks_unlinked.clear();
350350

351-
for (const BlockMap::value_type& entry : m_block_index) {
352-
delete entry.second;
353-
}
354-
355351
m_block_index.clear();
356352
m_prev_block_index.clear();
357353

@@ -407,8 +403,8 @@ bool BlockManager::LoadBlockIndexDB(ChainstateManager& chainman)
407403
// Check presence of blk files
408404
LogPrintf("Checking all blk files are present...\n");
409405
std::set<int> setBlkDataFiles;
410-
for (const std::pair<const uint256, CBlockIndex*>& item : m_block_index) {
411-
CBlockIndex* pindex = item.second;
406+
for (const auto& [_, block_index] : m_block_index) {
407+
const CBlockIndex* pindex = &block_index;
412408
if (pindex->nStatus & BLOCK_HAVE_DATA) {
413409
setBlkDataFiles.insert(pindex->nFile);
414410
}

src/node/blockstorage.h

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
#ifndef BITCOIN_NODE_BLOCKSTORAGE_H
66
#define BITCOIN_NODE_BLOCKSTORAGE_H
77

8+
#include <chain.h>
89
#include <fs.h>
910
#include <protocol.h> // For CMessageHeader::MessageStartChars
1011
#include <sync.h>
@@ -20,7 +21,6 @@ class ArgsManager;
2021
class BlockValidationState;
2122
class CBlock;
2223
class CBlockFileInfo;
23-
class CBlockIndex;
2424
class CBlockUndo;
2525
class CChain;
2626
class CChainParams;
@@ -63,8 +63,12 @@ extern bool fTimestampIndex;
6363
/** True if we're running in -spentindex mode. */
6464
extern bool fSpentIndex;
6565

66-
typedef std::unordered_map<uint256, CBlockIndex*, BlockHasher> BlockMap;
67-
typedef std::unordered_multimap<uint256, CBlockIndex*, BlockHasher> PrevBlockMap;
66+
// Because validation code takes pointers to the map's CBlockIndex objects, if
67+
// we ever switch to another associative container, we need to either use a
68+
// container that has stable addressing (true of all std associative
69+
// containers), or make the key a `std::unique_ptr<CBlockIndex>`
70+
using BlockMap = std::unordered_map<uint256, CBlockIndex, BlockHasher>;
71+
using PrevBlockMap = std::unordered_multimap<uint256, CBlockIndex*, BlockHasher>;
6872

6973
struct CBlockIndexWorkComparator {
7074
bool operator()(const CBlockIndex* pa, const CBlockIndex* pb) const;
@@ -157,7 +161,8 @@ class BlockManager
157161
//! Mark one block file as pruned (modify associated database entries)
158162
void PruneOneBlockFile(const int fileNumber) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
159163

160-
CBlockIndex* LookupBlockIndex(const uint256& hash) const EXCLUSIVE_LOCKS_REQUIRED(cs_main);
164+
CBlockIndex* LookupBlockIndex(const uint256& hash) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
165+
const CBlockIndex* LookupBlockIndex(const uint256& hash) const EXCLUSIVE_LOCKS_REQUIRED(cs_main);
161166

162167
/** Get block file info entry for one block file */
163168
CBlockFileInfo* GetBlockFileInfo(size_t n);

src/rpc/blockchain.cpp

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1879,10 +1879,10 @@ static RPCHelpMan getchaintips()
18791879
std::set<const CBlockIndex*> setOrphans;
18801880
std::set<const CBlockIndex*> setPrevs;
18811881

1882-
for (const std::pair<const uint256, CBlockIndex*>& item : chainman.BlockIndex()) {
1883-
if (!active_chain.Contains(item.second)) {
1884-
setOrphans.insert(item.second);
1885-
setPrevs.insert(item.second->pprev);
1882+
for (const auto& [_, block_index] : chainman.BlockIndex()) {
1883+
if (!active_chain.Contains(&block_index)) {
1884+
setOrphans.insert(&block_index);
1885+
setPrevs.insert(block_index.pprev);
18861886
}
18871887
}
18881888

src/rpc/evo.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1558,7 +1558,7 @@ static RPCHelpMan protx_info()
15581558
g_txindex->BlockUntilSyncedToCurrentChain();
15591559
}
15601560

1561-
CBlockIndex* pindex{nullptr};
1561+
const CBlockIndex* pindex{nullptr};
15621562

15631563
uint256 proTxHash(ParseHashV(request.params[0], "proTxHash"));
15641564

src/rpc/masternode.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -370,7 +370,7 @@ static RPCHelpMan masternode_payments()
370370
const NodeContext& node = EnsureAnyNodeContext(request.context);
371371
const ChainstateManager& chainman = EnsureChainman(node);
372372

373-
CBlockIndex* pindex{nullptr};
373+
const CBlockIndex* pindex{nullptr};
374374

375375
if (g_txindex) {
376376
g_txindex->BlockUntilSyncedToCurrentChain();

src/rpc/quorums.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -966,7 +966,7 @@ static RPCHelpMan verifychainlock()
966966
const ChainstateManager& chainman = EnsureChainman(node);
967967

968968
int nBlockHeight;
969-
CBlockIndex* pIndex{nullptr};
969+
const CBlockIndex* pIndex{nullptr};
970970
if (request.params[2].isNull()) {
971971
pIndex = WITH_LOCK(cs_main, return chainman.m_blockman.LookupBlockIndex(nBlockHash));
972972
if (pIndex == nullptr) {

src/rpc/rawtransaction.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,7 @@ void TxToJSON(const CTransaction& tx, const uint256 hashBlock, CTxMemPool& mempo
9393
bool chainLock = false;
9494
if (!hashBlock.IsNull()) {
9595
entry.pushKV("blockhash", hashBlock.GetHex());
96-
CBlockIndex* pindex = active_chainstate.m_blockman.LookupBlockIndex(hashBlock);
96+
const CBlockIndex* pindex = active_chainstate.m_blockman.LookupBlockIndex(hashBlock);
9797
if (pindex) {
9898
if (active_chainstate.m_chain.Contains(pindex)) {
9999
entry.pushKV("height", pindex->nHeight);
@@ -324,7 +324,7 @@ static RPCHelpMan getrawtransactionmulti() {
324324
const uint256 blockhash{uint256S(blockhash_str)};
325325
const UniValue txids = transactions[blockhash_str].get_array();
326326

327-
CBlockIndex* blockindex{blockhash.IsNull() ? nullptr : WITH_LOCK(::cs_main, return chainman.m_blockman.LookupBlockIndex(blockhash))};
327+
const CBlockIndex* blockindex{blockhash.IsNull() ? nullptr : WITH_LOCK(::cs_main, return chainman.m_blockman.LookupBlockIndex(blockhash))};
328328
if (blockindex == nullptr && !blockhash.IsNull()) {
329329
for (const auto idx : irange::range(txids.size())) {
330330
result.pushKV(txids[idx].get_str(), "None");

src/test/validation_chainstate_tests.cpp

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -77,9 +77,6 @@ BOOST_AUTO_TEST_CASE(validation_chainstate_resize_caches)
7777
// The view cache should be empty since we had to destruct to downsize.
7878
BOOST_CHECK(!c1.CoinsTip().HaveCoinInCache(outpoint));
7979
}
80-
81-
// Avoid triggering the address sanitizer.
82-
WITH_LOCK(::cs_main, manager.Unload());
8380
}
8481

8582
//! Test UpdateTip behavior for both active and background chainstates.

src/test/validation_chainstatemanager_tests.cpp

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -114,8 +114,6 @@ BOOST_AUTO_TEST_CASE(chainstatemanager)
114114
SyncWithValidationInterfaceQueue();
115115

116116
DashTestSetupClose(m_node);
117-
118-
WITH_LOCK(::cs_main, manager.Unload());
119117
}
120118

121119
//! Test rebalancing the caches associated with each chainstate.

src/validation.cpp

Lines changed: 22 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1906,7 +1906,7 @@ bool CChainState::ConnectBlock(const CBlock& block, BlockValidationState& state,
19061906
// effectively caching the result of part of the verification.
19071907
BlockMap::const_iterator it = m_blockman.m_block_index.find(hashAssumeValid);
19081908
if (it != m_blockman.m_block_index.end()) {
1909-
if (it->second->GetAncestor(pindex->nHeight) == pindex &&
1909+
if (it->second.GetAncestor(pindex->nHeight) == pindex &&
19101910
pindexBestHeader->GetAncestor(pindex->nHeight) == pindex &&
19111911
pindexBestHeader->nChainWork >= nMinimumChainWork) {
19121912
// This block is a member of the assumed verified chain and an ancestor of the best header.
@@ -3116,8 +3116,8 @@ bool CChainState::InvalidateBlock(BlockValidationState& state, CBlockIndex* pind
31163116

31173117
{
31183118
LOCK(cs_main);
3119-
for (const auto& entry : m_blockman.m_block_index) {
3120-
CBlockIndex *candidate = entry.second;
3119+
for (auto& entry : m_blockman.m_block_index) {
3120+
CBlockIndex* candidate = &entry.second;
31213121
// We don't need to put anything in our active chain into the
31223122
// multimap, because those candidates will be found and considered
31233123
// as we disconnect.
@@ -3225,12 +3225,10 @@ bool CChainState::InvalidateBlock(BlockValidationState& state, CBlockIndex* pind
32253225
// it up here, this should be an essentially unobservable error.
32263226
// Loop back over all block index entries and add any missing entries
32273227
// to setBlockIndexCandidates.
3228-
BlockMap::iterator it = m_blockman.m_block_index.begin();
3229-
while (it != m_blockman.m_block_index.end()) {
3230-
if (it->second->IsValid(BLOCK_VALID_TRANSACTIONS) && !(it->second->nStatus & BLOCK_CONFLICT_CHAINLOCK) && it->second->HaveTxsDownloaded() && !setBlockIndexCandidates.value_comp()(it->second, m_chain.Tip())) {
3231-
setBlockIndexCandidates.insert(it->second);
3228+
for (auto& [_, block_index] : m_blockman.m_block_index) {
3229+
if (block_index.IsValid(BLOCK_VALID_TRANSACTIONS) && !(block_index.nStatus & BLOCK_CONFLICT_CHAINLOCK) && block_index.HaveTxsDownloaded() && !setBlockIndexCandidates.value_comp()(&block_index, m_chain.Tip())) {
3230+
setBlockIndexCandidates.insert(&block_index);
32323231
}
3233-
it++;
32343232
}
32353233

32363234
InvalidChainFound(to_mark_failed);
@@ -3329,8 +3327,8 @@ bool CChainState::MarkConflictingBlock(BlockValidationState& state, CBlockIndex
33293327
// add it again.
33303328
BlockMap::iterator it = m_blockman.m_block_index.begin();
33313329
while (it != m_blockman.m_block_index.end()) {
3332-
if (it->second->IsValid(BLOCK_VALID_TRANSACTIONS) && !(it->second->nStatus & BLOCK_CONFLICT_CHAINLOCK) && it->second->HaveTxsDownloaded() && !setBlockIndexCandidates.value_comp()(it->second, m_chain.Tip())) {
3333-
setBlockIndexCandidates.insert(it->second);
3330+
if (it->second.IsValid(BLOCK_VALID_TRANSACTIONS) && !(it->second.nStatus & BLOCK_CONFLICT_CHAINLOCK) && it->second.HaveTxsDownloaded() && !setBlockIndexCandidates.value_comp()(&it->second, m_chain.Tip())) {
3331+
setBlockIndexCandidates.insert(&it->second);
33343332
}
33353333
it++;
33363334
}
@@ -3362,21 +3360,19 @@ void CChainState::ResetBlockFailureFlags(CBlockIndex *pindex) {
33623360
int nHeight = pindex->nHeight;
33633361

33643362
// Remove the invalidity flag from this block and all its descendants.
3365-
BlockMap::iterator it = m_blockman.m_block_index.begin();
3366-
while (it != m_blockman.m_block_index.end()) {
3367-
if (!it->second->IsValid() && it->second->GetAncestor(nHeight) == pindex) {
3368-
it->second->nStatus &= ~BLOCK_FAILED_MASK;
3369-
m_blockman.m_dirty_blockindex.insert(it->second);
3370-
if (it->second->IsValid(BLOCK_VALID_TRANSACTIONS) && !(it->second->nStatus & BLOCK_CONFLICT_CHAINLOCK) && it->second->HaveTxsDownloaded() && setBlockIndexCandidates.value_comp()(m_chain.Tip(), it->second)) {
3371-
setBlockIndexCandidates.insert(it->second);
3363+
for (auto& [_, block_index] : m_blockman.m_block_index) {
3364+
if (!block_index.IsValid() && block_index.GetAncestor(nHeight) == pindex) {
3365+
block_index.nStatus &= ~BLOCK_FAILED_MASK;
3366+
m_blockman.m_dirty_blockindex.insert(&block_index);
3367+
if (block_index.IsValid(BLOCK_VALID_TRANSACTIONS) && !(block_index.nStatus & BLOCK_CONFLICT_CHAINLOCK) && block_index.HaveTxsDownloaded() && setBlockIndexCandidates.value_comp()(m_chain.Tip(), &block_index)) {
3368+
setBlockIndexCandidates.insert(&block_index);
33723369
}
3373-
if (it->second == m_chainman.m_best_invalid) {
3370+
if (&block_index == m_chainman.m_best_invalid) {
33743371
// Reset invalid block marker if it was pointing to one of those.
33753372
m_chainman.m_best_invalid = nullptr;
33763373
}
3377-
m_chainman.m_failed_blocks.erase(it->second);
3374+
m_chainman.m_failed_blocks.erase(&block_index);
33783375
}
3379-
it++;
33803376
}
33813377

33823378
// Remove the invalidity flag from all ancestors too.
@@ -3687,7 +3683,7 @@ bool ChainstateManager::AcceptBlockHeader(const CBlockHeader& block, BlockValida
36873683
if (hash != chainparams.GetConsensus().hashGenesisBlock) {
36883684
if (miSelf != m_blockman.m_block_index.end()) {
36893685
// Block header is already known.
3690-
CBlockIndex* pindex = miSelf->second;
3686+
CBlockIndex* pindex = &(miSelf->second);
36913687
if (ppindex)
36923688
*ppindex = pindex;
36933689
if (pindex->nStatus & BLOCK_FAILED_MASK) {
@@ -3713,7 +3709,7 @@ bool ChainstateManager::AcceptBlockHeader(const CBlockHeader& block, BlockValida
37133709
LogPrintf("ERROR: %s: prev block not found\n", __func__);
37143710
return state.Invalid(BlockValidationResult::BLOCK_MISSING_PREV, "prev-blk-not-found");
37153711
}
3716-
pindexPrev = (*mi).second;
3712+
pindexPrev = &((*mi).second);
37173713
assert(pindexPrev);
37183714

37193715
if (pindexPrev->nStatus & BLOCK_FAILED_MASK) {
@@ -4298,13 +4294,13 @@ bool CChainState::ReplayBlocks()
42984294
if (m_blockman.m_block_index.count(hashHeads[0]) == 0) {
42994295
return error("ReplayBlocks(): reorganization to unknown block requested");
43004296
}
4301-
pindexNew = m_blockman.m_block_index[hashHeads[0]];
4297+
pindexNew = &(m_blockman.m_block_index[hashHeads[0]]);
43024298

43034299
if (!hashHeads[1].IsNull()) { // The old tip is allowed to be 0, indicating it's the first flush.
43044300
if (m_blockman.m_block_index.count(hashHeads[1]) == 0) {
43054301
return error("ReplayBlocks(): reorganization from unknown block requested");
43064302
}
4307-
pindexOld = m_blockman.m_block_index[hashHeads[1]];
4303+
pindexOld = &(m_blockman.m_block_index[hashHeads[1]]);
43084304
pindexFork = LastCommonAncestor(pindexOld, pindexNew);
43094305
assert(pindexFork != nullptr);
43104306
const bool fDIP0003Active = pindexOld->nHeight >= m_params.GetConsensus().DIP0003Height;
@@ -4590,8 +4586,8 @@ void CChainState::CheckBlockIndex()
45904586

45914587
// Build forward-pointing map of the entire block tree.
45924588
std::multimap<CBlockIndex*,CBlockIndex*> forward;
4593-
for (const std::pair<const uint256, CBlockIndex*>& entry : m_blockman.m_block_index) {
4594-
forward.insert(std::make_pair(entry.second->pprev, entry.second));
4589+
for (auto& [_, block_index] : m_blockman.m_block_index) {
4590+
forward.emplace(block_index.pprev, &block_index);
45954591
}
45964592

45974593
assert(forward.size() == m_blockman.m_block_index.size());

0 commit comments

Comments
 (0)