diff options
author | Wladimir J. van der Laan <laanwj@gmail.com> | 2014-10-07 18:06:30 +0200 |
---|---|---|
committer | Pieter Wuille <pieter.wuille@gmail.com> | 2014-10-14 15:42:01 -0700 |
commit | ad96e7ccd94679d9125a436ceb5b476aacdfca82 (patch) | |
tree | d13b3705ce0c51478907f0d680af112b6f5ac006 | |
parent | e17bd58392bb81d5343d0b73e4aa6b113f5828f9 (diff) |
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.
-rw-r--r-- | src/main.cpp | 62 |
1 files changed, 54 insertions, 8 deletions
diff --git a/src/main.cpp b/src/main.cpp index bb16b716dc..ad133e1bb8 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<uint256, CDiskBlockPos> 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<uint256> queue; + queue.push_back(hash); + while (!queue.empty()) { + uint256 head = queue.front(); + queue.pop_front(); + std::pair<std::multimap<uint256, CDiskBlockPos>::iterator, std::multimap<uint256, CDiskBlockPos>::iterator> range = mapBlocksUnknownParent.equal_range(head); + while (range.first != range.second) { + std::multimap<uint256, CDiskBlockPos>::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()); |