stop using pointer to map key; it could be volatile

This commit is contained in:
Brannon King 2020-02-13 15:59:09 -07:00
parent ce70ebd2a4
commit 9d3800265e
10 changed files with 113 additions and 102 deletions

View file

@ -171,7 +171,7 @@ class CBlockIndex
{ {
public: public:
//! pointer to the hash of the block, if any. Memory is owned by this CBlockIndex //! pointer to the hash of the block, if any. Memory is owned by this CBlockIndex
const uint256* phashBlock; const uint256 hash;
//! pointer to the index of the predecessor of this block //! pointer to the index of the predecessor of this block
CBlockIndex* pprev; CBlockIndex* pprev;
@ -222,7 +222,6 @@ public:
void SetNull() void SetNull()
{ {
phashBlock = nullptr;
pprev = nullptr; pprev = nullptr;
pskip = nullptr; pskip = nullptr;
nHeight = 0; nHeight = 0;
@ -244,12 +243,12 @@ public:
nNonce = 0; nNonce = 0;
} }
CBlockIndex() CBlockIndex(const uint256& blockHash) : hash(blockHash)
{ {
SetNull(); SetNull();
} }
explicit CBlockIndex(const CBlockHeader& block) explicit CBlockIndex(const CBlockHeader& block) : hash(block.GetHash())
{ {
SetNull(); SetNull();
@ -295,7 +294,7 @@ public:
uint256 GetBlockHash() const uint256 GetBlockHash() const
{ {
return *phashBlock; return hash;
} }
uint256 GetBlockPoWHash() const uint256 GetBlockPoWHash() const

View file

@ -1351,9 +1351,9 @@ static UniValue getchaintips(const JSONRPCRequest& request)
for (const auto& item : g_chainstate.mapBlockIndex) for (const auto& item : g_chainstate.mapBlockIndex)
{ {
if (!chainActive.Contains(item.second)) { if (!chainActive.Contains(item)) {
setOrphans.insert(item.second); setOrphans.insert(item);
setPrevs.insert(item.second->pprev); setPrevs.insert(item->pprev);
} }
} }
@ -1373,7 +1373,7 @@ static UniValue getchaintips(const JSONRPCRequest& request)
{ {
UniValue obj(UniValue::VOBJ); UniValue obj(UniValue::VOBJ);
obj.pushKV("height", block->nHeight); obj.pushKV("height", block->nHeight);
obj.pushKV("hash", block->phashBlock->GetHex()); obj.pushKV("hash", block->hash.GetHex());
// not use ForkAt method because we need the previous one as well // not use ForkAt method because we need the previous one as well
const CBlockIndex *forkAt = block, *forkPrev = block; const CBlockIndex *forkAt = block, *forkPrev = block;
@ -1385,8 +1385,8 @@ static UniValue getchaintips(const JSONRPCRequest& request)
const int branchLen = block->nHeight - forkAt->nHeight; const int branchLen = block->nHeight - forkAt->nHeight;
obj.pushKV("branchlen", branchLen); obj.pushKV("branchlen", branchLen);
if (forkAt != forkPrev) { if (forkAt != forkPrev) {
obj.pushKV("branchhash", forkAt->phashBlock->GetHex()); obj.pushKV("branchhash", forkAt->hash.GetHex());
obj.pushKV("branchhashNext", forkPrev->phashBlock->GetHex()); obj.pushKV("branchhashNext", forkPrev->hash.GetHex());
} }
std::string status; std::string status;

View file

@ -1,7 +1,5 @@
#include <boost/test/unit_test.hpp> #include <boost/test/unit_test.hpp>
#include <stdlib.h>
#include <rpc/blockchain.h> #include <rpc/blockchain.h>
#include <test/test_bitcoin.h> #include <test/test_bitcoin.h>
#include <txdb.h> #include <txdb.h>
@ -16,7 +14,7 @@ static bool DoubleEquals(double a, double b, double epsilon)
static CBlockIndex* CreateBlockIndexWithNbits(uint32_t nbits) static CBlockIndex* CreateBlockIndexWithNbits(uint32_t nbits)
{ {
CBlockIndex* block_index = new CBlockIndex(); CBlockIndex* block_index = new CBlockIndex((uint256()));
block_index->nHeight = 46367; block_index->nHeight = 46367;
block_index->nTime = 1269211443; block_index->nTime = 1269211443;
block_index->nBits = nbits; block_index->nBits = nbits;

View file

@ -76,7 +76,7 @@ const unsigned int nonces[] = {
static CBlockIndex CreateBlockIndex(int nHeight) static CBlockIndex CreateBlockIndex(int nHeight)
{ {
CBlockIndex index; CBlockIndex index((uint256()));
index.nHeight = nHeight; index.nHeight = nHeight;
index.pprev = chainActive.Tip(); index.pprev = chainActive.Tip();
return index; return index;
@ -376,8 +376,7 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity)
// Create an actual 209999-long block chain (without valid blocks). // Create an actual 209999-long block chain (without valid blocks).
while (chainActive.Tip()->nHeight < 209999) { while (chainActive.Tip()->nHeight < 209999) {
CBlockIndex* prev = chainActive.Tip(); CBlockIndex* prev = chainActive.Tip();
CBlockIndex* next = new CBlockIndex(); CBlockIndex* next = new CBlockIndex(InsecureRand256());
next->phashBlock = new uint256(InsecureRand256());
next->hashClaimTrie = pblocktemplate->block.hashClaimTrie; next->hashClaimTrie = pblocktemplate->block.hashClaimTrie;
pcoinsTip->SetBestBlock(next->GetBlockHash()); pcoinsTip->SetBestBlock(next->GetBlockHash());
next->pprev = prev; next->pprev = prev;
@ -389,8 +388,7 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity)
// Extend to a 210000-long block chain. // Extend to a 210000-long block chain.
while (chainActive.Tip()->nHeight < 210000) { while (chainActive.Tip()->nHeight < 210000) {
CBlockIndex* prev = chainActive.Tip(); CBlockIndex* prev = chainActive.Tip();
CBlockIndex* next = new CBlockIndex(); CBlockIndex* next = new CBlockIndex(InsecureRand256());
next->phashBlock = new uint256(InsecureRand256());
next->hashClaimTrie = pblocktemplate->block.hashClaimTrie; next->hashClaimTrie = pblocktemplate->block.hashClaimTrie;
pcoinsTip->SetBestBlock(next->GetBlockHash()); pcoinsTip->SetBestBlock(next->GetBlockHash());
next->pprev = prev; next->pprev = prev;
@ -423,7 +421,6 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity)
CBlockIndex* del = chainActive.Tip(); CBlockIndex* del = chainActive.Tip();
chainActive.SetTip(del->pprev); chainActive.SetTip(del->pprev);
pcoinsTip->SetBestBlock(del->pprev->GetBlockHash()); pcoinsTip->SetBestBlock(del->pprev->GetBlockHash());
delete del->phashBlock;
delete del; delete del;
} }

View file

@ -18,7 +18,7 @@ BOOST_AUTO_TEST_CASE(get_next_work)
{ {
const auto chainParams = CreateChainParams(CBaseChainParams::MAIN); const auto chainParams = CreateChainParams(CBaseChainParams::MAIN);
int64_t nLastRetargetTime = 1261130161; // Block #30240 int64_t nLastRetargetTime = 1261130161; // Block #30240
CBlockIndex pindexLast; CBlockIndex pindexLast((uint256()));
pindexLast.nHeight = 32255; pindexLast.nHeight = 32255;
pindexLast.nTime = 1262152739; // Block #32255 pindexLast.nTime = 1262152739; // Block #32255
pindexLast.nBits = 0x1d00ffff; pindexLast.nBits = 0x1d00ffff;
@ -30,7 +30,7 @@ BOOST_AUTO_TEST_CASE(get_next_work_pow_limit)
{ {
const auto chainParams = CreateChainParams(CBaseChainParams::MAIN); const auto chainParams = CreateChainParams(CBaseChainParams::MAIN);
int64_t nLastRetargetTime = 1231006505; // Block #0 int64_t nLastRetargetTime = 1231006505; // Block #0
CBlockIndex pindexLast; CBlockIndex pindexLast((uint256()));
pindexLast.nHeight = 2015; pindexLast.nHeight = 2015;
pindexLast.nTime = 1233061996; // Block #2015 pindexLast.nTime = 1233061996; // Block #2015
pindexLast.nBits = 0x1d00ffff; pindexLast.nBits = 0x1d00ffff;
@ -42,7 +42,7 @@ BOOST_AUTO_TEST_CASE(get_next_work_lower_limit_actual)
{ {
const auto chainParams = CreateChainParams(CBaseChainParams::MAIN); const auto chainParams = CreateChainParams(CBaseChainParams::MAIN);
int64_t nLastRetargetTime = 1279008237; // Block #66528 int64_t nLastRetargetTime = 1279008237; // Block #66528
CBlockIndex pindexLast; CBlockIndex pindexLast((uint256()));
pindexLast.nHeight = 68543; pindexLast.nHeight = 68543;
pindexLast.nTime = 1279297671; // Block #68543 pindexLast.nTime = 1279297671; // Block #68543
pindexLast.nBits = 0x1c05a3f4; pindexLast.nBits = 0x1c05a3f4;
@ -54,7 +54,7 @@ BOOST_AUTO_TEST_CASE(get_next_work_upper_limit_actual)
{ {
const auto chainParams = CreateChainParams(CBaseChainParams::MAIN); const auto chainParams = CreateChainParams(CBaseChainParams::MAIN);
int64_t nLastRetargetTime = 1263163443; // NOTE: Not an actual block time int64_t nLastRetargetTime = 1263163443; // NOTE: Not an actual block time
CBlockIndex pindexLast; CBlockIndex pindexLast((uint256()));
pindexLast.nHeight = 46367; pindexLast.nHeight = 46367;
pindexLast.nTime = 1269211443; // Block #46367 pindexLast.nTime = 1269211443; // Block #46367
pindexLast.nBits = 0x1c387f6f; pindexLast.nBits = 0x1c387f6f;
@ -64,8 +64,10 @@ BOOST_AUTO_TEST_CASE(get_next_work_upper_limit_actual)
BOOST_AUTO_TEST_CASE(GetBlockProofEquivalentTime_test) BOOST_AUTO_TEST_CASE(GetBlockProofEquivalentTime_test)
{ {
const auto chainParams = CreateChainParams(CBaseChainParams::MAIN); const auto chainParams = CreateChainParams(CBaseChainParams::MAIN);
std::vector<CBlockIndex> blocks(10000); std::vector<CBlockIndex> blocks;
blocks.reserve(10000);
for (int i = 0; i < 10000; i++) { for (int i = 0; i < 10000; i++) {
blocks.emplace_back(uint256());
blocks[i].pprev = i ? &blocks[i - 1] : nullptr; blocks[i].pprev = i ? &blocks[i - 1] : nullptr;
blocks[i].nHeight = i; blocks[i].nHeight = i;
blocks[i].nTime = 1269211443 + i * chainParams->GetConsensus().nPowTargetSpacing; blocks[i].nTime = 1269211443 + i * chainParams->GetConsensus().nPowTargetSpacing;

View file

@ -16,9 +16,11 @@ BOOST_FIXTURE_TEST_SUITE(skiplist_tests, BasicTestingSetup)
BOOST_AUTO_TEST_CASE(skiplist_test) BOOST_AUTO_TEST_CASE(skiplist_test)
{ {
std::vector<CBlockIndex> vIndex(SKIPLIST_LENGTH); std::vector<CBlockIndex> vIndex;
vIndex.reserve(SKIPLIST_LENGTH);
for (int i=0; i<SKIPLIST_LENGTH; i++) { for (int i=0; i<SKIPLIST_LENGTH; i++) {
vIndex.emplace_back(uint256());
vIndex[i].nHeight = i; vIndex[i].nHeight = i;
vIndex[i].pprev = (i == 0) ? nullptr : &vIndex[i - 1]; vIndex[i].pprev = (i == 0) ? nullptr : &vIndex[i - 1];
vIndex[i].BuildSkip(); vIndex[i].BuildSkip();
@ -47,12 +49,13 @@ BOOST_AUTO_TEST_CASE(getlocator_test)
{ {
// Build a main chain 100000 blocks long. // Build a main chain 100000 blocks long.
std::vector<uint256> vHashMain(100000); std::vector<uint256> vHashMain(100000);
std::vector<CBlockIndex> vBlocksMain(100000); std::vector<CBlockIndex> vBlocksMain;
for (unsigned int i=0; i<vBlocksMain.size(); i++) { vBlocksMain.reserve(100000);
for (unsigned int i=0; i<vHashMain.size(); i++) {
vHashMain[i] = ArithToUint256(i); // Set the hash equal to the height, so we can quickly check the distances. vHashMain[i] = ArithToUint256(i); // Set the hash equal to the height, so we can quickly check the distances.
vBlocksMain.emplace_back(vHashMain[i]);
vBlocksMain[i].nHeight = i; vBlocksMain[i].nHeight = i;
vBlocksMain[i].pprev = i ? &vBlocksMain[i - 1] : nullptr; vBlocksMain[i].pprev = i ? &vBlocksMain[i - 1] : nullptr;
vBlocksMain[i].phashBlock = &vHashMain[i];
vBlocksMain[i].BuildSkip(); vBlocksMain[i].BuildSkip();
BOOST_CHECK_EQUAL((int)UintToArith256(vBlocksMain[i].GetBlockHash()).GetLow64(), vBlocksMain[i].nHeight); 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); BOOST_CHECK(vBlocksMain[i].pprev == nullptr || vBlocksMain[i].nHeight == vBlocksMain[i].pprev->nHeight + 1);
@ -60,12 +63,13 @@ BOOST_AUTO_TEST_CASE(getlocator_test)
// Build a branch that splits off at block 49999, 50000 blocks long. // Build a branch that splits off at block 49999, 50000 blocks long.
std::vector<uint256> vHashSide(50000); std::vector<uint256> vHashSide(50000);
std::vector<CBlockIndex> vBlocksSide(50000); std::vector<CBlockIndex> vBlocksSide;
for (unsigned int i=0; i<vBlocksSide.size(); i++) { vBlocksSide.reserve(50000);
for (unsigned int i=0; i<vHashSide.size(); i++) {
vHashSide[i] = ArithToUint256(i + 50000 + (arith_uint256(1) << 128)); // Add 1<<128 to the hashes, so GetLow64() still returns the height. vHashSide[i] = ArithToUint256(i + 50000 + (arith_uint256(1) << 128)); // Add 1<<128 to the hashes, so GetLow64() still returns the height.
vBlocksSide.emplace_back(vHashSide[i]);
vBlocksSide[i].nHeight = i + 50000; vBlocksSide[i].nHeight = i + 50000;
vBlocksSide[i].pprev = i ? &vBlocksSide[i - 1] : (vBlocksMain.data()+49999); vBlocksSide[i].pprev = i ? &vBlocksSide[i - 1] : (vBlocksMain.data()+49999);
vBlocksSide[i].phashBlock = &vHashSide[i];
vBlocksSide[i].BuildSkip(); vBlocksSide[i].BuildSkip();
BOOST_CHECK_EQUAL((int)UintToArith256(vBlocksSide[i].GetBlockHash()).GetLow64(), vBlocksSide[i].nHeight); 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); BOOST_CHECK(vBlocksSide[i].pprev == nullptr || vBlocksSide[i].nHeight == vBlocksSide[i].pprev->nHeight + 1);
@ -102,12 +106,13 @@ BOOST_AUTO_TEST_CASE(getlocator_test)
BOOST_AUTO_TEST_CASE(findearliestatleast_test) BOOST_AUTO_TEST_CASE(findearliestatleast_test)
{ {
std::vector<uint256> vHashMain(100000); std::vector<uint256> vHashMain(100000);
std::vector<CBlockIndex> vBlocksMain(100000); std::vector<CBlockIndex> vBlocksMain;
for (unsigned int i=0; i<vBlocksMain.size(); i++) { vBlocksMain.reserve(100000);
for (unsigned int i=0; i<vHashMain.size(); i++) {
vHashMain[i] = ArithToUint256(i); // Set the hash equal to the height vHashMain[i] = ArithToUint256(i); // Set the hash equal to the height
vBlocksMain.emplace_back(vHashMain[i]);
vBlocksMain[i].nHeight = i; vBlocksMain[i].nHeight = i;
vBlocksMain[i].pprev = i ? &vBlocksMain[i - 1] : nullptr; vBlocksMain[i].pprev = i ? &vBlocksMain[i - 1] : nullptr;
vBlocksMain[i].phashBlock = &vHashMain[i];
vBlocksMain[i].BuildSkip(); vBlocksMain[i].BuildSkip();
if (i < 10) { if (i < 10) {
vBlocksMain[i].nTime = i; vBlocksMain[i].nTime = i;
@ -148,7 +153,7 @@ BOOST_AUTO_TEST_CASE(findearliestatleast_edge_test)
std::list<CBlockIndex> blocks; std::list<CBlockIndex> blocks;
for (unsigned int timeMax : {100, 100, 100, 200, 200, 200, 300, 300, 300}) { for (unsigned int timeMax : {100, 100, 100, 200, 200, 200, 300, 300, 300}) {
CBlockIndex* prev = blocks.empty() ? nullptr : &blocks.back(); CBlockIndex* prev = blocks.empty() ? nullptr : &blocks.back();
blocks.emplace_back(); blocks.emplace_back(uint256());
blocks.back().nHeight = prev ? prev->nHeight + 1 : 0; blocks.back().nHeight = prev ? prev->nHeight + 1 : 0;
blocks.back().pprev = prev; blocks.back().pprev = prev;
blocks.back().BuildSkip(); blocks.back().BuildSkip();

View file

@ -76,7 +76,7 @@ public:
VersionBitsTester& Mine(unsigned int height, int32_t nTime, int32_t nVersion) { VersionBitsTester& Mine(unsigned int height, int32_t nTime, int32_t nVersion) {
while (vpblock.size() < height) { while (vpblock.size() < height) {
CBlockIndex* pindex = new CBlockIndex(); CBlockIndex* pindex = new CBlockIndex((uint256()));
pindex->nHeight = vpblock.size(); pindex->nHeight = vpblock.size();
pindex->pprev = vpblock.size() > 0 ? vpblock.back() : nullptr; pindex->pprev = vpblock.size() > 0 ? vpblock.back() : nullptr;
pindex->nTime = nTime; pindex->nTime = nTime;

View file

@ -220,7 +220,7 @@ bool CheckSequenceLocks(const CTransaction &tx, int flags, LockPoints* lp, bool
CBlockIndex* tip = chainActive.Tip(); CBlockIndex* tip = chainActive.Tip();
assert(tip != nullptr); assert(tip != nullptr);
CBlockIndex index; CBlockIndex index((uint256()));
index.pprev = tip; index.pprev = tip;
// CheckSequenceLocks() uses chainActive.Height()+1 to evaluate // CheckSequenceLocks() uses chainActive.Height()+1 to evaluate
// height based locks because when SequenceLocks() is called within // height based locks because when SequenceLocks() is called within
@ -1151,14 +1151,14 @@ static void CheckForkWarningConditions()
if (!GetfLargeWorkForkFound() && pindexBestForkBase) if (!GetfLargeWorkForkFound() && pindexBestForkBase)
{ {
std::string warning = std::string("'Warning: Large-work fork detected, forking after block ") + std::string warning = std::string("'Warning: Large-work fork detected, forking after block ") +
pindexBestForkBase->phashBlock->ToString() + std::string("'"); pindexBestForkBase->hash.ToString() + std::string("'");
AlertNotify(warning); AlertNotify(warning);
} }
if (pindexBestForkTip && pindexBestForkBase) 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__, 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(), pindexBestForkBase->nHeight, pindexBestForkBase->hash.ToString(),
pindexBestForkTip->nHeight, pindexBestForkTip->phashBlock->ToString()); pindexBestForkTip->nHeight, pindexBestForkTip->hash.ToString());
SetfLargeWorkForkFound(true); SetfLargeWorkForkFound(true);
} }
else else
@ -1713,8 +1713,8 @@ static unsigned int GetBlockScriptFlags(const CBlockIndex* pindex, const Consens
// mainnet and testnet), so for simplicity, always leave P2SH // mainnet and testnet), so for simplicity, always leave P2SH
// on except for the one violating block. // on except for the one violating block.
if (consensusparams.BIP16Exception.IsNull() || // no bip16 exception on this chain if (consensusparams.BIP16Exception.IsNull() || // no bip16 exception on this chain
pindex->phashBlock == nullptr || // this is a new candidate block, eg from TestBlockValidity() pindex->hash.IsNull() || // this is a new candidate block, eg from TestBlockValidity()
*pindex->phashBlock != consensusparams.BIP16Exception) // this block isn't the historical exception pindex->hash != consensusparams.BIP16Exception) // this block isn't the historical exception
{ {
flags |= SCRIPT_VERIFY_P2SH; flags |= SCRIPT_VERIFY_P2SH;
} }
@ -1766,7 +1766,7 @@ bool CChainState::ConnectBlock(const CBlock& block, CValidationState& state, CBl
{ {
AssertLockHeld(cs_main); AssertLockHeld(cs_main);
assert(pindex); assert(pindex);
assert(*pindex->phashBlock == block.GetHash()); assert(pindex->hash == block.GetHash());
int64_t nTimeStart = GetTimeMicros(); int64_t nTimeStart = GetTimeMicros();
// Check it again in case a previous version let a bad block in // Check it again in case a previous version let a bad block in
@ -1822,9 +1822,9 @@ bool CChainState::ConnectBlock(const CBlock& block, CValidationState& state, CBl
// relative to a piece of software is an objective fact these defaults can be easily reviewed. // 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 // 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. // effectively caching the result of part of the verification.
BlockMap::const_iterator it = mapBlockIndex.find(hashAssumeValid); auto it = mapBlockIndex.find(hashAssumeValid);
if (it != mapBlockIndex.end()) { if (it != mapBlockIndex.end()) {
if (it->second->GetAncestor(pindex->nHeight) == pindex && if ((*it)->GetAncestor(pindex->nHeight) == pindex &&
pindexBestHeader->GetAncestor(pindex->nHeight) == pindex && pindexBestHeader->GetAncestor(pindex->nHeight) == pindex &&
pindexBestHeader->nChainWork >= nMinimumChainWork) { pindexBestHeader->nChainWork >= nMinimumChainWork) {
// This block is a member of the assumed verified chain and an ancestor of the best header. // This block is a member of the assumed verified chain and an ancestor of the best header.
@ -2095,7 +2095,7 @@ bool CChainState::ConnectBlock(const CBlock& block, CValidationState& state, CBl
setDirtyBlockIndex.insert(pindex); setDirtyBlockIndex.insert(pindex);
} }
assert(pindex->phashBlock); assert(!pindex->hash.IsNull());
// add this block to the view's block chain // add this block to the view's block chain
view.SetBestBlock(pindex->GetBlockHash()); view.SetBestBlock(pindex->GetBlockHash());
@ -2892,12 +2892,12 @@ bool CChainState::InvalidateBlock(CValidationState& state, const CChainParams& c
// The resulting new best tip may not be in setBlockIndexCandidates anymore, so // The resulting new best tip may not be in setBlockIndexCandidates anymore, so
// add it again. // add it again.
BlockMap::iterator it = mapBlockIndex.begin(); auto it = mapBlockIndex.begin();
while (it != mapBlockIndex.end()) { while (it != mapBlockIndex.end()) {
if (it->second->IsValid(BLOCK_VALID_TRANSACTIONS) && it->second->nChainTx && !setBlockIndexCandidates.value_comp()(it->second, chainActive.Tip())) { if ((*it)->IsValid(BLOCK_VALID_TRANSACTIONS) && (*it)->nChainTx && !setBlockIndexCandidates.value_comp()(*it, chainActive.Tip())) {
setBlockIndexCandidates.insert(it->second); setBlockIndexCandidates.insert(*it);
} }
it++; ++it;
} }
InvalidChainFound(pindex); InvalidChainFound(pindex);
@ -2918,21 +2918,21 @@ void CChainState::ResetBlockFailureFlags(CBlockIndex *pindex) {
int nHeight = pindex->nHeight; int nHeight = pindex->nHeight;
// Remove the invalidity flag from this block and all its descendants. // Remove the invalidity flag from this block and all its descendants.
BlockMap::iterator it = mapBlockIndex.begin(); auto it = mapBlockIndex.begin();
while (it != mapBlockIndex.end()) { while (it != mapBlockIndex.end()) {
if (!it->second->IsValid() && it->second->GetAncestor(nHeight) == pindex) { if (!(*it)->IsValid() && (*it)->GetAncestor(nHeight) == pindex) {
it->second->nStatus &= ~BLOCK_FAILED_MASK; (*it)->nStatus &= ~BLOCK_FAILED_MASK;
setDirtyBlockIndex.insert(it->second); setDirtyBlockIndex.insert(*it);
if (it->second->IsValid(BLOCK_VALID_TRANSACTIONS) && it->second->nChainTx && setBlockIndexCandidates.value_comp()(chainActive.Tip(), it->second)) { if ((*it)->IsValid(BLOCK_VALID_TRANSACTIONS) && (*it)->nChainTx && setBlockIndexCandidates.value_comp()(chainActive.Tip(), *it)) {
setBlockIndexCandidates.insert(it->second); setBlockIndexCandidates.insert(*it);
} }
if (it->second == pindexBestInvalid) { if (*it == pindexBestInvalid) {
// Reset invalid block marker if it was pointing to one of those. // Reset invalid block marker if it was pointing to one of those.
pindexBestInvalid = nullptr; pindexBestInvalid = nullptr;
} }
m_failed_blocks.erase(it->second); m_failed_blocks.erase(*it);
} }
it++; ++it;
} }
// Remove the invalidity flag from all ancestors too. // Remove the invalidity flag from all ancestors too.
@ -2956,9 +2956,9 @@ CBlockIndex* CChainState::AddToBlockIndex(const CBlockHeader& block)
// Check for duplicate // Check for duplicate
uint256 hash = block.GetHash(); uint256 hash = block.GetHash();
BlockMap::iterator it = mapBlockIndex.find(hash); auto it = mapBlockIndex.find(hash);
if (it != mapBlockIndex.end()) if (it != mapBlockIndex.end())
return it->second; return *it;
// Construct new block index object // Construct new block index object
CBlockIndex* pindexNew = new CBlockIndex(block); CBlockIndex* pindexNew = new CBlockIndex(block);
@ -2966,12 +2966,11 @@ CBlockIndex* CChainState::AddToBlockIndex(const CBlockHeader& block)
// to avoid miners withholding blocks but broadcasting headers, to get a // to avoid miners withholding blocks but broadcasting headers, to get a
// competitive advantage. // competitive advantage.
pindexNew->nSequenceId = 0; pindexNew->nSequenceId = 0;
BlockMap::iterator mi = mapBlockIndex.insert(std::make_pair(hash, pindexNew)).first; mapBlockIndex.insert(pindexNew);
pindexNew->phashBlock = &((*mi).first);
BlockMap::iterator miPrev = mapBlockIndex.find(block.hashPrevBlock); BlockMap::iterator miPrev = mapBlockIndex.find(block.hashPrevBlock);
if (miPrev != mapBlockIndex.end()) if (miPrev != mapBlockIndex.end())
{ {
pindexNew->pprev = (*miPrev).second; pindexNew->pprev = *miPrev;
pindexNew->nHeight = pindexNew->pprev->nHeight + 1; pindexNew->nHeight = pindexNew->pprev->nHeight + 1;
pindexNew->BuildSkip(); pindexNew->BuildSkip();
} }
@ -3401,12 +3400,12 @@ bool CChainState::AcceptBlockHeader(const CBlockHeader& block, CValidationState&
AssertLockHeld(cs_main); AssertLockHeld(cs_main);
// Check for duplicate // Check for duplicate
uint256 hash = block.GetHash(); uint256 hash = block.GetHash();
BlockMap::iterator miSelf = mapBlockIndex.find(hash); auto 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;
if (ppindex) if (ppindex)
*ppindex = pindex; *ppindex = pindex;
if (pindex->nStatus & BLOCK_FAILED_MASK) if (pindex->nStatus & BLOCK_FAILED_MASK)
@ -3419,10 +3418,10 @@ bool CChainState::AcceptBlockHeader(const CBlockHeader& block, CValidationState&
// Get prev block index // Get prev block index
CBlockIndex* pindexPrev = nullptr; CBlockIndex* pindexPrev = nullptr;
BlockMap::iterator mi = mapBlockIndex.find(block.hashPrevBlock); auto mi = mapBlockIndex.find(block.hashPrevBlock);
if (mi == mapBlockIndex.end()) if (mi == mapBlockIndex.end())
return state.DoS(10, error("%s: prev block not found", __func__), 0, "prev-blk-not-found"); return state.DoS(10, error("%s: prev block not found", __func__), 0, "prev-blk-not-found");
pindexPrev = (*mi).second; pindexPrev = *mi;
if (pindexPrev->nStatus & BLOCK_FAILED_MASK) if (pindexPrev->nStatus & BLOCK_FAILED_MASK)
return state.DoS(100, error("%s: prev block invalid", __func__), REJECT_INVALID, "bad-prevblk"); return state.DoS(100, error("%s: prev block invalid", __func__), REJECT_INVALID, "bad-prevblk");
if (!ContextualCheckBlockHeader(block, state, chainparams, pindexPrev, GetAdjustedTime())) if (!ContextualCheckBlockHeader(block, state, chainparams, pindexPrev, GetAdjustedTime()))
@ -3617,11 +3616,9 @@ bool TestBlockValidity(CValidationState& state, const CChainParams& chainparams,
assert(pindexPrev && pindexPrev == chainActive.Tip()); assert(pindexPrev && pindexPrev == chainActive.Tip());
CCoinsViewCache viewNew(pcoinsTip.get()); CCoinsViewCache viewNew(pcoinsTip.get());
CClaimTrieCache trieCache(pclaimTrie); CClaimTrieCache trieCache(pclaimTrie);
uint256 block_hash(block.GetHash());
CBlockIndex indexDummy(block); CBlockIndex indexDummy(block);
indexDummy.pprev = pindexPrev; indexDummy.pprev = pindexPrev;
indexDummy.nHeight = pindexPrev->nHeight + 1; indexDummy.nHeight = pindexPrev->nHeight + 1;
indexDummy.phashBlock = &block_hash;
// NOTE: CheckBlockHeader is called by CheckBlock // NOTE: CheckBlockHeader is called by CheckBlock
if (!ContextualCheckBlockHeader(block, state, chainparams, pindexPrev, GetAdjustedTime())) if (!ContextualCheckBlockHeader(block, state, chainparams, pindexPrev, GetAdjustedTime()))
@ -3659,7 +3656,7 @@ void PruneOneBlockFile(const int fileNumber)
LOCK(cs_LastBlockFile); LOCK(cs_LastBlockFile);
for (const auto& entry : g_chainstate.mapBlockIndex) { for (const auto& entry : g_chainstate.mapBlockIndex) {
CBlockIndex* pindex = entry.second; CBlockIndex* pindex = entry;
if (pindex->nFile == fileNumber) { if (pindex->nFile == fileNumber) {
pindex->nStatus &= ~BLOCK_HAVE_DATA; pindex->nStatus &= ~BLOCK_HAVE_DATA;
pindex->nStatus &= ~BLOCK_HAVE_UNDO; pindex->nStatus &= ~BLOCK_HAVE_UNDO;
@ -3856,15 +3853,14 @@ CBlockIndex * CChainState::InsertBlockIndex(const uint256& hash)
// Return existing // Return existing
auto mi = mapBlockIndex.find(hash); auto mi = mapBlockIndex.find(hash);
if (mi != mapBlockIndex.end()) if (mi != mapBlockIndex.end())
return mi->second; return *mi;
if (hash.IsNull()) if (hash.IsNull())
return nullptr; return nullptr;
// Create new // Create new
CBlockIndex* pindexNew = new CBlockIndex(); CBlockIndex* pindexNew = new CBlockIndex(hash);
mi = mapBlockIndex.insert(std::make_pair(hash, pindexNew)).first; mapBlockIndex.insert(pindexNew);
pindexNew->phashBlock = &(mi->first);
return pindexNew; return pindexNew;
} }
@ -3879,9 +3875,8 @@ bool CChainState::LoadBlockIndex(const Consensus::Params& consensus_params, CBlo
// Calculate nChainWork // Calculate nChainWork
std::vector<std::pair<int, CBlockIndex*> > vSortedByHeight; std::vector<std::pair<int, CBlockIndex*> > vSortedByHeight;
vSortedByHeight.reserve(mapBlockIndex.size()); vSortedByHeight.reserve(mapBlockIndex.size());
for (const std::pair<const uint256, CBlockIndex*>& item : mapBlockIndex) for (const auto& pindex : mapBlockIndex)
{ {
CBlockIndex* pindex = item.second;
vSortedByHeight.push_back(std::make_pair(pindex->nHeight, pindex)); vSortedByHeight.push_back(std::make_pair(pindex->nHeight, pindex));
} }
sort(vSortedByHeight.begin(), vSortedByHeight.end()); sort(vSortedByHeight.begin(), vSortedByHeight.end());
@ -3946,9 +3941,8 @@ bool static LoadBlockIndexDB(const CChainParams& chainparams) EXCLUSIVE_LOCKS_RE
// Check presence of blk files // Check presence of blk files
LogPrintf("Checking all blk files are present...\n"); LogPrintf("Checking all blk files are present...\n");
std::set<int> setBlkDataFiles; std::set<int> setBlkDataFiles;
for (const std::pair<const uint256, CBlockIndex*>& item : g_chainstate.mapBlockIndex) for (const auto& pindex : g_chainstate.mapBlockIndex)
{ {
CBlockIndex* pindex = item.second;
if (pindex->nStatus & BLOCK_HAVE_DATA) { if (pindex->nStatus & BLOCK_HAVE_DATA) {
setBlkDataFiles.insert(pindex->nFile); setBlkDataFiles.insert(pindex->nFile);
} }
@ -4135,10 +4129,7 @@ bool CChainState::RollforwardBlock(const CBlockIndex* pindex, CCoinsViewCache& i
bool CChainState::ReplayBlocks(const CChainParams& params, CCoinsView* view) bool CChainState::ReplayBlocks(const CChainParams& params, CCoinsView* view)
{ {
LOCK(cs_main); AssertLockHeld(cs_main);
CCoinsViewCache cache(view);
CClaimTrieCache trieCache(pclaimTrie);
std::vector<uint256> hashHeads = view->GetHeadBlocks(); std::vector<uint256> hashHeads = view->GetHeadBlocks();
if (hashHeads.empty()) return true; // We're already in a consistent state. if (hashHeads.empty()) return true; // We're already in a consistent state.
@ -4151,20 +4142,25 @@ bool CChainState::ReplayBlocks(const CChainParams& params, CCoinsView* view)
const CBlockIndex* pindexNew; // New tip during the interrupted flush. const CBlockIndex* pindexNew; // New tip during the interrupted flush.
const CBlockIndex* pindexFork = nullptr; // Latest block common to both the old and the new tip. const CBlockIndex* pindexFork = nullptr; // Latest block common to both the old and the new tip.
if (mapBlockIndex.count(hashHeads[0]) == 0) { auto it = mapBlockIndex.find(hashHeads[0]);
if (it == mapBlockIndex.end()) {
return error("ReplayBlocks(): reorganization to unknown block requested"); return error("ReplayBlocks(): reorganization to unknown block requested");
} }
pindexNew = mapBlockIndex[hashHeads[0]]; pindexNew = *it;
if (!hashHeads[1].IsNull()) { // The old tip is allowed to be 0, indicating it's the first flush. if (!hashHeads[1].IsNull()) { // The old tip is allowed to be 0, indicating it's the first flush.
if (mapBlockIndex.count(hashHeads[1]) == 0) { it = mapBlockIndex.find(hashHeads[1]);
if (it == mapBlockIndex.end()) {
return error("ReplayBlocks(): reorganization from unknown block requested"); return error("ReplayBlocks(): reorganization from unknown block requested");
} }
pindexOld = mapBlockIndex[hashHeads[1]]; pindexOld = *it;
pindexFork = LastCommonAncestor(pindexOld, pindexNew); pindexFork = LastCommonAncestor(pindexOld, pindexNew);
assert(pindexFork != nullptr); assert(pindexFork != nullptr);
} }
CCoinsViewCache cache(view);
CClaimTrieCache trieCache(pclaimTrie);
// Rollback along the old branch. // Rollback along the old branch.
while (pindexOld != pindexFork) { while (pindexOld != pindexFork) {
if (pindexOld->nHeight > 0) { // Never disconnect the genesis block. if (pindexOld->nHeight > 0) { // Never disconnect the genesis block.
@ -4246,8 +4242,7 @@ bool CChainState::RewindBlockIndex(const CChainParams& params)
// Reduce validity flag and have-data flags. // Reduce validity flag and have-data flags.
// We do this after actual disconnecting, otherwise we'll end up writing the lack of data // We do this after actual disconnecting, otherwise we'll end up writing the lack of data
// to disk before writing the chainstate, resulting in a failure to continue if interrupted. // to disk before writing the chainstate, resulting in a failure to continue if interrupted.
for (const auto& entry : mapBlockIndex) { for (const auto& pindexIter : mapBlockIndex) {
CBlockIndex* pindexIter = entry.second;
// Note: If we encounter an insufficiently validated block that // Note: If we encounter an insufficiently validated block that
// is on chainActive, it must be because we are a pruning node, and // is on chainActive, it must be because we are a pruning node, and
@ -4340,8 +4335,8 @@ void UnloadBlockIndex()
warningcache[b].clear(); warningcache[b].clear();
} }
for (BlockMap::value_type& entry : g_chainstate.mapBlockIndex) { for (auto& entry : g_chainstate.mapBlockIndex) {
delete entry.second; delete entry;
} }
g_chainstate.mapBlockIndex.clear(); g_chainstate.mapBlockIndex.clear();
fHavePruned = false; fHavePruned = false;
@ -4389,7 +4384,7 @@ bool CChainState::LoadGenesisBlock(const CChainParams& chainparams)
// mapBlockIndex. Note that we can't use chainActive here, since it is // mapBlockIndex. Note that we can't use chainActive here, since it is
// set based on the coins db, not the block index db, which is the only // set based on the coins db, not the block index db, which is the only
// thing loaded at this point. // thing loaded at this point.
if (mapBlockIndex.count(chainparams.GenesisBlock().GetHash())) if (mapBlockIndex.find(chainparams.GenesisBlock().GetHash()) != mapBlockIndex.end())
return true; return true;
try { try {
@ -4552,7 +4547,7 @@ void CChainState::CheckBlockIndex(const Consensus::Params& consensusParams)
// Build forward-pointing map of the entire block tree. // Build forward-pointing map of the entire block tree.
std::multimap<CBlockIndex*,CBlockIndex*> forward; std::multimap<CBlockIndex*,CBlockIndex*> forward;
for (auto& entry : mapBlockIndex) { for (auto& entry : mapBlockIndex) {
forward.insert(std::make_pair(entry.second->pprev, entry.second)); forward.insert(std::make_pair(entry->pprev, entry));
} }
assert(forward.size() == mapBlockIndex.size()); assert(forward.size() == mapBlockIndex.size());
@ -4898,7 +4893,7 @@ double GuessVerificationProgress(const ChainTxData& data, const CBlockIndex *pin
CBlockIndex *LookupBlockIndex(const uint256 &hash) { CBlockIndex *LookupBlockIndex(const uint256 &hash) {
AssertLockHeld(cs_main); AssertLockHeld(cs_main);
auto it = g_chainstate.mapBlockIndex.find(hash); auto it = g_chainstate.mapBlockIndex.find(hash);
return it == g_chainstate.mapBlockIndex.end() ? nullptr : it->second; return it == g_chainstate.mapBlockIndex.end() ? nullptr : *it;
} }
class CMainCleanup class CMainCleanup
@ -4909,7 +4904,7 @@ public:
// block headers // block headers
auto it1 = g_chainstate.mapBlockIndex.begin(); auto it1 = g_chainstate.mapBlockIndex.begin();
for (; it1 != g_chainstate.mapBlockIndex.end(); ++it1) for (; it1 != g_chainstate.mapBlockIndex.end(); ++it1)
delete (*it1).second; delete *it1;
g_chainstate.mapBlockIndex.clear(); g_chainstate.mapBlockIndex.clear();
} }
} instance_of_cmaincleanup; } instance_of_cmaincleanup;

View file

@ -144,7 +144,25 @@ extern CCriticalSection cs_main;
extern CBlockPolicyEstimator feeEstimator; extern CBlockPolicyEstimator feeEstimator;
extern CTxMemPool mempool; extern CTxMemPool mempool;
extern std::atomic_bool g_is_mempool_loaded; extern std::atomic_bool g_is_mempool_loaded;
typedef std::map<uint256, CBlockIndex*> BlockMap;
struct BlockIndexPointerCompare {
inline bool operator() (const CBlockIndex* lhs, const CBlockIndex* rhs) const {
return lhs->hash < rhs->hash;
}
};
struct BlockMap : public std::set<CBlockIndex*, BlockIndexPointerCompare> {
inline iterator find(const uint256& blockHash) {
CBlockIndex temp(blockHash);
return std::set<CBlockIndex*, BlockIndexPointerCompare>::find(&temp);
}
inline const_iterator find(const uint256& blockHash) const {
CBlockIndex temp(blockHash);
return std::set<CBlockIndex*, BlockIndexPointerCompare>::find(&temp);
}
};
extern uint64_t nLastBlockTx; extern uint64_t nLastBlockTx;
extern uint64_t nLastBlockWeight; extern uint64_t nLastBlockWeight;
extern const std::string strMessageMagic; extern const std::string strMessageMagic;

View file

@ -207,12 +207,9 @@ static int64_t AddTx(CWallet& wallet, uint32_t lockTime, int64_t mockTime, int64
CBlockIndex* block = nullptr; CBlockIndex* block = nullptr;
if (blockTime > 0) { if (blockTime > 0) {
LOCK(cs_main); LOCK(cs_main);
auto inserted = g_chainstate.mapBlockIndex.emplace(GetRandHash(), new CBlockIndex); auto inserted = g_chainstate.mapBlockIndex.insert(new CBlockIndex(GetRandHash()));
assert(inserted.second); block = *inserted.first;
const uint256& hash = inserted.first->first;
block = inserted.first->second;
block->nTime = blockTime; block->nTime = blockTime;
block->phashBlock = &hash;
} }
CWalletTx wtx(&wallet, MakeTransactionRef(tx)); CWalletTx wtx(&wallet, MakeTransactionRef(tx));