From ad96e7ccd94679d9125a436ceb5b476aacdfca82 Mon Sep 17 00:00:00 2001 From: "Wladimir J. van der Laan" Date: Tue, 7 Oct 2014 18:06:30 +0200 Subject: [PATCH] Make -reindex cope with out-of-order blocks Remember out-of-order block headers along with disk positions. This is likely the simplest and least-impact way to make -reindex work with headers first. Based on top of #4468. --- src/main.cpp | 62 +++++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 54 insertions(+), 8 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index bb16b716dcb..ad133e1bb81 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -3070,6 +3070,8 @@ void PrintBlockTree() bool LoadExternalBlockFile(FILE* fileIn, CDiskBlockPos *dbp) { + // Map of disk positions for blocks with unknown parent (only used for reindex) + static std::multimap mapBlocksUnknownParent; int64_t nStart = GetTimeMillis(); int nLoaded = 0; @@ -3112,20 +3114,64 @@ bool LoadExternalBlockFile(FILE* fileIn, CDiskBlockPos *dbp) try { // read block uint64_t nBlockPos = blkdat.GetPos(); + if (nBlockPos < nStartByte) // skip already indexed part + continue; + if (dbp) + dbp->nPos = nBlockPos; blkdat.SetLimit(nBlockPos + nSize); + + // read block header + CBlockHeader blockhdr; + blkdat >> blockhdr; + nRewind = blkdat.GetPos(); + + // process block header + uint256 hash = blockhdr.GetHash(); + if (hash != Params().HashGenesisBlock() && mapBlockIndex.find(blockhdr.hashPrevBlock) == mapBlockIndex.end()) { + LogPrint("reindex", "%s: Out of order block %s, parent %s not known\n", __func__, hash.ToString(), + blockhdr.hashPrevBlock.ToString()); + if (dbp) + mapBlocksUnknownParent.insert(std::make_pair(blockhdr.hashPrevBlock, *dbp)); + // TODO a slight optimization would be: blkdat.Skip(nSize - 80) + continue; + } + + // read block + blkdat.SetPos(nBlockPos); CBlock block; blkdat >> block; nRewind = blkdat.GetPos(); // process block - if (nBlockPos >= nStartByte) { - if (dbp) - dbp->nPos = nBlockPos; - CValidationState state; - if (ProcessBlock(state, NULL, &block, dbp)) - nLoaded++; - if (state.IsError()) - break; + CValidationState state; + if (ProcessBlock(state, NULL, &block, dbp)) + nLoaded++; + if (state.IsError()) + break; + + // Recursively process earlier encountered successors of this block + deque queue; + queue.push_back(hash); + while (!queue.empty()) { + uint256 head = queue.front(); + queue.pop_front(); + std::pair::iterator, std::multimap::iterator> range = mapBlocksUnknownParent.equal_range(head); + while (range.first != range.second) { + std::multimap::iterator it = range.first; + if (ReadBlockFromDisk(block, it->second)) + { + LogPrintf("%s: Processing out of order child %s of %s\n", __func__, block.GetHash().ToString(), + head.ToString()); + CValidationState dummy; + if (ProcessBlock(dummy, NULL, &block, &it->second)) + { + nLoaded++; + queue.push_back(block.GetHash()); + } + } + range.first++; + mapBlocksUnknownParent.erase(it); + } } } catch (std::exception &e) { LogPrintf("%s : Deserialize or I/O error - %s", __func__, e.what());