diff --git a/src/main.cpp b/src/main.cpp index bed13ae..d76783d 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -3607,6 +3607,23 @@ bool ProcessBlock(CNode* pfrom, CBlock* pblock) printf("IBD-DIAG: queued %u more blocks from header planner after accepting %s\n", nQueued, hash.ToString().substr(0,20).c_str()); } + else if (IsInitialBlockDownload() && nBestHeight < GetNumBlocksOfPeers()) + { + // Header cache exhausted during IBD — request more headers from all peers. + // This fixes the stall where mapHeaderSync drains to empty, hashBestHeaderSync + // becomes 0, and the refill path is never taken again. + printf("IBD-DIAG: header cache empty at height %d, requesting more headers from all peers\n", + nBestHeight); + LOCK(cs_vNodes); + for (CNode* pnode : vNodes) + { + if (!pnode->fClient && pnode->nVersion != 0) + { + pnode->pindexLastGetHeadersBegin = NULL; + pnode->PushGetHeaders(pindexBest, uint256(0)); + } + } + } return true; } @@ -5970,6 +5987,11 @@ bool SendMessages(CNode* pto, bool fSendTrickle) } else { pto->PushGetBlocks(pindexBest, uint256(0)); } + // Also send getheaders during stall to restart the header planner. + // Without this, a drained header cache stays empty because only + // getblocks is sent on stall, which can't refill mapHeaderSync. + pto->pindexLastGetHeadersBegin = NULL; + pto->PushGetHeaders(pindexBest, uint256(0)); nLastBlockReceived = GetTime(); } } diff --git a/src/rpcblockchain.cpp b/src/rpcblockchain.cpp index d3fafa8..33fc8ba 100644 --- a/src/rpcblockchain.cpp +++ b/src/rpcblockchain.cpp @@ -364,26 +364,46 @@ Value gettxoutsetinfo(const Array& params, bool fHelp) return obj; } -static int64_t ComputeActiveChainSupplyFromBlocks(int& nBlocksScanned, int& nTransactionsScanned) +static void GetActiveChainVector(std::vector& chain) { - nBlocksScanned = 0; - nTransactionsScanned = 0; + chain.clear(); if (!pindexBest) throw runtime_error("recalculatesupply: no best block"); + for (CBlockIndex* pindex = pindexBest; pindex; pindex = pindex->pprev) + chain.push_back(pindex); + + std::reverse(chain.begin(), chain.end()); +} + +static int64_t ComputeActiveChainSupplyFromBlocks(const std::vector& chain, int& nBlocksScanned, int& nTransactionsScanned) +{ + nBlocksScanned = 0; + nTransactionsScanned = 0; + CTxDB txdb("r"); int64_t nSupply = 0; - for (CBlockIndex* pindex = pindexGenesisBlock; pindex; pindex = pindex->pnext) + for (std::vector::const_iterator pindexIt = chain.begin(); pindexIt != chain.end(); ++pindexIt) { - CBlock block; - if (!block.ReadFromDisk(pindex, true)) - throw runtime_error(strprintf("recalculatesupply: failed reading block at height %d", pindex->nHeight)); + CBlockIndex* pindex = *pindexIt; + if (!pindex) + throw runtime_error("recalculatesupply: null active-chain block index"); + if (pindex->nHeight == 0) + { + nBlocksScanned++; + continue; + } + + CBlock block; int64_t nBlockValueIn = 0; int64_t nBlockValueOut = 0; + if (!block.ReadFromDisk(pindex)) + throw runtime_error(strprintf("recalculatesupply: failed reading block at height %d", pindex->nHeight)); + for (std::vector::const_iterator txIt = block.vtx.begin(); txIt != block.vtx.end(); ++txIt) { const CTransaction& tx = *txIt; @@ -442,9 +462,12 @@ Value recalculatesupply(const Array& params, bool fHelp) int nUtxoCount = 0; int64_t nUtxoSupply = txdbRead.SumUtxoValues(nUtxoCount); + std::vector activeChain; + GetActiveChainVector(activeChain); + int nBlocksScanned = 0; int nTransactionsScanned = 0; - int64_t nHistoricalSupply = ComputeActiveChainSupplyFromBlocks(nBlocksScanned, nTransactionsScanned); + int64_t nHistoricalSupply = ComputeActiveChainSupplyFromBlocks(activeChain, nBlocksScanned, nTransactionsScanned); int64_t nOldTipSupply = pindexBest->nMoneySupply; @@ -453,15 +476,27 @@ Value recalculatesupply(const Array& params, bool fHelp) CTxDB txdbWrite; int64_t nRunningSupply = 0; - for (CBlockIndex* pindex = pindexGenesisBlock; pindex; pindex = pindex->pnext) + for (std::vector::const_iterator pindexIt = activeChain.begin(); pindexIt != activeChain.end(); ++pindexIt) { - CBlock block; - if (!block.ReadFromDisk(pindex, true)) - throw runtime_error(strprintf("recalculatesupply: failed reading block at height %d during apply", pindex->nHeight)); + CBlockIndex* pindex = *pindexIt; + if (!pindex) + throw runtime_error("recalculatesupply: null active-chain block index during apply"); + if (pindex->nHeight == 0) + { + pindex->nMoneySupply = 0; + if (!txdbWrite.WriteBlockIndex(CDiskBlockIndex(pindex))) + throw runtime_error("recalculatesupply: failed to persist genesis block index during apply"); + continue; + } + + CBlock block; int64_t nBlockValueIn = 0; int64_t nBlockValueOut = 0; + if (!block.ReadFromDisk(pindex)) + throw runtime_error(strprintf("recalculatesupply: failed reading block at height %d during apply", pindex->nHeight)); + for (std::vector::const_iterator txIt = block.vtx.begin(); txIt != block.vtx.end(); ++txIt) { const CTransaction& tx = *txIt;