merge bitcoin#24909: Move and rename pindexBestHeader, fHavePruned

This commit is contained in:
Kittywhiskers Van Gogh 2024-06-30 18:31:48 +00:00 committed by pasta
parent 70485cb2f5
commit bcafa282a3
No known key found for this signature in database
GPG Key ID: 52527BEDABE87984
14 changed files with 121 additions and 115 deletions

View File

@ -45,7 +45,7 @@ static void BlockToJsonVerbose(benchmark::Bench& bench)
TestBlockAndIndex data; TestBlockAndIndex data;
const LLMQContext& llmq_ctx = *data.testing_setup->m_node.llmq_ctx; const LLMQContext& llmq_ctx = *data.testing_setup->m_node.llmq_ctx;
bench.run([&] { bench.run([&] {
auto univalue = blockToJSON(data.block, &data.blockindex, &data.blockindex, *llmq_ctx.clhandler, *llmq_ctx.isman, /*verbose*/ true); auto univalue = blockToJSON(data.testing_setup->m_node.chainman->m_blockman, data.block, &data.blockindex, &data.blockindex, *llmq_ctx.clhandler, *llmq_ctx.isman, /*verbose*/ true);
ankerl::nanobench::doNotOptimizeAway(univalue); ankerl::nanobench::doNotOptimizeAway(univalue);
}); });
} }
@ -56,7 +56,7 @@ static void BlockToJsonVerboseWrite(benchmark::Bench& bench)
{ {
TestBlockAndIndex data; TestBlockAndIndex data;
const LLMQContext& llmq_ctx = *data.testing_setup->m_node.llmq_ctx; const LLMQContext& llmq_ctx = *data.testing_setup->m_node.llmq_ctx;
auto univalue = blockToJSON(data.block, &data.blockindex, &data.blockindex, *llmq_ctx.clhandler, *llmq_ctx.isman, /*verbose*/ true); auto univalue = blockToJSON(data.testing_setup->m_node.chainman->m_blockman, data.block, &data.blockindex, &data.blockindex, *llmq_ctx.clhandler, *llmq_ctx.isman, /*verbose*/ true);
bench.run([&] { bench.run([&] {
auto str = univalue.write(); auto str = univalue.write();
ankerl::nanobench::doNotOptimizeAway(str); ankerl::nanobench::doNotOptimizeAway(str);

View File

@ -79,7 +79,7 @@ void CDSNotificationInterface::UpdatedBlockTip(const CBlockIndex *pindexNew, con
if (pindexNew == pindexFork) // blocks were disconnected without any new ones if (pindexNew == pindexFork) // blocks were disconnected without any new ones
return; return;
m_mn_sync.UpdatedBlockTip(pindexNew, fInitialDownload); m_mn_sync.UpdatedBlockTip(m_chainman.m_best_header, pindexNew, fInitialDownload);
// Update global DIP0001 activation status // Update global DIP0001 activation status
fDIP0001ActiveAtTip = pindexNew->nHeight >= Params().GetConsensus().DIP0001Height; fDIP0001ActiveAtTip = pindexNew->nHeight >= Params().GetConsensus().DIP0001Height;

View File

@ -1890,7 +1890,7 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info)
if (ShutdownRequested()) break; if (ShutdownRequested()) break;
// 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!
@ -1936,7 +1936,7 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info)
// 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) {
strLoadError = _("You need to rebuild the database using -reindex to go back to unpruned mode. This will redownload the entire blockchain"); strLoadError = _("You need to rebuild the database using -reindex to go back to unpruned mode. This will redownload the entire blockchain");
break; break;
} }
@ -2022,7 +2022,7 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info)
for (CChainState* chainstate : chainman.GetAll()) { for (CChainState* chainstate : chainman.GetAll()) {
if (!is_coinsview_empty(chainstate)) { if (!is_coinsview_empty(chainstate)) {
uiInterface.InitMessage(_("Verifying blocks…").translated); uiInterface.InitMessage(_("Verifying blocks…").translated);
if (fHavePruned && args.GetArg("-checkblocks", DEFAULT_CHECKBLOCKS) > MIN_BLOCKS_TO_KEEP) { if (chainman.m_blockman.m_have_pruned && args.GetArg("-checkblocks", DEFAULT_CHECKBLOCKS) > 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);
} }
@ -2328,9 +2328,9 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info)
tip_info->block_hash = chainman.ActiveChain().Tip() ? chainman.ActiveChain().Tip()->GetBlockHash() : Params().GenesisBlock().GetHash(); tip_info->block_hash = chainman.ActiveChain().Tip() ? chainman.ActiveChain().Tip()->GetBlockHash() : Params().GenesisBlock().GetHash();
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

@ -329,7 +329,7 @@ void CMasternodeSync::NotifyHeaderTip(const CBlockIndex *pindexNew, bool fInitia
} }
} }
void CMasternodeSync::UpdatedBlockTip(const CBlockIndex *pindexNew, bool fInitialDownload) void CMasternodeSync::UpdatedBlockTip(const CBlockIndex *pindexTip, const CBlockIndex *pindexNew, bool fInitialDownload)
{ {
LogPrint(BCLog::MNSYNC, "CMasternodeSync::UpdatedBlockTip -- pindexNew->nHeight: %d fInitialDownload=%d\n", pindexNew->nHeight, fInitialDownload); LogPrint(BCLog::MNSYNC, "CMasternodeSync::UpdatedBlockTip -- pindexNew->nHeight: %d fInitialDownload=%d\n", pindexNew->nHeight, fInitialDownload);
nTimeLastUpdateBlockTip = GetTime<std::chrono::seconds>().count(); nTimeLastUpdateBlockTip = GetTime<std::chrono::seconds>().count();
@ -353,7 +353,6 @@ void CMasternodeSync::UpdatedBlockTip(const CBlockIndex *pindexNew, bool fInitia
} }
// Note: since we sync headers first, it should be ok to use this // Note: since we sync headers first, it should be ok to use this
CBlockIndex* pindexTip = WITH_LOCK(cs_main, return pindexBestHeader);
if (pindexTip == nullptr) return; if (pindexTip == nullptr) return;
bool fReachedBestHeaderNew = pindexNew->GetBlockHash() == pindexTip->GetBlockHash(); bool fReachedBestHeaderNew = pindexNew->GetBlockHash() == pindexTip->GetBlockHash();

View File

@ -75,7 +75,7 @@ public:
void AcceptedBlockHeader(const CBlockIndex *pindexNew); void AcceptedBlockHeader(const CBlockIndex *pindexNew);
void NotifyHeaderTip(const CBlockIndex *pindexNew, bool fInitialDownload); void NotifyHeaderTip(const CBlockIndex *pindexNew, bool fInitialDownload);
void UpdatedBlockTip(const CBlockIndex *pindexNew, bool fInitialDownload); void UpdatedBlockTip(const CBlockIndex *pindexTip, const CBlockIndex *pindexNew, bool fInitialDownload);
void DoMaintenance(); void DoMaintenance();
}; };

View File

@ -1856,9 +1856,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)
@ -2434,7 +2434,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());
@ -2824,13 +2824,13 @@ void PeerManagerImpl::ProcessHeadersMessage(CNode& pfrom, const Peer& peer,
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++;
std::string msg_type = (pfrom.nServices & NODE_HEADERS_COMPRESSED) ? NetMsgType::GETHEADERS2 : NetMsgType::GETHEADERS; std::string msg_type = (pfrom.nServices & NODE_HEADERS_COMPRESSED) ? NetMsgType::GETHEADERS2 : NetMsgType::GETHEADERS;
m_connman.PushMessage(&pfrom, msgMaker.Make(msg_type, m_chainman.ActiveChain().GetLocator(pindexBestHeader), uint256())); m_connman.PushMessage(&pfrom, msgMaker.Make(msg_type, m_chainman.ActiveChain().GetLocator(m_chainman.m_best_header), uint256()));
LogPrint(BCLog::NET, "received header %s: missing prev block %s, sending %s (%d) to end (peer=%d, nUnconnectingHeaders=%d)\n", LogPrint(BCLog::NET, "received header %s: missing prev block %s, sending %s (%d) to end (peer=%d, nUnconnectingHeaders=%d)\n",
headers[0].GetHash().ToString(), headers[0].GetHash().ToString(),
headers[0].hashPrevBlock.ToString(), headers[0].hashPrevBlock.ToString(),
msg_type, msg_type,
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.
@ -2887,7 +2887,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.
std::string msg_type = (pfrom.nServices & NODE_HEADERS_COMPRESSED) ? NetMsgType::GETHEADERS2 : NetMsgType::GETHEADERS; std::string msg_type = (pfrom.nServices & NODE_HEADERS_COMPRESSED) ? NetMsgType::GETHEADERS2 : NetMsgType::GETHEADERS;
LogPrint(BCLog::NET, "more %s (%d) to end to peer=%d (startheight:%d)\n", LogPrint(BCLog::NET, "more %s (%d) to end to peer=%d (startheight:%d)\n",
@ -3819,7 +3819,7 @@ void PeerManagerImpl::ProcessMessage(
// Download if this is a nice peer, or we have no nice peers and this one might do. // Download if this is a nice peer, or we have no nice peers and this one might do.
bool fFetch = state->fPreferredDownload || (nPreferredDownload == 0 && !pfrom.IsAddrFetchConn()); bool fFetch = state->fPreferredDownload || (nPreferredDownload == 0 && !pfrom.IsAddrFetchConn());
// Only actively request headers from a single peer, unless we're close to end of initial download. // Only actively request headers from a single peer, unless we're close to end of initial download.
if ((nSyncStarted == 0 && fFetch) || pindexBestHeader->GetBlockTime() > GetAdjustedTime() - nMaxTipAge) { if ((nSyncStarted == 0 && fFetch) || m_chainman.m_best_header->GetBlockTime() > GetAdjustedTime() - nMaxTipAge) {
// Make sure to mark this peer as the one we are currently syncing with etc. // Make sure to mark this peer as the one we are currently syncing with etc.
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 +
@ -3827,7 +3827,7 @@ void PeerManagerImpl::ProcessMessage(
// 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()) / m_chainparams.GetConsensus().nPowTargetSpacing (GetAdjustedTime() - m_chainman.m_best_header->GetBlockTime()) / m_chainparams.GetConsensus().nPowTargetSpacing
); );
nSyncStarted++; nSyncStarted++;
// Headers-first is the primary method of announcement on // Headers-first is the primary method of announcement on
@ -3872,8 +3872,8 @@ void PeerManagerImpl::ProcessMessage(
} }
if (best_block != nullptr) { if (best_block != nullptr) {
std::string msg_type = (pfrom.nServices & NODE_HEADERS_COMPRESSED) ? NetMsgType::GETHEADERS2 : NetMsgType::GETHEADERS; std::string msg_type = (pfrom.nServices & NODE_HEADERS_COMPRESSED) ? NetMsgType::GETHEADERS2 : NetMsgType::GETHEADERS;
m_connman.PushMessage(&pfrom, msgMaker.Make(msg_type, m_chainman.ActiveChain().GetLocator(pindexBestHeader), *best_block)); m_connman.PushMessage(&pfrom, msgMaker.Make(msg_type, m_chainman.ActiveChain().GetLocator(m_chainman.m_best_header), *best_block));
LogPrint(BCLog::NET, "%s (%d) %s to peer=%d\n", msg_type, pindexBestHeader->nHeight, best_block->ToString(), pfrom.GetId()); LogPrint(BCLog::NET, "%s (%d) %s to peer=%d\n", msg_type, m_chainman.m_best_header->nHeight, best_block->ToString(), pfrom.GetId());
} }
return; return;
@ -4289,7 +4289,7 @@ void PeerManagerImpl::ProcessMessage(
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((pfrom.nServices & NODE_HEADERS_COMPRESSED) ? NetMsgType::GETHEADERS2 : NetMsgType::GETHEADERS, m_chainman.ActiveChain().GetLocator(pindexBestHeader), uint256())); m_connman.PushMessage(&pfrom, msgMaker.Make((pfrom.nServices & NODE_HEADERS_COMPRESSED) ? NetMsgType::GETHEADERS2 : NetMsgType::GETHEADERS, m_chainman.ActiveChain().GetLocator(m_chainman.m_best_header), uint256()));
return; return;
} }
@ -5445,28 +5445,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 && pto->CanRelay()) { if (!state.fSyncStarted && !pto->fClient && !fImporting && !fReindex && pto->CanRelay()) {
// Only actively request headers from a single peer, unless we're close to end of initial download. // Only actively request headers from a single peer, unless we're close to end of initial download.
if ((nSyncStarted == 0 && fFetch) || pindexBestHeader->GetBlockTime() > GetAdjustedTime() - nMaxTipAge) { if ((nSyncStarted == 0 && fFetch) || m_chainman.m_best_header->GetBlockTime() > GetAdjustedTime() - nMaxTipAge) {
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;
@ -5835,7 +5836,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() - nMaxTipAge) { if (m_chainman.m_best_header->GetBlockTime() <= GetAdjustedTime() - nMaxTipAge) {
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

@ -25,7 +25,6 @@
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;
@ -86,7 +85,8 @@ 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, const uint256& hash, enum BlockStatus nStatus) CBlockIndex* BlockManager::AddToBlockIndex(const CBlockHeader& block, const uint256& hash, CBlockIndex*& best_header,
enum BlockStatus nStatus)
{ {
assert(!(nStatus & BLOCK_FAILED_MASK)); // no failed blocks allowed assert(!(nStatus & BLOCK_FAILED_MASK)); // no failed blocks allowed
AssertLockHeld(cs_main); AssertLockHeld(cs_main);
@ -113,8 +113,8 @@ CBlockIndex* BlockManager::AddToBlockIndex(const CBlockHeader& block, const uint
pindexNew->nChainWork = (pindexNew->pprev ? pindexNew->pprev->nChainWork : 0) + GetBlockProof(*pindexNew); pindexNew->nChainWork = (pindexNew->pprev ? pindexNew->pprev->nChainWork : 0) + GetBlockProof(*pindexNew);
if (nStatus & BLOCK_VALID_MASK) { if (nStatus & BLOCK_VALID_MASK) {
pindexNew->RaiseValidity(nStatus); pindexNew->RaiseValidity(nStatus);
if (pindexBestHeader == nullptr || pindexBestHeader->nChainWork < pindexNew->nChainWork) { if (best_header == nullptr || best_header->nChainWork < pindexNew->nChainWork) {
pindexBestHeader = pindexNew; best_header = pindexNew;
} }
} else { } else {
pindexNew->RaiseValidity(BLOCK_VALID_TREE); // required validity level pindexNew->RaiseValidity(BLOCK_VALID_TREE); // required validity level
@ -309,8 +309,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;
@ -327,6 +325,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()
@ -389,8 +389,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");
} }
@ -428,10 +428,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

@ -49,8 +49,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 bytes of block files that we're trying to stay below. */ /** Number of bytes of block files that we're trying to stay below. */
@ -160,7 +158,9 @@ 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, const uint256& hash, enum BlockStatus nStatus = BLOCK_VALID_TREE) EXCLUSIVE_LOCKS_REQUIRED(cs_main); CBlockIndex* AddToBlockIndex(const CBlockHeader& block, const uint256& hash, CBlockIndex*& best_header,
enum BlockStatus nStatus = BLOCK_VALID_TREE)
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);
@ -184,6 +184,12 @@ 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);
/** /**
* Return the spend height, which is one more than the inputs.GetBestBlock(). * Return the spend height, which is one more than the inputs.GetBestBlock().
* While checking, GetBestBlock() refers to the parent block. (protected by cs_main) * While checking, GetBestBlock() refers to the parent block. (protected by cs_main)
@ -197,9 +203,6 @@ public:
} }
}; };
//! 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

@ -419,9 +419,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;
@ -934,7 +935,7 @@ public:
bool havePruned() override bool havePruned() override
{ {
LOCK(cs_main); LOCK(cs_main);
return ::fHavePruned; return m_node.chainman->m_blockman.m_have_pruned;
} }
bool isReadyToBroadcast() override { return !::fImporting && !::fReindex && !isInitialBlockDownload(); } bool isReadyToBroadcast() override { return !::fImporting && !::fReindex && !isInitialBlockDownload(); }
bool isInitialBlockDownload() override { bool isInitialBlockDownload() override {

View File

@ -273,10 +273,10 @@ static bool rest_block(const CoreContext& 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);
@ -284,7 +284,7 @@ static bool rest_block(const CoreContext& 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()))
@ -311,7 +311,7 @@ static bool rest_block(const CoreContext& context,
} }
case RetFormat::JSON: { case RetFormat::JSON: {
UniValue objBlock = blockToJSON(block, tip, pblockindex, *llmq::chainLocksHandler, *llmq::quorumInstantSendManager, showTxDetails); UniValue objBlock = blockToJSON(chainman.m_blockman, block, tip, pblockindex, *llmq::chainLocksHandler, *llmq::quorumInstantSendManager, showTxDetails);
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

@ -156,7 +156,7 @@ UniValue blockheaderToJSON(const CBlockIndex* tip, const CBlockIndex* blockindex
return result; return result;
} }
UniValue blockToJSON(const CBlock& block, const CBlockIndex* tip, const CBlockIndex* blockindex, llmq::CChainLocksHandler& clhandler, llmq::CInstantSendManager& isman, bool txDetails) UniValue blockToJSON(BlockManager& blockman, const CBlock& block, const CBlockIndex* tip, const CBlockIndex* blockindex, llmq::CChainLocksHandler& clhandler, llmq::CInstantSendManager& isman, bool txDetails)
{ {
UniValue result = blockheaderToJSON(tip, blockindex, clhandler, isman); UniValue result = blockheaderToJSON(tip, blockindex, clhandler, isman);
@ -164,7 +164,7 @@ UniValue blockToJSON(const CBlock& block, const CBlockIndex* tip, const CBlockIn
UniValue txs(UniValue::VARR); UniValue txs(UniValue::VARR);
if (txDetails) { if (txDetails) {
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);
// coinbase transaction (i == 0) doesn't have undo data // coinbase transaction (i == 0) doesn't have undo data
@ -1060,11 +1060,11 @@ static RPCHelpMan getblockheaders()
}; };
} }
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)");
} }
@ -1078,11 +1078,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)");
} }
@ -1137,7 +1137,7 @@ static RPCHelpMan getmerkleblocks()
throw JSONRPCError(RPC_INVALID_PARAMETER, "Count is out of range"); throw JSONRPCError(RPC_INVALID_PARAMETER, "Count is out of range");
} }
CBlock block = GetBlockChecked(pblockindex); CBlock block = GetBlockChecked(chainman.m_blockman, pblockindex);
UniValue arrMerkleBlocks(UniValue::VARR); UniValue arrMerkleBlocks(UniValue::VARR);
@ -1247,8 +1247,8 @@ static RPCHelpMan getblock()
CBlock block; CBlock block;
const CBlockIndex* pblockindex; const CBlockIndex* pblockindex;
const CBlockIndex* tip; const CBlockIndex* tip;
ChainstateManager& chainman = EnsureChainman(node);
{ {
ChainstateManager& chainman = EnsureChainman(node);
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();
@ -1257,7 +1257,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)
@ -1269,7 +1269,7 @@ static RPCHelpMan getblock()
} }
LLMQContext& llmq_ctx = EnsureLLMQContext(node); LLMQContext& llmq_ctx = EnsureLLMQContext(node);
return blockToJSON(block, tip, pblockindex, *llmq_ctx.clhandler, *llmq_ctx.isman, verbosity >= 2); return blockToJSON(chainman.m_blockman, block, tip, pblockindex, *llmq_ctx.clhandler, *llmq_ctx.isman, verbosity >= 2);
}, },
}; };
} }
@ -1760,18 +1760,18 @@ RPCHelpMan getblockchaininfo()
const auto ehfSignals = node.mnhf_manager->GetSignalsStage(tip); const auto ehfSignals = node.mnhf_manager->GetSignalsStage(tip);
UniValue obj(UniValue::VOBJ); UniValue obj(UniValue::VOBJ);
obj.pushKV("chain", strChainName); obj.pushKV("chain", strChainName);
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", fPruneMode); obj.pushKV("pruned", fPruneMode);
if (fPruneMode) { if (fPruneMode) {
const CBlockIndex* block = tip; const CBlockIndex* block = tip;
CHECK_NONFATAL(block); CHECK_NONFATAL(block);
@ -2358,8 +2358,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;
@ -2571,7 +2571,7 @@ static RPCHelpMan getspecialtxes()
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Block not found"); throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Block not found");
} }
const CBlock block = GetBlockChecked(pblockindex); const CBlock block = GetBlockChecked(chainman.m_blockman, pblockindex);
int nTxNum = 0; int nTxNum = 0;
UniValue result(UniValue::VARR); UniValue result(UniValue::VARR);

View File

@ -9,6 +9,7 @@
#include <core_io.h> #include <core_io.h>
#include <streams.h> #include <streams.h>
#include <sync.h> #include <sync.h>
#include <validation.h>
#include <stdint.h> #include <stdint.h>
#include <vector> #include <vector>
@ -40,7 +41,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, llmq::CChainLocksHandler& clhandler, llmq::CInstantSendManager& isman, bool txDetails = false) LOCKS_EXCLUDED(cs_main); UniValue blockToJSON(BlockManager& blockman, const CBlock& block, const CBlockIndex* tip, const CBlockIndex* blockindex, llmq::CChainLocksHandler& clhandler, llmq::CInstantSendManager& isman, bool txDetails = false) LOCKS_EXCLUDED(cs_main);
/** Mempool information to JSON */ /** Mempool information to JSON */
UniValue MempoolInfoToJSON(const CTxMemPool& pool, llmq::CInstantSendManager& isman); UniValue MempoolInfoToJSON(const CTxMemPool& pool, llmq::CInstantSendManager& isman);

View File

@ -105,7 +105,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;
@ -348,8 +347,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;
} }
@ -1296,8 +1296,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__,
@ -1888,8 +1888,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
@ -1904,7 +1904,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);
} }
} }
} }
@ -2348,9 +2348,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;
} }
} }
} }
@ -2911,7 +2911,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;
@ -3129,9 +3129,9 @@ bool CChainState::InvalidateBlock(BlockValidationState& state, CBlockIndex* pind
CBlockIndex *invalid_walk_tip = m_chain.Tip(); CBlockIndex *invalid_walk_tip = m_chain.Tip();
const CBlockIndex* pindexOldTip = m_chain.Tip(); const CBlockIndex* pindexOldTip = m_chain.Tip();
if (pindex == pindexBestHeader) { if (pindex == m_chainman.m_best_header) {
m_chainman.m_best_invalid = pindexBestHeader; m_chainman.m_best_invalid = m_chainman.m_best_header;
pindexBestHeader = pindexBestHeader->pprev; m_chainman.m_best_header = m_chainman.m_best_header->pprev;
} }
// ActivateBestChain considers blocks already in m_chain // ActivateBestChain considers blocks already in m_chain
@ -3147,9 +3147,9 @@ bool CChainState::InvalidateBlock(BlockValidationState& state, CBlockIndex* pind
if (!ret) return false; if (!ret) return false;
assert(invalid_walk_tip->pprev == m_chain.Tip()); assert(invalid_walk_tip->pprev == m_chain.Tip());
if (pindexOldTip == pindexBestHeader) { if (pindexOldTip == m_chainman.m_best_header) {
m_chainman.m_best_invalid = pindexBestHeader; m_chainman.m_best_invalid = m_chainman.m_best_header;
pindexBestHeader = pindexBestHeader->pprev; m_chainman.m_best_header = m_chainman.m_best_header->pprev;
} }
// We immediately mark the disconnected blocks as invalid. // We immediately mark the disconnected blocks as invalid.
@ -3264,8 +3264,8 @@ bool CChainState::MarkConflictingBlock(BlockValidationState& state, CBlockIndex
bool pindex_was_in_chain = false; bool pindex_was_in_chain = false;
CBlockIndex *conflicting_walk_tip = m_chain.Tip(); CBlockIndex *conflicting_walk_tip = m_chain.Tip();
if (pindex == pindexBestHeader) { if (pindex == m_chainman.m_best_header) {
pindexBestHeader = pindexBestHeader->pprev; m_chainman.m_best_header = m_chainman.m_best_header->pprev;
} }
{ {
@ -3282,8 +3282,8 @@ bool CChainState::MarkConflictingBlock(BlockValidationState& state, CBlockIndex
MaybeUpdateMempoolForReorg(disconnectpool, false); MaybeUpdateMempoolForReorg(disconnectpool, false);
return false; return false;
} }
if (pindexOldTip == pindexBestHeader) { if (pindexOldTip == m_chainman.m_best_header) {
pindexBestHeader = pindexBestHeader->pprev; m_chainman.m_best_header = m_chainman.m_best_header->pprev;
} }
} }
@ -3749,13 +3749,13 @@ bool ChainstateManager::AcceptBlockHeader(const CBlockHeader& block, BlockValida
if (llmq::chainLocksHandler->HasConflictingChainLock(pindexPrev->nHeight + 1, hash)) { if (llmq::chainLocksHandler->HasConflictingChainLock(pindexPrev->nHeight + 1, hash)) {
if (miSelf == m_blockman.m_block_index.end()) { if (miSelf == m_blockman.m_block_index.end()) {
m_blockman.AddToBlockIndex(block, hash, BLOCK_CONFLICT_CHAINLOCK); m_blockman.AddToBlockIndex(block, hash, m_best_header, BLOCK_CONFLICT_CHAINLOCK);
} }
LogPrintf("ERROR: %s: header %s conflicts with chainlock\n", __func__, hash.ToString()); LogPrintf("ERROR: %s: header %s conflicts with chainlock\n", __func__, hash.ToString());
return state.Invalid(BlockValidationResult::BLOCK_CHAINLOCK, "bad-chainlock"); return state.Invalid(BlockValidationResult::BLOCK_CHAINLOCK, "bad-chainlock");
} }
} }
CBlockIndex* pindex{m_blockman.AddToBlockIndex(block, hash)}; CBlockIndex* pindex{m_blockman.AddToBlockIndex(block, hash, m_best_header)};
if (ppindex) if (ppindex)
*ppindex = pindex; *ppindex = pindex;
@ -4342,13 +4342,11 @@ void UnloadBlockIndex(CTxMemPool* mempool, ChainstateManager& chainman)
{ {
LOCK(cs_main); LOCK(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()
@ -4423,6 +4421,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();
@ -4458,7 +4458,7 @@ bool CChainState::AddGenesisBlock(const CBlock& block, BlockValidationState& sta
if (blockPos.IsNull()) { if (blockPos.IsNull()) {
return error("%s: writing genesis block to disk failed (%s)", __func__, state.ToString()); return error("%s: writing genesis block to disk failed (%s)", __func__, state.ToString());
} }
CBlockIndex* pindex = m_blockman.AddToBlockIndex(block, block.GetHash()); CBlockIndex* pindex = m_blockman.AddToBlockIndex(block, block.GetHash(), m_chainman.m_best_header);
ReceivedBlockTransactions(block, pindex, blockPos); ReceivedBlockTransactions(block, pindex, blockPos);
return true; return true;
} }
@ -4700,7 +4700,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);
@ -4778,7 +4778,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
@ -5424,6 +5424,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

@ -150,9 +150,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;
@ -881,6 +878,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};