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.
This commit is contained in:
parent
e17bd58392
commit
ad96e7ccd9
1 changed files with 54 additions and 8 deletions
52
src/main.cpp
52
src/main.cpp
|
@ -3070,6 +3070,8 @@ void PrintBlockTree()
|
||||||
|
|
||||||
bool LoadExternalBlockFile(FILE* fileIn, CDiskBlockPos *dbp)
|
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();
|
int64_t nStart = GetTimeMillis();
|
||||||
|
|
||||||
int nLoaded = 0;
|
int nLoaded = 0;
|
||||||
|
@ -3112,20 +3114,64 @@ bool LoadExternalBlockFile(FILE* fileIn, CDiskBlockPos *dbp)
|
||||||
try {
|
try {
|
||||||
// read block
|
// read block
|
||||||
uint64_t nBlockPos = blkdat.GetPos();
|
uint64_t nBlockPos = blkdat.GetPos();
|
||||||
|
if (nBlockPos < nStartByte) // skip already indexed part
|
||||||
|
continue;
|
||||||
|
if (dbp)
|
||||||
|
dbp->nPos = nBlockPos;
|
||||||
blkdat.SetLimit(nBlockPos + nSize);
|
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;
|
CBlock block;
|
||||||
blkdat >> block;
|
blkdat >> block;
|
||||||
nRewind = blkdat.GetPos();
|
nRewind = blkdat.GetPos();
|
||||||
|
|
||||||
// process block
|
// process block
|
||||||
if (nBlockPos >= nStartByte) {
|
|
||||||
if (dbp)
|
|
||||||
dbp->nPos = nBlockPos;
|
|
||||||
CValidationState state;
|
CValidationState state;
|
||||||
if (ProcessBlock(state, NULL, &block, dbp))
|
if (ProcessBlock(state, NULL, &block, dbp))
|
||||||
nLoaded++;
|
nLoaded++;
|
||||||
if (state.IsError())
|
if (state.IsError())
|
||||||
break;
|
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) {
|
} catch (std::exception &e) {
|
||||||
LogPrintf("%s : Deserialize or I/O error - %s", __func__, e.what());
|
LogPrintf("%s : Deserialize or I/O error - %s", __func__, e.what());
|
||||||
|
|
Loading…
Reference in a new issue