Merge bitcoin/bitcoin#24909: refactor: Move and rename pindexBestHeader, fHavePruned

f0a2fb3c5d scripted-diff: Rename pindexBestHeader, fHavePruned (Carl Dong)
a401402125 Clear fHavePruned in BlockManager::Unload() (Carl Dong)
3308ecd3fc move-mostly: Make fHavePruned a BlockMan member (Carl Dong)
c96524113c Clear pindexBestHeader in ChainstateManager::Unload() (Carl Dong)
73eedaaacc style-only: Miscellaneous whitespace changes (Carl Dong)
0d567daf23 move-mostly: Make pindexBestHeader a ChainMan member (Carl Dong)
5d670173a3 validation: Load pindexBestHeader in ChainMan (Carl Dong)

Pull request description:

  Split off from #22564 per Marco's suggestion: https://github.com/bitcoin/bitcoin/pull/22564#issuecomment-1100011503

  This is basically the move-mostly parts of #22564. The overall intent is to move mutable globals manually reset by `::UnloadBlockIndex` into appropriate structs such that they are cleared at the appropriate times. Please read #22564's description for more rationale.

  In summary , this PR moves:
  1. `pindexBestHeader` -> `ChainstateManager::m_best_header`
  2. `fHavePruned` -> `BlockManager::m_have_pruned`

ACKs for top commit:
  ajtowns:
    ACK f0a2fb3c5d -- code review only
  MarcoFalke:
    kirby ACK f0a2fb3c5d 😋

Tree-SHA512: 8d161701af81af1ff42da1b22a6bef2f8626e8642146bc9c3b27f3a7cd24f4d691910a2392b188ae058fec0611a17304dd73f60da695f53832d327f73d2fc963
This commit is contained in:
MarcoFalke 2022-04-20 12:13:18 +02:00
commit dbdc83ae01
No known key found for this signature in database
GPG key ID: CE2B75697E69A548
12 changed files with 100 additions and 99 deletions

View file

@ -40,7 +40,7 @@ static void BlockToJsonVerbose(benchmark::Bench& bench)
{ {
TestBlockAndIndex data; TestBlockAndIndex data;
bench.run([&] { bench.run([&] {
auto univalue = blockToJSON(data.block, &data.blockindex, &data.blockindex, TxVerbosity::SHOW_DETAILS_AND_PREVOUT); auto univalue = blockToJSON(data.testing_setup->m_node.chainman->m_blockman, data.block, &data.blockindex, &data.blockindex, TxVerbosity::SHOW_DETAILS_AND_PREVOUT);
ankerl::nanobench::doNotOptimizeAway(univalue); ankerl::nanobench::doNotOptimizeAway(univalue);
}); });
} }
@ -50,7 +50,7 @@ BENCHMARK(BlockToJsonVerbose);
static void BlockToJsonVerboseWrite(benchmark::Bench& bench) static void BlockToJsonVerboseWrite(benchmark::Bench& bench)
{ {
TestBlockAndIndex data; TestBlockAndIndex data;
auto univalue = blockToJSON(data.block, &data.blockindex, &data.blockindex, TxVerbosity::SHOW_DETAILS_AND_PREVOUT); auto univalue = blockToJSON(data.testing_setup->m_node.chainman->m_blockman, data.block, &data.blockindex, &data.blockindex, TxVerbosity::SHOW_DETAILS_AND_PREVOUT);
bench.run([&] { bench.run([&] {
auto str = univalue.write(); auto str = univalue.write();
ankerl::nanobench::doNotOptimizeAway(str); ankerl::nanobench::doNotOptimizeAway(str);

View file

@ -109,7 +109,6 @@ using node::LoadChainstate;
using node::NodeContext; using node::NodeContext;
using node::ThreadImport; using node::ThreadImport;
using node::VerifyLoadedChainstate; using node::VerifyLoadedChainstate;
using node::fHavePruned;
using node::fPruneMode; using node::fPruneMode;
using node::fReindex; using node::fReindex;
using node::nPruneTarget; using node::nPruneTarget;
@ -1481,7 +1480,7 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info)
try { try {
uiInterface.InitMessage(_("Verifying blocks…").translated); uiInterface.InitMessage(_("Verifying blocks…").translated);
auto check_blocks = args.GetIntArg("-checkblocks", DEFAULT_CHECKBLOCKS); auto check_blocks = args.GetIntArg("-checkblocks", DEFAULT_CHECKBLOCKS);
if (fHavePruned && check_blocks > MIN_BLOCKS_TO_KEEP) { if (chainman.m_blockman.m_have_pruned && check_blocks > MIN_BLOCKS_TO_KEEP) {
LogPrintf("Prune: pruned datadir may not have more than %d blocks; only checking available blocks\n", LogPrintf("Prune: pruned datadir may not have more than %d blocks; only checking available blocks\n",
MIN_BLOCKS_TO_KEEP); MIN_BLOCKS_TO_KEEP);
} }
@ -1665,9 +1664,9 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info)
tip_info->block_time = chainman.ActiveChain().Tip() ? chainman.ActiveChain().Tip()->GetBlockTime() : Params().GenesisBlock().GetBlockTime(); tip_info->block_time = chainman.ActiveChain().Tip() ? chainman.ActiveChain().Tip()->GetBlockTime() : Params().GenesisBlock().GetBlockTime();
tip_info->verification_progress = GuessVerificationProgress(Params().TxData(), chainman.ActiveChain().Tip()); tip_info->verification_progress = GuessVerificationProgress(Params().TxData(), chainman.ActiveChain().Tip());
} }
if (tip_info && ::pindexBestHeader) { if (tip_info && chainman.m_best_header) {
tip_info->header_height = ::pindexBestHeader->nHeight; tip_info->header_height = chainman.m_best_header->nHeight;
tip_info->header_time = ::pindexBestHeader->GetBlockTime(); tip_info->header_time = chainman.m_best_header->GetBlockTime();
} }
} }
LogPrintf("nBestHeight = %d\n", chain_active_height); LogPrintf("nBestHeight = %d\n", chain_active_height);

View file

@ -1499,9 +1499,9 @@ bool PeerManagerImpl::BlockRequestAllowed(const CBlockIndex* pindex)
{ {
AssertLockHeld(cs_main); AssertLockHeld(cs_main);
if (m_chainman.ActiveChain().Contains(pindex)) return true; if (m_chainman.ActiveChain().Contains(pindex)) return true;
return pindex->IsValid(BLOCK_VALID_SCRIPTS) && (pindexBestHeader != nullptr) && return pindex->IsValid(BLOCK_VALID_SCRIPTS) && (m_chainman.m_best_header != nullptr) &&
(pindexBestHeader->GetBlockTime() - pindex->GetBlockTime() < STALE_RELAY_AGE_LIMIT) && (m_chainman.m_best_header->GetBlockTime() - pindex->GetBlockTime() < STALE_RELAY_AGE_LIMIT) &&
(GetBlockProofEquivalentTime(*pindexBestHeader, *pindex, *pindexBestHeader, m_chainparams.GetConsensus()) < STALE_RELAY_AGE_LIMIT); (GetBlockProofEquivalentTime(*m_chainman.m_best_header, *pindex, *m_chainman.m_best_header, m_chainparams.GetConsensus()) < STALE_RELAY_AGE_LIMIT);
} }
std::optional<std::string> PeerManagerImpl::FetchBlock(NodeId peer_id, const CBlockIndex& block_index) std::optional<std::string> PeerManagerImpl::FetchBlock(NodeId peer_id, const CBlockIndex& block_index)
@ -1896,7 +1896,7 @@ void PeerManagerImpl::ProcessGetBlockData(CNode& pfrom, Peer& peer, const CInv&
const CNetMsgMaker msgMaker(pfrom.GetCommonVersion()); const CNetMsgMaker msgMaker(pfrom.GetCommonVersion());
// 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
if (m_connman.OutboundTargetReached(true) && if (m_connman.OutboundTargetReached(true) &&
(((pindexBestHeader != nullptr) && (pindexBestHeader->GetBlockTime() - pindex->GetBlockTime() > HISTORICAL_BLOCK_AGE)) || inv.IsMsgFilteredBlk()) && (((m_chainman.m_best_header != nullptr) && (m_chainman.m_best_header->GetBlockTime() - pindex->GetBlockTime() > HISTORICAL_BLOCK_AGE)) || inv.IsMsgFilteredBlk()) &&
!pfrom.HasPermission(NetPermissionFlags::Download) // nodes with the download permission may exceed target !pfrom.HasPermission(NetPermissionFlags::Download) // nodes with the download permission may exceed target
) { ) {
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());
@ -2173,12 +2173,12 @@ void PeerManagerImpl::ProcessHeadersMessage(CNode& pfrom, const Peer& peer,
// nUnconnectingHeaders gets reset back to 0. // nUnconnectingHeaders gets reset back to 0.
if (!m_chainman.m_blockman.LookupBlockIndex(headers[0].hashPrevBlock) && nCount < MAX_BLOCKS_TO_ANNOUNCE) { if (!m_chainman.m_blockman.LookupBlockIndex(headers[0].hashPrevBlock) && nCount < MAX_BLOCKS_TO_ANNOUNCE) {
nodestate->nUnconnectingHeaders++; nodestate->nUnconnectingHeaders++;
m_connman.PushMessage(&pfrom, msgMaker.Make(NetMsgType::GETHEADERS, m_chainman.ActiveChain().GetLocator(pindexBestHeader), uint256())); m_connman.PushMessage(&pfrom, msgMaker.Make(NetMsgType::GETHEADERS, m_chainman.ActiveChain().GetLocator(m_chainman.m_best_header), 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",
headers[0].GetHash().ToString(), headers[0].GetHash().ToString(),
headers[0].hashPrevBlock.ToString(), headers[0].hashPrevBlock.ToString(),
pindexBestHeader->nHeight, m_chainman.m_best_header->nHeight,
pfrom.GetId(), nodestate->nUnconnectingHeaders); pfrom.GetId(), nodestate->nUnconnectingHeaders);
// Set hashLastUnknownBlock for this peer, so that if we // Set hashLastUnknownBlock for this peer, so that if we
// eventually get the headers - even from a different peer - // eventually get the headers - even from a different peer -
// we can use this peer to download. // we can use this peer to download.
@ -2235,7 +2235,7 @@ void PeerManagerImpl::ProcessHeadersMessage(CNode& pfrom, const Peer& peer,
if (nCount == MAX_HEADERS_RESULTS) { if (nCount == MAX_HEADERS_RESULTS) {
// Headers message had its maximum size; the peer may have more headers. // Headers message had its maximum size; the peer may have more headers.
// TODO: optimize: if pindexLast is an ancestor of m_chainman.ActiveChain().Tip or pindexBestHeader, continue // TODO: optimize: if pindexLast is an ancestor of m_chainman.ActiveChain().Tip or m_chainman.m_best_header, continue
// from there instead. // from there instead.
LogPrint(BCLog::NET, "more getheaders (%d) to end to peer=%d (startheight:%d)\n", LogPrint(BCLog::NET, "more getheaders (%d) to end to peer=%d (startheight:%d)\n",
pindexLast->nHeight, pfrom.GetId(), peer.m_starting_height); pindexLast->nHeight, pfrom.GetId(), peer.m_starting_height);
@ -3102,8 +3102,8 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type,
} }
if (best_block != nullptr) { if (best_block != nullptr) {
m_connman.PushMessage(&pfrom, msgMaker.Make(NetMsgType::GETHEADERS, m_chainman.ActiveChain().GetLocator(pindexBestHeader), *best_block)); m_connman.PushMessage(&pfrom, msgMaker.Make(NetMsgType::GETHEADERS, m_chainman.ActiveChain().GetLocator(m_chainman.m_best_header), *best_block));
LogPrint(BCLog::NET, "getheaders (%d) %s to peer=%d\n", pindexBestHeader->nHeight, best_block->ToString(), pfrom.GetId()); LogPrint(BCLog::NET, "getheaders (%d) %s to peer=%d\n", m_chainman.m_best_header->nHeight, best_block->ToString(), pfrom.GetId());
} }
return; return;
@ -3549,7 +3549,7 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type,
if (!m_chainman.m_blockman.LookupBlockIndex(cmpctblock.header.hashPrevBlock)) { if (!m_chainman.m_blockman.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 (!m_chainman.ActiveChainstate().IsInitialBlockDownload()) if (!m_chainman.ActiveChainstate().IsInitialBlockDownload())
m_connman.PushMessage(&pfrom, msgMaker.Make(NetMsgType::GETHEADERS, m_chainman.ActiveChain().GetLocator(pindexBestHeader), uint256())); m_connman.PushMessage(&pfrom, msgMaker.Make(NetMsgType::GETHEADERS, m_chainman.ActiveChain().GetLocator(m_chainman.m_best_header), uint256()));
return; return;
} }
@ -4670,28 +4670,29 @@ bool PeerManagerImpl::SendMessages(CNode* pto)
CNodeState &state = *State(pto->GetId()); CNodeState &state = *State(pto->GetId());
// Start block sync // Start block sync
if (pindexBestHeader == nullptr) if (m_chainman.m_best_header == nullptr) {
pindexBestHeader = m_chainman.ActiveChain().Tip(); m_chainman.m_best_header = m_chainman.ActiveChain().Tip();
}
bool fFetch = state.fPreferredDownload || (nPreferredDownload == 0 && !pto->fClient && !pto->IsAddrFetchConn()); // Download if this is a nice peer, or we have no nice peers and this one might do. bool fFetch = state.fPreferredDownload || (nPreferredDownload == 0 && !pto->fClient && !pto->IsAddrFetchConn()); // Download if this is a nice peer, or we have no nice peers and this one might do.
if (!state.fSyncStarted && !pto->fClient && !fImporting && !fReindex) { if (!state.fSyncStarted && !pto->fClient && !fImporting && !fReindex) {
// Only actively request headers from a single peer, unless we're close to today. // Only actively request headers from a single peer, unless we're close to today.
if ((nSyncStarted == 0 && fFetch) || pindexBestHeader->GetBlockTime() > GetAdjustedTime() - 24 * 60 * 60) { if ((nSyncStarted == 0 && fFetch) || m_chainman.m_best_header->GetBlockTime() > GetAdjustedTime() - 24 * 60 * 60) {
state.fSyncStarted = true; state.fSyncStarted = true;
state.m_headers_sync_timeout = current_time + HEADERS_DOWNLOAD_TIMEOUT_BASE + state.m_headers_sync_timeout = current_time + HEADERS_DOWNLOAD_TIMEOUT_BASE +
( (
// Convert HEADERS_DOWNLOAD_TIMEOUT_PER_HEADER to microseconds before scaling // Convert HEADERS_DOWNLOAD_TIMEOUT_PER_HEADER to microseconds before scaling
// to maintain precision // to maintain precision
std::chrono::microseconds{HEADERS_DOWNLOAD_TIMEOUT_PER_HEADER} * std::chrono::microseconds{HEADERS_DOWNLOAD_TIMEOUT_PER_HEADER} *
(GetAdjustedTime() - pindexBestHeader->GetBlockTime()) / consensusParams.nPowTargetSpacing (GetAdjustedTime() - m_chainman.m_best_header->GetBlockTime()) / consensusParams.nPowTargetSpacing
); );
nSyncStarted++; nSyncStarted++;
const CBlockIndex *pindexStart = pindexBestHeader; const CBlockIndex* pindexStart = m_chainman.m_best_header;
/* If possible, start at the block preceding the currently /* If possible, start at the block preceding the currently
best known header. This ensures that we always get a best known header. This ensures that we always get a
non-empty list of headers back as long as the peer non-empty list of headers back as long as the peer
is up-to-date. With a non-empty response, we can initialise is up-to-date. With a non-empty response, we can initialise
the peer's known best block. This wouldn't be possible the peer's known best block. This wouldn't be possible
if we requested starting at pindexBestHeader and if we requested starting at m_chainman.m_best_header and
got back an empty response. */ got back an empty response. */
if (pindexStart->pprev) if (pindexStart->pprev)
pindexStart = pindexStart->pprev; pindexStart = pindexStart->pprev;
@ -5016,7 +5017,7 @@ bool PeerManagerImpl::SendMessages(CNode* pto)
// Check for headers sync timeouts // Check for headers sync timeouts
if (state.fSyncStarted && state.m_headers_sync_timeout < std::chrono::microseconds::max()) { if (state.fSyncStarted && state.m_headers_sync_timeout < std::chrono::microseconds::max()) {
// Detect whether this is a stalling initial-headers-sync peer // Detect whether this is a stalling initial-headers-sync peer
if (pindexBestHeader->GetBlockTime() <= GetAdjustedTime() - 24 * 60 * 60) { if (m_chainman.m_best_header->GetBlockTime() <= GetAdjustedTime() - 24 * 60 * 60) {
if (current_time > state.m_headers_sync_timeout && nSyncStarted == 1 && (nPreferredDownload - state.fPreferredDownload >= 1)) { if (current_time > state.m_headers_sync_timeout && nSyncStarted == 1 && (nPreferredDownload - state.fPreferredDownload >= 1)) {
// Disconnect a peer (without NetPermissionFlags::NoBan permission) if it is our only sync peer, // Disconnect a peer (without NetPermissionFlags::NoBan permission) if it is our only sync peer,
// and we have others we could be using instead. // and we have others we could be using instead.

View file

@ -24,7 +24,6 @@
namespace node { namespace node {
std::atomic_bool fImporting(false); std::atomic_bool fImporting(false);
std::atomic_bool fReindex(false); std::atomic_bool fReindex(false);
bool fHavePruned = false;
bool fPruneMode = false; bool fPruneMode = false;
uint64_t nPruneTarget = 0; uint64_t nPruneTarget = 0;
@ -81,7 +80,7 @@ const CBlockIndex* BlockManager::LookupBlockIndex(const uint256& hash) const
return it == m_block_index.end() ? nullptr : &it->second; return it == m_block_index.end() ? nullptr : &it->second;
} }
CBlockIndex* BlockManager::AddToBlockIndex(const CBlockHeader& block) CBlockIndex* BlockManager::AddToBlockIndex(const CBlockHeader& block, CBlockIndex*& best_header)
{ {
AssertLockHeld(cs_main); AssertLockHeld(cs_main);
@ -106,8 +105,9 @@ CBlockIndex* BlockManager::AddToBlockIndex(const CBlockHeader& block)
pindexNew->nTimeMax = (pindexNew->pprev ? std::max(pindexNew->pprev->nTimeMax, pindexNew->nTime) : pindexNew->nTime); pindexNew->nTimeMax = (pindexNew->pprev ? std::max(pindexNew->pprev->nTimeMax, pindexNew->nTime) : pindexNew->nTime);
pindexNew->nChainWork = (pindexNew->pprev ? pindexNew->pprev->nChainWork : 0) + GetBlockProof(*pindexNew); pindexNew->nChainWork = (pindexNew->pprev ? pindexNew->pprev->nChainWork : 0) + GetBlockProof(*pindexNew);
pindexNew->RaiseValidity(BLOCK_VALID_TREE); pindexNew->RaiseValidity(BLOCK_VALID_TREE);
if (pindexBestHeader == nullptr || pindexBestHeader->nChainWork < pindexNew->nChainWork) if (best_header == nullptr || best_header->nChainWork < pindexNew->nChainWork) {
pindexBestHeader = pindexNew; best_header = pindexNew;
}
m_dirty_blockindex.insert(pindexNew); m_dirty_blockindex.insert(pindexNew);
@ -285,8 +285,6 @@ bool BlockManager::LoadBlockIndex(const Consensus::Params& consensus_params)
if (pindex->pprev) { if (pindex->pprev) {
pindex->BuildSkip(); pindex->BuildSkip();
} }
if (pindex->IsValid(BLOCK_VALID_TREE) && (pindexBestHeader == nullptr || CBlockIndexWorkComparator()(pindexBestHeader, pindex)))
pindexBestHeader = pindex;
} }
return true; return true;
@ -302,6 +300,8 @@ void BlockManager::Unload()
m_last_blockfile = 0; m_last_blockfile = 0;
m_dirty_blockindex.clear(); m_dirty_blockindex.clear();
m_dirty_fileinfo.clear(); m_dirty_fileinfo.clear();
m_have_pruned = false;
} }
bool BlockManager::WriteBlockIndexDB() bool BlockManager::WriteBlockIndexDB()
@ -364,8 +364,8 @@ bool BlockManager::LoadBlockIndexDB()
} }
// Check whether we have ever pruned block & undo files // Check whether we have ever pruned block & undo files
m_block_tree_db->ReadFlag("prunedblockfiles", fHavePruned); m_block_tree_db->ReadFlag("prunedblockfiles", m_have_pruned);
if (fHavePruned) { if (m_have_pruned) {
LogPrintf("LoadBlockIndexDB(): Block files have previously been pruned\n"); LogPrintf("LoadBlockIndexDB(): Block files have previously been pruned\n");
} }
@ -391,10 +391,10 @@ const CBlockIndex* BlockManager::GetLastCheckpoint(const CCheckpointData& data)
return nullptr; return nullptr;
} }
bool IsBlockPruned(const CBlockIndex* pblockindex) bool BlockManager::IsBlockPruned(const CBlockIndex* pblockindex)
{ {
AssertLockHeld(::cs_main); AssertLockHeld(::cs_main);
return (fHavePruned && !(pblockindex->nStatus & BLOCK_HAVE_DATA) && pblockindex->nTx > 0); return (m_have_pruned && !(pblockindex->nStatus & BLOCK_HAVE_DATA) && pblockindex->nTx > 0);
} }
// If we're using -prune with -reindex, then delete block files that will be ignored by the // If we're using -prune with -reindex, then delete block files that will be ignored by the

View file

@ -45,8 +45,6 @@ static const unsigned int MAX_BLOCKFILE_SIZE = 0x8000000; // 128 MiB
extern std::atomic_bool fImporting; extern std::atomic_bool fImporting;
extern std::atomic_bool fReindex; extern std::atomic_bool fReindex;
/** Pruning-related variables and constants */ /** Pruning-related variables and constants */
/** True if any block files have ever been pruned. */
extern bool fHavePruned;
/** True if we're running in -prune mode. */ /** True if we're running in -prune mode. */
extern bool fPruneMode; extern bool fPruneMode;
/** Number of MiB of block files that we're trying to stay below. */ /** Number of MiB of block files that we're trying to stay below. */
@ -147,7 +145,7 @@ public:
/** Clear all data members. */ /** Clear all data members. */
void Unload() EXCLUSIVE_LOCKS_REQUIRED(cs_main); void Unload() EXCLUSIVE_LOCKS_REQUIRED(cs_main);
CBlockIndex* AddToBlockIndex(const CBlockHeader& block) EXCLUSIVE_LOCKS_REQUIRED(cs_main); CBlockIndex* AddToBlockIndex(const CBlockHeader& block, CBlockIndex*& best_header) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
/** Create a new block index entry for a given block hash */ /** Create a new block index entry for a given block hash */
CBlockIndex* InsertBlockIndex(const uint256& hash) EXCLUSIVE_LOCKS_REQUIRED(cs_main); CBlockIndex* InsertBlockIndex(const uint256& hash) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
@ -171,15 +169,18 @@ public:
//! Returns last CBlockIndex* that is a checkpoint //! Returns last CBlockIndex* that is a checkpoint
const CBlockIndex* GetLastCheckpoint(const CCheckpointData& data) EXCLUSIVE_LOCKS_REQUIRED(cs_main); const CBlockIndex* GetLastCheckpoint(const CCheckpointData& data) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
/** True if any block files have ever been pruned. */
bool m_have_pruned = false;
//! Check whether the block associated with this index entry is pruned or not.
bool IsBlockPruned(const CBlockIndex* pblockindex) EXCLUSIVE_LOCKS_REQUIRED(::cs_main);
~BlockManager() ~BlockManager()
{ {
Unload(); Unload();
} }
}; };
//! Check whether the block associated with this index entry is pruned or not.
bool IsBlockPruned(const CBlockIndex* pblockindex) EXCLUSIVE_LOCKS_REQUIRED(::cs_main);
void CleanupBlockRevFiles(); void CleanupBlockRevFiles();
/** Open a block file (blk?????.dat) */ /** Open a block file (blk?????.dat) */

View file

@ -49,7 +49,7 @@ std::optional<ChainstateLoadingError> LoadChainstate(bool fReset,
if (shutdown_requested && shutdown_requested()) return ChainstateLoadingError::SHUTDOWN_PROBED; if (shutdown_requested && shutdown_requested()) return ChainstateLoadingError::SHUTDOWN_PROBED;
// LoadBlockIndex will load fHavePruned if we've ever removed a // LoadBlockIndex will load m_have_pruned if we've ever removed a
// block file from disk. // block file from disk.
// Note that it also sets fReindex based on the disk flag! // Note that it also sets fReindex based on the disk flag!
// From here on out fReindex and fReset mean something different! // From here on out fReindex and fReset mean something different!
@ -65,7 +65,7 @@ std::optional<ChainstateLoadingError> LoadChainstate(bool fReset,
// Check for changed -prune state. What we are concerned about is a user who has pruned blocks // Check for changed -prune state. What we are concerned about is a user who has pruned blocks
// in the past, but is now trying to run unpruned. // in the past, but is now trying to run unpruned.
if (fHavePruned && !fPruneMode) { if (chainman.m_blockman.m_have_pruned && !fPruneMode) {
return ChainstateLoadingError::ERROR_PRUNED_NEEDS_REINDEX; return ChainstateLoadingError::ERROR_PRUNED_NEEDS_REINDEX;
} }

View file

@ -212,9 +212,10 @@ public:
bool getHeaderTip(int& height, int64_t& block_time) override bool getHeaderTip(int& height, int64_t& block_time) override
{ {
LOCK(::cs_main); LOCK(::cs_main);
if (::pindexBestHeader) { auto best_header = chainman().m_best_header;
height = ::pindexBestHeader->nHeight; if (best_header) {
block_time = ::pindexBestHeader->GetBlockTime(); height = best_header->nHeight;
block_time = best_header->GetBlockTime();
return true; return true;
} }
return false; return false;
@ -644,7 +645,7 @@ public:
bool havePruned() override bool havePruned() override
{ {
LOCK(cs_main); LOCK(cs_main);
return node::fHavePruned; return m_node.chainman->m_blockman.m_have_pruned;
} }
bool isReadyToBroadcast() override { return !node::fImporting && !node::fReindex && !isInitialBlockDownload(); } bool isReadyToBroadcast() override { return !node::fImporting && !node::fReindex && !isInitialBlockDownload(); }
bool isInitialBlockDownload() override { bool isInitialBlockDownload() override {

View file

@ -37,7 +37,6 @@
#include <univalue.h> #include <univalue.h>
using node::GetTransaction; using node::GetTransaction;
using node::IsBlockPruned;
using node::NodeContext; using node::NodeContext;
using node::ReadBlockFromDisk; using node::ReadBlockFromDisk;
@ -295,10 +294,10 @@ static bool rest_block(const std::any& context,
CBlock block; CBlock block;
const CBlockIndex* pblockindex = nullptr; const CBlockIndex* pblockindex = nullptr;
const CBlockIndex* tip = nullptr; const CBlockIndex* tip = nullptr;
ChainstateManager* maybe_chainman = GetChainman(context, req);
if (!maybe_chainman) return false;
ChainstateManager& chainman = *maybe_chainman;
{ {
ChainstateManager* maybe_chainman = GetChainman(context, req);
if (!maybe_chainman) return false;
ChainstateManager& chainman = *maybe_chainman;
LOCK(cs_main); LOCK(cs_main);
tip = chainman.ActiveChain().Tip(); tip = chainman.ActiveChain().Tip();
pblockindex = chainman.m_blockman.LookupBlockIndex(hash); pblockindex = chainman.m_blockman.LookupBlockIndex(hash);
@ -306,7 +305,7 @@ static bool rest_block(const std::any& context,
return RESTERR(req, HTTP_NOT_FOUND, hashStr + " not found"); return RESTERR(req, HTTP_NOT_FOUND, hashStr + " not found");
} }
if (IsBlockPruned(pblockindex)) if (chainman.m_blockman.IsBlockPruned(pblockindex))
return RESTERR(req, HTTP_NOT_FOUND, hashStr + " not available (pruned data)"); return RESTERR(req, HTTP_NOT_FOUND, hashStr + " not available (pruned data)");
if (!ReadBlockFromDisk(block, pblockindex, Params().GetConsensus())) if (!ReadBlockFromDisk(block, pblockindex, Params().GetConsensus()))
@ -333,7 +332,7 @@ static bool rest_block(const std::any& context,
} }
case RESTResponseFormat::JSON: { case RESTResponseFormat::JSON: {
UniValue objBlock = blockToJSON(block, tip, pblockindex, tx_verbosity); UniValue objBlock = blockToJSON(chainman.m_blockman, block, tip, pblockindex, tx_verbosity);
std::string strJSON = objBlock.write() + "\n"; std::string strJSON = objBlock.write() + "\n";
req->WriteHeader("Content-Type", "application/json"); req->WriteHeader("Content-Type", "application/json");
req->WriteReply(HTTP_OK, strJSON); req->WriteReply(HTTP_OK, strJSON);

View file

@ -54,7 +54,6 @@ using node::BlockManager;
using node::CCoinsStats; using node::CCoinsStats;
using node::CoinStatsHashType; using node::CoinStatsHashType;
using node::GetUTXOStats; using node::GetUTXOStats;
using node::IsBlockPruned;
using node::NodeContext; using node::NodeContext;
using node::ReadBlockFromDisk; using node::ReadBlockFromDisk;
using node::SnapshotMetadata; using node::SnapshotMetadata;
@ -161,7 +160,7 @@ UniValue blockheaderToJSON(const CBlockIndex* tip, const CBlockIndex* blockindex
return result; return result;
} }
UniValue blockToJSON(const CBlock& block, const CBlockIndex* tip, const CBlockIndex* blockindex, TxVerbosity verbosity) UniValue blockToJSON(BlockManager& blockman, const CBlock& block, const CBlockIndex* tip, const CBlockIndex* blockindex, TxVerbosity verbosity)
{ {
UniValue result = blockheaderToJSON(tip, blockindex); UniValue result = blockheaderToJSON(tip, blockindex);
@ -180,7 +179,7 @@ UniValue blockToJSON(const CBlock& block, const CBlockIndex* tip, const CBlockIn
case TxVerbosity::SHOW_DETAILS: case TxVerbosity::SHOW_DETAILS:
case TxVerbosity::SHOW_DETAILS_AND_PREVOUT: case TxVerbosity::SHOW_DETAILS_AND_PREVOUT:
CBlockUndo blockUndo; CBlockUndo blockUndo;
const bool have_undo{WITH_LOCK(::cs_main, return !IsBlockPruned(blockindex) && UndoReadFromDisk(blockUndo, blockindex))}; const bool have_undo{WITH_LOCK(::cs_main, return !blockman.IsBlockPruned(blockindex) && UndoReadFromDisk(blockUndo, blockindex))};
for (size_t i = 0; i < block.vtx.size(); ++i) { for (size_t i = 0; i < block.vtx.size(); ++i) {
const CTransactionRef& tx = block.vtx.at(i); const CTransactionRef& tx = block.vtx.at(i);
@ -565,11 +564,11 @@ static RPCHelpMan getblockheader()
}; };
} }
static CBlock GetBlockChecked(const CBlockIndex* pblockindex) EXCLUSIVE_LOCKS_REQUIRED(::cs_main) static CBlock GetBlockChecked(BlockManager& blockman, const CBlockIndex* pblockindex) EXCLUSIVE_LOCKS_REQUIRED(::cs_main)
{ {
AssertLockHeld(::cs_main); AssertLockHeld(::cs_main);
CBlock block; CBlock block;
if (IsBlockPruned(pblockindex)) { if (blockman.IsBlockPruned(pblockindex)) {
throw JSONRPCError(RPC_MISC_ERROR, "Block not available (pruned data)"); throw JSONRPCError(RPC_MISC_ERROR, "Block not available (pruned data)");
} }
@ -583,11 +582,11 @@ static CBlock GetBlockChecked(const CBlockIndex* pblockindex) EXCLUSIVE_LOCKS_RE
return block; return block;
} }
static CBlockUndo GetUndoChecked(const CBlockIndex* pblockindex) EXCLUSIVE_LOCKS_REQUIRED(cs_main) static CBlockUndo GetUndoChecked(BlockManager& blockman, const CBlockIndex* pblockindex) EXCLUSIVE_LOCKS_REQUIRED(cs_main)
{ {
AssertLockHeld(::cs_main); AssertLockHeld(::cs_main);
CBlockUndo blockUndo; CBlockUndo blockUndo;
if (IsBlockPruned(pblockindex)) { if (blockman.IsBlockPruned(pblockindex)) {
throw JSONRPCError(RPC_MISC_ERROR, "Undo data not available (pruned data)"); throw JSONRPCError(RPC_MISC_ERROR, "Undo data not available (pruned data)");
} }
@ -701,8 +700,8 @@ static RPCHelpMan getblock()
CBlock block; CBlock block;
const CBlockIndex* pblockindex; const CBlockIndex* pblockindex;
const CBlockIndex* tip; const CBlockIndex* tip;
ChainstateManager& chainman = EnsureAnyChainman(request.context);
{ {
ChainstateManager& chainman = EnsureAnyChainman(request.context);
LOCK(cs_main); LOCK(cs_main);
pblockindex = chainman.m_blockman.LookupBlockIndex(hash); pblockindex = chainman.m_blockman.LookupBlockIndex(hash);
tip = chainman.ActiveChain().Tip(); tip = chainman.ActiveChain().Tip();
@ -711,7 +710,7 @@ static RPCHelpMan getblock()
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Block not found"); throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Block not found");
} }
block = GetBlockChecked(pblockindex); block = GetBlockChecked(chainman.m_blockman, pblockindex);
} }
if (verbosity <= 0) if (verbosity <= 0)
@ -731,7 +730,7 @@ static RPCHelpMan getblock()
tx_verbosity = TxVerbosity::SHOW_DETAILS_AND_PREVOUT; tx_verbosity = TxVerbosity::SHOW_DETAILS_AND_PREVOUT;
} }
return blockToJSON(block, tip, pblockindex, tx_verbosity); return blockToJSON(chainman.m_blockman, block, tip, pblockindex, tx_verbosity);
}, },
}; };
} }
@ -1205,18 +1204,18 @@ RPCHelpMan getblockchaininfo()
CHECK_NONFATAL(tip); CHECK_NONFATAL(tip);
const int height = tip->nHeight; const int height = tip->nHeight;
UniValue obj(UniValue::VOBJ); UniValue obj(UniValue::VOBJ);
obj.pushKV("chain", Params().NetworkIDString()); obj.pushKV("chain", Params().NetworkIDString());
obj.pushKV("blocks", height); obj.pushKV("blocks", height);
obj.pushKV("headers", pindexBestHeader ? pindexBestHeader->nHeight : -1); obj.pushKV("headers", chainman.m_best_header ? chainman.m_best_header->nHeight : -1);
obj.pushKV("bestblockhash", tip->GetBlockHash().GetHex()); obj.pushKV("bestblockhash", tip->GetBlockHash().GetHex());
obj.pushKV("difficulty", (double)GetDifficulty(tip)); obj.pushKV("difficulty", (double)GetDifficulty(tip));
obj.pushKV("time", (int64_t)tip->nTime); obj.pushKV("time", (int64_t)tip->nTime);
obj.pushKV("mediantime", (int64_t)tip->GetMedianTimePast()); obj.pushKV("mediantime", (int64_t)tip->GetMedianTimePast());
obj.pushKV("verificationprogress", GuessVerificationProgress(Params().TxData(), tip)); obj.pushKV("verificationprogress", GuessVerificationProgress(Params().TxData(), tip));
obj.pushKV("initialblockdownload", active_chainstate.IsInitialBlockDownload()); obj.pushKV("initialblockdownload", active_chainstate.IsInitialBlockDownload());
obj.pushKV("chainwork", tip->nChainWork.GetHex()); obj.pushKV("chainwork", tip->nChainWork.GetHex());
obj.pushKV("size_on_disk", chainman.m_blockman.CalculateCurrentUsage()); obj.pushKV("size_on_disk", chainman.m_blockman.CalculateCurrentUsage());
obj.pushKV("pruned", node::fPruneMode); obj.pushKV("pruned", node::fPruneMode);
if (node::fPruneMode) { if (node::fPruneMode) {
const CBlockIndex* block = tip; const CBlockIndex* block = tip;
CHECK_NONFATAL(block); CHECK_NONFATAL(block);
@ -1777,8 +1776,8 @@ static RPCHelpMan getblockstats()
} }
} }
const CBlock block = GetBlockChecked(pindex); const CBlock block = GetBlockChecked(chainman.m_blockman, pindex);
const CBlockUndo blockUndo = GetUndoChecked(pindex); const CBlockUndo blockUndo = GetUndoChecked(chainman.m_blockman, pindex);
const bool do_all = stats.size() == 0; // Calculate everything if nothing selected (default) const bool do_all = stats.size() == 0; // Calculate everything if nothing selected (default)
const bool do_mediantxsize = do_all || stats.count("mediantxsize") != 0; const bool do_mediantxsize = do_all || stats.count("mediantxsize") != 0;

View file

@ -10,6 +10,7 @@
#include <fs.h> #include <fs.h>
#include <streams.h> #include <streams.h>
#include <sync.h> #include <sync.h>
#include <validation.h>
#include <any> #include <any>
#include <stdint.h> #include <stdint.h>
@ -39,7 +40,7 @@ double GetDifficulty(const CBlockIndex* blockindex);
void RPCNotifyBlockChange(const CBlockIndex*); void RPCNotifyBlockChange(const CBlockIndex*);
/** Block description to JSON */ /** Block description to JSON */
UniValue blockToJSON(const CBlock& block, const CBlockIndex* tip, const CBlockIndex* blockindex, TxVerbosity verbosity) LOCKS_EXCLUDED(cs_main); UniValue blockToJSON(node::BlockManager& blockman, const CBlock& block, const CBlockIndex* tip, const CBlockIndex* blockindex, TxVerbosity verbosity) LOCKS_EXCLUDED(cs_main);
/** Block header to JSON */ /** Block header to JSON */
UniValue blockheaderToJSON(const CBlockIndex* tip, const CBlockIndex* blockindex) LOCKS_EXCLUDED(cs_main); UniValue blockheaderToJSON(const CBlockIndex* tip, const CBlockIndex* blockindex) LOCKS_EXCLUDED(cs_main);

View file

@ -69,7 +69,6 @@ using node::CBlockIndexHeightOnlyComparator;
using node::CBlockIndexWorkComparator; using node::CBlockIndexWorkComparator;
using node::CCoinsStats; using node::CCoinsStats;
using node::CoinStatsHashType; using node::CoinStatsHashType;
using node::fHavePruned;
using node::fImporting; using node::fImporting;
using node::fPruneMode; using node::fPruneMode;
using node::fReindex; using node::fReindex;
@ -120,7 +119,6 @@ const std::vector<std::string> CHECKLEVEL_DOC {
*/ */
RecursiveMutex cs_main; RecursiveMutex cs_main;
CBlockIndex *pindexBestHeader = nullptr;
Mutex g_best_block_mutex; Mutex g_best_block_mutex;
std::condition_variable g_best_block_cv; std::condition_variable g_best_block_cv;
uint256 g_best_block; uint256 g_best_block;
@ -280,8 +278,9 @@ static bool IsCurrentForFeeEstimation(CChainState& active_chainstate) EXCLUSIVE_
return false; return false;
if (active_chainstate.m_chain.Tip()->GetBlockTime() < count_seconds(GetTime<std::chrono::seconds>() - MAX_FEE_ESTIMATION_TIP_AGE)) if (active_chainstate.m_chain.Tip()->GetBlockTime() < count_seconds(GetTime<std::chrono::seconds>() - MAX_FEE_ESTIMATION_TIP_AGE))
return false; return false;
if (active_chainstate.m_chain.Height() < pindexBestHeader->nHeight - 1) if (active_chainstate.m_chain.Height() < active_chainstate.m_chainman.m_best_header->nHeight - 1) {
return false; return false;
}
return true; return true;
} }
@ -1602,8 +1601,8 @@ void CChainState::InvalidChainFound(CBlockIndex* pindexNew)
if (!m_chainman.m_best_invalid || pindexNew->nChainWork > m_chainman.m_best_invalid->nChainWork) { if (!m_chainman.m_best_invalid || pindexNew->nChainWork > m_chainman.m_best_invalid->nChainWork) {
m_chainman.m_best_invalid = pindexNew; m_chainman.m_best_invalid = pindexNew;
} }
if (pindexBestHeader != nullptr && pindexBestHeader->GetAncestor(pindexNew->nHeight) == pindexNew) { if (m_chainman.m_best_header != nullptr && m_chainman.m_best_header->GetAncestor(pindexNew->nHeight) == pindexNew) {
pindexBestHeader = m_chain.Tip(); m_chainman.m_best_header = m_chain.Tip();
} }
LogPrintf("%s: invalid block=%s height=%d log2_work=%f date=%s\n", __func__, LogPrintf("%s: invalid block=%s height=%d log2_work=%f date=%s\n", __func__,
@ -2029,8 +2028,8 @@ bool CChainState::ConnectBlock(const CBlock& block, BlockValidationState& state,
BlockMap::const_iterator it = m_blockman.m_block_index.find(hashAssumeValid); BlockMap::const_iterator it = m_blockman.m_block_index.find(hashAssumeValid);
if (it != m_blockman.m_block_index.end()) { if (it != m_blockman.m_block_index.end()) {
if (it->second.GetAncestor(pindex->nHeight) == pindex && if (it->second.GetAncestor(pindex->nHeight) == pindex &&
pindexBestHeader->GetAncestor(pindex->nHeight) == pindex && m_chainman.m_best_header->GetAncestor(pindex->nHeight) == pindex &&
pindexBestHeader->nChainWork >= nMinimumChainWork) { m_chainman.m_best_header->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.
// Script verification is skipped when connecting blocks under the // Script verification is skipped when connecting blocks under the
// assumevalid block. Assuming the assumevalid block is valid this // assumevalid block. Assuming the assumevalid block is valid this
@ -2045,7 +2044,7 @@ bool CChainState::ConnectBlock(const CBlock& block, BlockValidationState& state,
// artificially set the default assumed verified block further back. // artificially set the default assumed verified block further back.
// The test against nMinimumChainWork prevents the skipping when denied access to any chain at // The test against nMinimumChainWork prevents the skipping when denied access to any chain at
// least as good as the expected chain. // least as good as the expected chain.
fScriptChecks = (GetBlockProofEquivalentTime(*pindexBestHeader, *pindex, *pindexBestHeader, m_params.GetConsensus()) <= 60 * 60 * 24 * 7 * 2); fScriptChecks = (GetBlockProofEquivalentTime(*m_chainman.m_best_header, *pindex, *m_chainman.m_best_header, m_params.GetConsensus()) <= 60 * 60 * 24 * 7 * 2);
} }
} }
} }
@ -2358,9 +2357,9 @@ bool CChainState::FlushStateToDisk(
} }
if (!setFilesToPrune.empty()) { if (!setFilesToPrune.empty()) {
fFlushForPrune = true; fFlushForPrune = true;
if (!fHavePruned) { if (!m_blockman.m_have_pruned) {
m_blockman.m_block_tree_db->WriteFlag("prunedblockfiles", true); m_blockman.m_block_tree_db->WriteFlag("prunedblockfiles", true);
fHavePruned = true; m_blockman.m_have_pruned = true;
} }
} }
} }
@ -2904,7 +2903,7 @@ static bool NotifyHeaderTip(CChainState& chainstate) LOCKS_EXCLUDED(cs_main) {
CBlockIndex* pindexHeader = nullptr; CBlockIndex* pindexHeader = nullptr;
{ {
LOCK(cs_main); LOCK(cs_main);
pindexHeader = pindexBestHeader; pindexHeader = chainstate.m_chainman.m_best_header;
if (pindexHeader != pindexHeaderOld) { if (pindexHeader != pindexHeaderOld) {
fNotify = true; fNotify = true;
@ -3621,7 +3620,7 @@ bool ChainstateManager::AcceptBlockHeader(const CBlockHeader& block, BlockValida
} }
} }
} }
CBlockIndex* pindex{m_blockman.AddToBlockIndex(block)}; CBlockIndex* pindex{m_blockman.AddToBlockIndex(block, m_best_header)};
if (ppindex) if (ppindex)
*ppindex = pindex; *ppindex = pindex;
@ -4122,13 +4121,11 @@ void UnloadBlockIndex(CTxMemPool* mempool, ChainstateManager& chainman)
{ {
AssertLockHeld(::cs_main); AssertLockHeld(::cs_main);
chainman.Unload(); chainman.Unload();
pindexBestHeader = nullptr;
if (mempool) mempool->clear(); if (mempool) mempool->clear();
g_versionbitscache.Clear(); g_versionbitscache.Clear();
for (int b = 0; b < VERSIONBITS_NUM_BITS; b++) { for (int b = 0; b < VERSIONBITS_NUM_BITS; b++) {
warningcache[b].clear(); warningcache[b].clear();
} }
fHavePruned = false;
} }
bool ChainstateManager::LoadBlockIndex() bool ChainstateManager::LoadBlockIndex()
@ -4203,6 +4200,8 @@ bool ChainstateManager::LoadBlockIndex()
if (pindex->nStatus & BLOCK_FAILED_MASK && (!m_best_invalid || pindex->nChainWork > m_best_invalid->nChainWork)) { if (pindex->nStatus & BLOCK_FAILED_MASK && (!m_best_invalid || pindex->nChainWork > m_best_invalid->nChainWork)) {
m_best_invalid = pindex; m_best_invalid = pindex;
} }
if (pindex->IsValid(BLOCK_VALID_TREE) && (m_best_header == nullptr || CBlockIndexWorkComparator()(m_best_header, pindex)))
m_best_header = pindex;
} }
needs_init = m_blockman.m_block_index.empty(); needs_init = m_blockman.m_block_index.empty();
@ -4237,7 +4236,7 @@ bool CChainState::LoadGenesisBlock()
if (blockPos.IsNull()) { if (blockPos.IsNull()) {
return error("%s: writing genesis block to disk failed", __func__); return error("%s: writing genesis block to disk failed", __func__);
} }
CBlockIndex *pindex = m_blockman.AddToBlockIndex(block); CBlockIndex* pindex = m_blockman.AddToBlockIndex(block, m_chainman.m_best_header);
ReceivedBlockTransactions(block, pindex, blockPos); ReceivedBlockTransactions(block, pindex, blockPos);
} catch (const std::runtime_error& e) { } catch (const std::runtime_error& e) {
return error("%s: failed to write genesis block: %s", __func__, e.what()); return error("%s: failed to write genesis block: %s", __func__, e.what());
@ -4448,7 +4447,7 @@ void CChainState::CheckBlockIndex()
// HAVE_DATA is only equivalent to nTx > 0 (or VALID_TRANSACTIONS) if no pruning has occurred. // HAVE_DATA is only equivalent to nTx > 0 (or VALID_TRANSACTIONS) if no pruning has occurred.
// Unless these indexes are assumed valid and pending block download on a // Unless these indexes are assumed valid and pending block download on a
// background chainstate. // background chainstate.
if (!fHavePruned && !pindex->IsAssumedValid()) { if (!m_blockman.m_have_pruned && !pindex->IsAssumedValid()) {
// If we've never pruned, then HAVE_DATA should be equivalent to nTx > 0 // If we've never pruned, then HAVE_DATA should be equivalent to nTx > 0
assert(!(pindex->nStatus & BLOCK_HAVE_DATA) == (pindex->nTx == 0)); assert(!(pindex->nStatus & BLOCK_HAVE_DATA) == (pindex->nTx == 0));
assert(pindexFirstMissing == pindexFirstNeverProcessed); assert(pindexFirstMissing == pindexFirstNeverProcessed);
@ -4522,7 +4521,7 @@ void CChainState::CheckBlockIndex()
if (pindexFirstMissing == nullptr) assert(!foundInUnlinked); // We aren't missing data for any parent -- cannot be in m_blocks_unlinked. if (pindexFirstMissing == nullptr) assert(!foundInUnlinked); // We aren't missing data for any parent -- cannot be in m_blocks_unlinked.
if (pindex->pprev && (pindex->nStatus & BLOCK_HAVE_DATA) && pindexFirstNeverProcessed == nullptr && pindexFirstMissing != nullptr) { if (pindex->pprev && (pindex->nStatus & BLOCK_HAVE_DATA) && pindexFirstNeverProcessed == nullptr && pindexFirstMissing != nullptr) {
// We HAVE_DATA for this block, have received data for all parents at some point, but we're currently missing data for some parent. // We HAVE_DATA for this block, have received data for all parents at some point, but we're currently missing data for some parent.
assert(fHavePruned); // We must have pruned. assert(m_blockman.m_have_pruned); // We must have pruned.
// This block may have entered m_blocks_unlinked if: // This block may have entered m_blocks_unlinked if:
// - it has a descendant that at some point had more work than the // - it has a descendant that at some point had more work than the
// tip, and // tip, and
@ -5169,6 +5168,7 @@ void ChainstateManager::Unload()
m_failed_blocks.clear(); m_failed_blocks.clear();
m_blockman.Unload(); m_blockman.Unload();
m_best_header = nullptr;
m_best_invalid = nullptr; m_best_invalid = nullptr;
} }

View file

@ -131,9 +131,6 @@ extern uint256 hashAssumeValid;
/** Minimum work we will assume exists on some valid chain. */ /** Minimum work we will assume exists on some valid chain. */
extern arith_uint256 nMinimumChainWork; extern arith_uint256 nMinimumChainWork;
/** Best header we've seen so far (used for getheaders queries' starting points). */
extern CBlockIndex *pindexBestHeader;
/** Documentation for argument 'checklevel'. */ /** Documentation for argument 'checklevel'. */
extern const std::vector<std::string> CHECKLEVEL_DOC; extern const std::vector<std::string> CHECKLEVEL_DOC;
@ -883,6 +880,9 @@ public:
*/ */
std::set<CBlockIndex*> m_failed_blocks; std::set<CBlockIndex*> m_failed_blocks;
/** Best header we've seen so far (used for getheaders queries' starting points). */
CBlockIndex* m_best_header = nullptr;
//! The total number of bytes available for us to use across all in-memory //! The total number of bytes available for us to use across all in-memory
//! coins caches. This will be split somehow across chainstates. //! coins caches. This will be split somehow across chainstates.
int64_t m_total_coinstip_cache{0}; int64_t m_total_coinstip_cache{0};