From 714aea576089013be7b401f6e963f822f6b09d91 Mon Sep 17 00:00:00 2001 From: Jeremy Rubin Date: Thu, 6 Aug 2020 22:03:40 -0700 Subject: [PATCH] Refactor BlockMap to use an unordered_set instead of an unordered_map --- src/bench/rpc_blockchain.cpp | 2 +- src/chain.h | 8 +-- src/rpc/blockchain.cpp | 10 +-- src/test/fuzz/chain.cpp | 3 - src/test/miner_tests.cpp | 5 +- src/test/skiplist_tests.cpp | 6 +- src/validation.cpp | 113 ++++++++++++++++--------------- src/validation.h | 18 ++++- src/wallet/test/wallet_tests.cpp | 10 +-- 9 files changed, 93 insertions(+), 82 deletions(-) diff --git a/src/bench/rpc_blockchain.cpp b/src/bench/rpc_blockchain.cpp index 4b45264a3cf1a2..6dcd1afe6fed75 100644 --- a/src/bench/rpc_blockchain.cpp +++ b/src/bench/rpc_blockchain.cpp @@ -22,7 +22,7 @@ static void BlockToJsonVerbose(benchmark::Bench& bench) CBlockIndex blockindex; const uint256 blockHash = block.GetHash(); - blockindex.phashBlock = &blockHash; + blockindex.m_hash_block = blockHash; blockindex.nBits = 403014710; bench.run([&] { diff --git a/src/chain.h b/src/chain.h index 802e23f7759a4c..9eda3a6160a565 100644 --- a/src/chain.h +++ b/src/chain.h @@ -137,8 +137,8 @@ enum BlockStatus: uint32_t { class CBlockIndex { public: - //! pointer to the hash of the block, if any. Memory is owned by this CBlockIndex - const uint256* phashBlock{nullptr}; + //! hash of the block. m_hash_block.IsNull() if there is not yet a hash + uint256 m_hash_block; //! pointer to the index of the predecessor of this block CBlockIndex* pprev{nullptr}; @@ -230,9 +230,9 @@ class CBlockIndex return block; } - uint256 GetBlockHash() const + const uint256& GetBlockHash() const { - return *phashBlock; + return m_hash_block; } /** diff --git a/src/rpc/blockchain.cpp b/src/rpc/blockchain.cpp index f27373b57cc440..7c37148c8312bc 100644 --- a/src/rpc/blockchain.cpp +++ b/src/rpc/blockchain.cpp @@ -1347,10 +1347,10 @@ static UniValue getchaintips(const JSONRPCRequest& request) std::set setOrphans; std::set setPrevs; - for (const std::pair& item : chainman.BlockIndex()) { - if (!chainman.ActiveChain().Contains(item.second)) { - setOrphans.insert(item.second); - setPrevs.insert(item.second->pprev); + for (CBlockIndex* pindex : chainman.BlockIndex()) { + if (!chainman.ActiveChain().Contains(pindex)) { + setOrphans.insert(pindex); + setPrevs.insert(pindex->pprev); } } @@ -1368,7 +1368,7 @@ static UniValue getchaintips(const JSONRPCRequest& request) for (const CBlockIndex* block : setTips) { UniValue obj(UniValue::VOBJ); obj.pushKV("height", block->nHeight); - obj.pushKV("hash", block->phashBlock->GetHex()); + obj.pushKV("hash", block->m_hash_block.GetHex()); const int branchLen = block->nHeight - chainman.ActiveChain().FindFork(block)->nHeight; obj.pushKV("branchlen", branchLen); diff --git a/src/test/fuzz/chain.cpp b/src/test/fuzz/chain.cpp index 47c71850cea6d5..7893536737d57c 100644 --- a/src/test/fuzz/chain.cpp +++ b/src/test/fuzz/chain.cpp @@ -19,8 +19,6 @@ void test_one_input(const std::vector& buffer) return; } - const uint256 zero{}; - disk_block_index->phashBlock = &zero; (void)disk_block_index->GetBlockHash(); (void)disk_block_index->GetBlockPos(); (void)disk_block_index->GetBlockTime(); @@ -59,7 +57,6 @@ void test_one_input(const std::vector& buffer) } CBlockIndex block_index{block_header}; - block_index.phashBlock = &zero; (void)block_index.GetBlockHash(); (void)block_index.ToString(); } diff --git a/src/test/miner_tests.cpp b/src/test/miner_tests.cpp index 62a0dc42413f7c..9f41a6642cb380 100644 --- a/src/test/miner_tests.cpp +++ b/src/test/miner_tests.cpp @@ -377,7 +377,7 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity) while (::ChainActive().Tip()->nHeight < 209999) { CBlockIndex* prev = ::ChainActive().Tip(); CBlockIndex* next = new CBlockIndex(); - next->phashBlock = new uint256(InsecureRand256()); + next->m_hash_block = uint256(InsecureRand256()); ::ChainstateActive().CoinsTip().SetBestBlock(next->GetBlockHash()); next->pprev = prev; next->nHeight = prev->nHeight + 1; @@ -389,7 +389,7 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity) while (::ChainActive().Tip()->nHeight < 210000) { CBlockIndex* prev = ::ChainActive().Tip(); CBlockIndex* next = new CBlockIndex(); - next->phashBlock = new uint256(InsecureRand256()); + next->m_hash_block = uint256(InsecureRand256()); ::ChainstateActive().CoinsTip().SetBestBlock(next->GetBlockHash()); next->pprev = prev; next->nHeight = prev->nHeight + 1; @@ -421,7 +421,6 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity) CBlockIndex* del = ::ChainActive().Tip(); ::ChainActive().SetTip(del->pprev); ::ChainstateActive().CoinsTip().SetBestBlock(del->pprev->GetBlockHash()); - delete del->phashBlock; delete del; } diff --git a/src/test/skiplist_tests.cpp b/src/test/skiplist_tests.cpp index 7ede79279f0920..ad86c288e2092b 100644 --- a/src/test/skiplist_tests.cpp +++ b/src/test/skiplist_tests.cpp @@ -51,7 +51,7 @@ BOOST_AUTO_TEST_CASE(getlocator_test) vHashMain[i] = ArithToUint256(i); // Set the hash equal to the height, so we can quickly check the distances. vBlocksMain[i].nHeight = i; vBlocksMain[i].pprev = i ? &vBlocksMain[i - 1] : nullptr; - vBlocksMain[i].phashBlock = &vHashMain[i]; + vBlocksMain[i].m_hash_block = vHashMain[i]; vBlocksMain[i].BuildSkip(); BOOST_CHECK_EQUAL((int)UintToArith256(vBlocksMain[i].GetBlockHash()).GetLow64(), vBlocksMain[i].nHeight); BOOST_CHECK(vBlocksMain[i].pprev == nullptr || vBlocksMain[i].nHeight == vBlocksMain[i].pprev->nHeight + 1); @@ -64,7 +64,7 @@ BOOST_AUTO_TEST_CASE(getlocator_test) vHashSide[i] = ArithToUint256(i + 50000 + (arith_uint256(1) << 128)); // Add 1<<128 to the hashes, so GetLow64() still returns the height. vBlocksSide[i].nHeight = i + 50000; vBlocksSide[i].pprev = i ? &vBlocksSide[i - 1] : (vBlocksMain.data()+49999); - vBlocksSide[i].phashBlock = &vHashSide[i]; + vBlocksSide[i].m_hash_block = vHashSide[i]; vBlocksSide[i].BuildSkip(); BOOST_CHECK_EQUAL((int)UintToArith256(vBlocksSide[i].GetBlockHash()).GetLow64(), vBlocksSide[i].nHeight); BOOST_CHECK(vBlocksSide[i].pprev == nullptr || vBlocksSide[i].nHeight == vBlocksSide[i].pprev->nHeight + 1); @@ -106,7 +106,7 @@ BOOST_AUTO_TEST_CASE(findearliestatleast_test) vHashMain[i] = ArithToUint256(i); // Set the hash equal to the height vBlocksMain[i].nHeight = i; vBlocksMain[i].pprev = i ? &vBlocksMain[i - 1] : nullptr; - vBlocksMain[i].phashBlock = &vHashMain[i]; + vBlocksMain[i].m_hash_block = vHashMain[i]; vBlocksMain[i].BuildSkip(); if (i < 10) { vBlocksMain[i].nTime = i; diff --git a/src/validation.cpp b/src/validation.cpp index 81af9727775c5d..1e54492a79b5be 100644 --- a/src/validation.cpp +++ b/src/validation.cpp @@ -173,8 +173,9 @@ namespace { CBlockIndex* LookupBlockIndex(const uint256& hash) { AssertLockHeld(cs_main); - BlockMap::const_iterator it = g_chainman.BlockIndex().find(hash); - return it == g_chainman.BlockIndex().end() ? nullptr : it->second; + auto& idx = g_chainman.BlockIndex(); + BlockMap::const_iterator it = idx.find(idx.hash_function()(hash)); + return it == idx.end() ? nullptr : *it; } CBlockIndex* FindForkInGlobalIndex(const CChain& chain, const CBlockLocator& locator) @@ -1345,14 +1346,14 @@ static void CheckForkWarningConditions() EXCLUSIVE_LOCKS_REQUIRED(cs_main) if (!GetfLargeWorkForkFound() && pindexBestForkBase) { std::string warning = std::string("'Warning: Large-work fork detected, forking after block ") + - pindexBestForkBase->phashBlock->ToString() + std::string("'"); + pindexBestForkBase->m_hash_block.ToString() + std::string("'"); AlertNotify(warning); } if (pindexBestForkTip && pindexBestForkBase) { LogPrintf("%s: Warning: Large valid fork found\n forking the chain at height %d (%s)\n lasting to height %d (%s).\nChain state database corruption likely.\n", __func__, - pindexBestForkBase->nHeight, pindexBestForkBase->phashBlock->ToString(), - pindexBestForkTip->nHeight, pindexBestForkTip->phashBlock->ToString()); + pindexBestForkBase->nHeight, pindexBestForkBase->m_hash_block.ToString(), + pindexBestForkTip->nHeight, pindexBestForkTip->m_hash_block.ToString()); SetfLargeWorkForkFound(true); } else @@ -1875,8 +1876,8 @@ static unsigned int GetBlockScriptFlags(const CBlockIndex* pindex, const Consens // mainnet and testnet), so for simplicity, always leave P2SH // on except for the one violating block. if (consensusparams.BIP16Exception.IsNull() || // no bip16 exception on this chain - pindex->phashBlock == nullptr || // this is a new candidate block, eg from TestBlockValidity() - *pindex->phashBlock != consensusparams.BIP16Exception) // this block isn't the historical exception + pindex->m_hash_block.IsNull() || // this is a new candidate block, eg from TestBlockValidity() + pindex->m_hash_block != consensusparams.BIP16Exception) // this block isn't the historical exception { flags |= SCRIPT_VERIFY_P2SH; } @@ -1929,7 +1930,7 @@ bool CChainState::ConnectBlock(const CBlock& block, BlockValidationState& state, { AssertLockHeld(cs_main); assert(pindex); - assert(*pindex->phashBlock == block.GetHash()); + assert(pindex->m_hash_block == block.GetHash()); int64_t nTimeStart = GetTimeMicros(); // Check it again in case a previous version let a bad block in @@ -1976,9 +1977,10 @@ bool CChainState::ConnectBlock(const CBlock& block, BlockValidationState& state, // relative to a piece of software is an objective fact these defaults can be easily reviewed. // This setting doesn't force the selection of any particular chain but makes validating some faster by // effectively caching the result of part of the verification. - BlockMap::const_iterator it = m_blockman.m_block_index.find(hashAssumeValid); + // + BlockMap::const_iterator it = m_blockman.m_block_index.find(m_blockman.m_block_index.hash_function()(hashAssumeValid)); if (it != m_blockman.m_block_index.end()) { - if (it->second->GetAncestor(pindex->nHeight) == pindex && + if ((*it)->GetAncestor(pindex->nHeight) == pindex && pindexBestHeader->GetAncestor(pindex->nHeight) == pindex && pindexBestHeader->nChainWork >= nMinimumChainWork) { // This block is a member of the assumed verified chain and an ancestor of the best header. @@ -2214,7 +2216,7 @@ bool CChainState::ConnectBlock(const CBlock& block, BlockValidationState& state, setDirtyBlockIndex.insert(pindex); } - assert(pindex->phashBlock); + assert(!pindex->m_hash_block.IsNull()); // add this block to the view's block chain view.SetBestBlock(pindex->GetBlockHash()); @@ -2995,8 +2997,7 @@ bool CChainState::InvalidateBlock(BlockValidationState& state, const CChainParam { LOCK(cs_main); - for (const auto& entry : m_blockman.m_block_index) { - CBlockIndex *candidate = entry.second; + for (CBlockIndex* candidate : m_blockman.m_block_index) { // We don't need to put anything in our active chain into the // multimap, because those candidates will be found and considered // as we disconnect. @@ -3093,8 +3094,8 @@ bool CChainState::InvalidateBlock(BlockValidationState& state, const CChainParam // to setBlockIndexCandidates. BlockMap::iterator it = m_blockman.m_block_index.begin(); while (it != m_blockman.m_block_index.end()) { - if (it->second->IsValid(BLOCK_VALID_TRANSACTIONS) && it->second->HaveTxsDownloaded() && !setBlockIndexCandidates.value_comp()(it->second, m_chain.Tip())) { - setBlockIndexCandidates.insert(it->second); + if ((*it)->IsValid(BLOCK_VALID_TRANSACTIONS) && (*it)->HaveTxsDownloaded() && !setBlockIndexCandidates.value_comp()(*it, m_chain.Tip())) { + setBlockIndexCandidates.insert(*it); } it++; } @@ -3121,17 +3122,18 @@ void CChainState::ResetBlockFailureFlags(CBlockIndex *pindex) { // Remove the invalidity flag from this block and all its descendants. BlockMap::iterator it = m_blockman.m_block_index.begin(); while (it != m_blockman.m_block_index.end()) { - if (!it->second->IsValid() && it->second->GetAncestor(nHeight) == pindex) { - it->second->nStatus &= ~BLOCK_FAILED_MASK; - setDirtyBlockIndex.insert(it->second); - if (it->second->IsValid(BLOCK_VALID_TRANSACTIONS) && it->second->HaveTxsDownloaded() && setBlockIndexCandidates.value_comp()(m_chain.Tip(), it->second)) { - setBlockIndexCandidates.insert(it->second); + CBlockIndex& block = **it; + if (!block.IsValid() && block.GetAncestor(nHeight) == pindex) { + block.nStatus &= ~BLOCK_FAILED_MASK; + setDirtyBlockIndex.insert(&block); + if (block.IsValid(BLOCK_VALID_TRANSACTIONS) && block.HaveTxsDownloaded() && setBlockIndexCandidates.value_comp()(m_chain.Tip(), &block)) { + setBlockIndexCandidates.insert(&block); } - if (it->second == pindexBestInvalid) { + if (&block == pindexBestInvalid) { // Reset invalid block marker if it was pointing to one of those. pindexBestInvalid = nullptr; } - m_blockman.m_failed_blocks.erase(it->second); + m_blockman.m_failed_blocks.erase(&block); } it++; } @@ -3157,9 +3159,9 @@ CBlockIndex* BlockManager::AddToBlockIndex(const CBlockHeader& block) // Check for duplicate uint256 hash = block.GetHash(); - BlockMap::iterator it = m_block_index.find(hash); + BlockMap::iterator it = m_block_index.find(m_block_index.hash_function()(hash)); if (it != m_block_index.end()) - return it->second; + return *it; // Construct new block index object CBlockIndex* pindexNew = new CBlockIndex(block); @@ -3167,12 +3169,12 @@ CBlockIndex* BlockManager::AddToBlockIndex(const CBlockHeader& block) // to avoid miners withholding blocks but broadcasting headers, to get a // competitive advantage. pindexNew->nSequenceId = 0; - BlockMap::iterator mi = m_block_index.insert(std::make_pair(hash, pindexNew)).first; - pindexNew->phashBlock = &((*mi).first); - BlockMap::iterator miPrev = m_block_index.find(block.hashPrevBlock); + pindexNew->m_hash_block = hash; + m_block_index.insert(pindexNew); + BlockMap::iterator miPrev = m_block_index.find(m_block_index.hash_function()(block.hashPrevBlock)); if (miPrev != m_block_index.end()) { - pindexNew->pprev = (*miPrev).second; + pindexNew->pprev = *miPrev; pindexNew->nHeight = pindexNew->pprev->nHeight + 1; pindexNew->BuildSkip(); } @@ -3614,12 +3616,12 @@ bool BlockManager::AcceptBlockHeader(const CBlockHeader& block, BlockValidationS AssertLockHeld(cs_main); // Check for duplicate uint256 hash = block.GetHash(); - BlockMap::iterator miSelf = m_block_index.find(hash); + BlockMap::iterator miSelf = m_block_index.find(m_block_index.hash_function()(hash)); CBlockIndex *pindex = nullptr; if (hash != chainparams.GetConsensus().hashGenesisBlock) { if (miSelf != m_block_index.end()) { // Block header is already known. - pindex = miSelf->second; + pindex = *miSelf; if (ppindex) *ppindex = pindex; if (pindex->nStatus & BLOCK_FAILED_MASK) { @@ -3636,12 +3638,12 @@ bool BlockManager::AcceptBlockHeader(const CBlockHeader& block, BlockValidationS // Get prev block index CBlockIndex* pindexPrev = nullptr; - BlockMap::iterator mi = m_block_index.find(block.hashPrevBlock); + BlockMap::iterator mi = m_block_index.find(m_block_index.hash_function()(block.hashPrevBlock)); if (mi == m_block_index.end()) { LogPrintf("ERROR: %s: prev block not found\n", __func__); return state.Invalid(BlockValidationResult::BLOCK_MISSING_PREV, "prev-blk-not-found"); } - pindexPrev = (*mi).second; + pindexPrev = *mi; if (pindexPrev->nStatus & BLOCK_FAILED_MASK) { LogPrintf("ERROR: %s: prev block invalid\n", __func__); return state.Invalid(BlockValidationResult::BLOCK_INVALID_PREV, "bad-prevblk"); @@ -3871,7 +3873,7 @@ bool TestBlockValidity(BlockValidationState& state, const CChainParams& chainpar CBlockIndex indexDummy(block); indexDummy.pprev = pindexPrev; indexDummy.nHeight = pindexPrev->nHeight + 1; - indexDummy.phashBlock = &block_hash; + indexDummy.m_hash_block = block_hash; // NOTE: CheckBlockHeader is called by CheckBlock if (!ContextualCheckBlockHeader(block, state, chainparams, pindexPrev, GetAdjustedTime())) @@ -3908,8 +3910,7 @@ void ChainstateManager::PruneOneBlockFile(const int fileNumber) AssertLockHeld(cs_main); LOCK(cs_LastBlockFile); - for (const auto& entry : m_blockman.m_block_index) { - CBlockIndex* pindex = entry.second; + for (CBlockIndex* pindex : m_blockman.m_block_index) { if (pindex->nFile == fileNumber) { pindex->nStatus &= ~BLOCK_HAVE_DATA; pindex->nStatus &= ~BLOCK_HAVE_UNDO; @@ -4084,14 +4085,14 @@ CBlockIndex * BlockManager::InsertBlockIndex(const uint256& hash) return nullptr; // Return existing - BlockMap::iterator mi = m_block_index.find(hash); + BlockMap::iterator mi = m_block_index.find(m_block_index.hash_function()(hash)); if (mi != m_block_index.end()) - return (*mi).second; + return *mi; // Create new CBlockIndex* pindexNew = new CBlockIndex(); - mi = m_block_index.insert(std::make_pair(hash, pindexNew)).first; - pindexNew->phashBlock = &((*mi).first); + pindexNew->m_hash_block = hash; + mi = m_block_index.insert(pindexNew).first; return pindexNew; } @@ -4107,9 +4108,8 @@ bool BlockManager::LoadBlockIndex( // Calculate nChainWork std::vector > vSortedByHeight; vSortedByHeight.reserve(m_block_index.size()); - for (const std::pair& item : m_block_index) + for (CBlockIndex* pindex : m_block_index) { - CBlockIndex* pindex = item.second; vSortedByHeight.push_back(std::make_pair(pindex->nHeight, pindex)); } sort(vSortedByHeight.begin(), vSortedByHeight.end()); @@ -4155,8 +4155,8 @@ void BlockManager::Unload() { m_failed_blocks.clear(); m_blocks_unlinked.clear(); - for (const BlockMap::value_type& entry : m_block_index) { - delete entry.second; + for (CBlockIndex* pindex : m_block_index) { + delete pindex; } m_block_index.clear(); @@ -4190,8 +4190,7 @@ bool static LoadBlockIndexDB(ChainstateManager& chainman, const CChainParams& ch // Check presence of blk files LogPrintf("Checking all blk files are present...\n"); std::set setBlkDataFiles; - for (const std::pair& item : chainman.BlockIndex()) { - CBlockIndex* pindex = item.second; + for (CBlockIndex* pindex : chainman.BlockIndex()) { if (pindex->nStatus & BLOCK_HAVE_DATA) { setBlkDataFiles.insert(pindex->nFile); } @@ -4392,16 +4391,18 @@ bool CChainState::ReplayBlocks(const CChainParams& params) const CBlockIndex* pindexNew; // New tip during the interrupted flush. const CBlockIndex* pindexFork = nullptr; // Latest block common to both the old and the new tip. - if (m_blockman.m_block_index.count(hashHeads[0]) == 0) { + auto mi = m_blockman.m_block_index.find(m_blockman.m_block_index.hash_function()(hashHeads[0])); + if (mi == m_blockman.m_block_index.end()) { return error("ReplayBlocks(): reorganization to unknown block requested"); } - pindexNew = m_blockman.m_block_index[hashHeads[0]]; + pindexNew = *mi; if (!hashHeads[1].IsNull()) { // The old tip is allowed to be 0, indicating it's the first flush. - if (m_blockman.m_block_index.count(hashHeads[1]) == 0) { + auto mi2 = m_blockman.m_block_index.find(m_blockman.m_block_index.hash_function()(hashHeads[1])); + if (mi2 == m_blockman.m_block_index.end()) { return error("ReplayBlocks(): reorganization from unknown block requested"); } - pindexOld = m_blockman.m_block_index[hashHeads[1]]; + pindexOld = *mi2; pindexFork = LastCommonAncestor(pindexOld, pindexNew); assert(pindexFork != nullptr); } @@ -4486,9 +4487,9 @@ bool CChainState::RewindBlockIndex(const CChainParams& params) // blocks will be dealt with below (releasing cs_main in between). { LOCK(cs_main); - for (const auto& entry : m_blockman.m_block_index) { - if (IsWitnessEnabled(entry.second->pprev, params.GetConsensus()) && !(entry.second->nStatus & BLOCK_OPT_WITNESS) && !m_chain.Contains(entry.second)) { - EraseBlockData(entry.second); + for (CBlockIndex* pindex : m_blockman.m_block_index) { + if (IsWitnessEnabled(pindex->pprev, params.GetConsensus()) && !(pindex->nStatus & BLOCK_OPT_WITNESS) && !m_chain.Contains(pindex)) { + EraseBlockData(pindex); } } } @@ -4636,7 +4637,7 @@ bool CChainState::LoadGenesisBlock(const CChainParams& chainparams) // m_blockman.m_block_index. Note that we can't use m_chain here, since it is // set based on the coins db, not the block index db, which is the only // thing loaded at this point. - if (m_blockman.m_block_index.count(chainparams.GenesisBlock().GetHash())) + if (m_blockman.m_block_index.count(m_blockman.m_block_index.hash_function()(chainparams.GenesisBlock().GetHash()))) return true; try { @@ -4795,8 +4796,8 @@ void CChainState::CheckBlockIndex(const Consensus::Params& consensusParams) // Build forward-pointing map of the entire block tree. std::multimap forward; - for (const std::pair& entry : m_blockman.m_block_index) { - forward.insert(std::make_pair(entry.second->pprev, entry.second)); + for (CBlockIndex* pindex : m_blockman.m_block_index) { + forward.insert(std::make_pair(pindex->pprev, pindex)); } assert(forward.size() == m_blockman.m_block_index.size()); @@ -5216,7 +5217,7 @@ class CMainCleanup // block headers BlockMap::iterator it1 = g_chainman.BlockIndex().begin(); for (; it1 != g_chainman.BlockIndex().end(); it1++) - delete (*it1).second; + delete *it1; g_chainman.BlockIndex().clear(); } }; diff --git a/src/validation.h b/src/validation.h index 534162d64aa6a7..9835f68e166012 100644 --- a/src/validation.h +++ b/src/validation.h @@ -101,7 +101,21 @@ struct BlockHasher // this used to call `GetCheapHash()` in uint256, which was later moved; the // cheap hash function simply calls ReadLE64() however, so the end result is // identical - size_t operator()(const uint256& hash) const { return ReadLE64(hash.begin()); } + mutable CBlockIndex mock; + BlockHasher() : mock() {}; + size_t operator()(CBlockIndex* const& ptr) const { return ReadLE64(ptr->GetBlockHash().begin()); } + // Helper for querying by hash + // e.g., map.find(map.hash_function()(h)) + CBlockIndex* operator()(const uint256& hash) { + mock.m_hash_block = hash; + return &mock; + } +}; + + +struct BlockEqual +{ + bool operator()(CBlockIndex* const& ptr, CBlockIndex* const& ptr2) const { return ptr->GetBlockHash() == ptr2->GetBlockHash(); } }; /** Current sync state passed to tip changed callbacks. */ @@ -114,7 +128,7 @@ enum class SynchronizationState { extern RecursiveMutex cs_main; extern CBlockPolicyEstimator feeEstimator; extern CTxMemPool mempool; -typedef std::unordered_map BlockMap; +typedef std::unordered_set BlockMap; extern Mutex g_best_block_mutex; extern std::condition_variable g_best_block_cv; extern uint256 g_best_block; diff --git a/src/wallet/test/wallet_tests.cpp b/src/wallet/test/wallet_tests.cpp index 7ef06663b55bba..4fea95852f05e3 100644 --- a/src/wallet/test/wallet_tests.cpp +++ b/src/wallet/test/wallet_tests.cpp @@ -347,13 +347,13 @@ static int64_t AddTx(ChainstateManager& chainman, CWallet& wallet, uint32_t lock CBlockIndex* block = nullptr; if (blockTime > 0) { LOCK(cs_main); - auto inserted = chainman.BlockIndex().emplace(GetRandHash(), new CBlockIndex); + auto pblock = new CBlockIndex; + pblock->m_hash_block = GetRandHash(); + auto inserted = chainman.BlockIndex().emplace(pblock); assert(inserted.second); - const uint256& hash = inserted.first->first; - block = inserted.first->second; + block = *inserted.first; block->nTime = blockTime; - block->phashBlock = &hash; - confirm = {CWalletTx::Status::CONFIRMED, block->nHeight, hash, 0}; + confirm = {CWalletTx::Status::CONFIRMED, block->nHeight, block->GetBlockHash(), 0}; } // If transaction is already in map, to avoid inconsistencies, unconfirmation