@@ -4393,6 +4393,8 @@ void Chainstate::LoadExternalBlockFile(
4393
4393
try {
4394
4394
// This takes over fileIn and calls fclose() on it in the CBufferedFile destructor
4395
4395
CBufferedFile blkdat (fileIn, 2 *MAX_BLOCK_SERIALIZED_SIZE, MAX_BLOCK_SERIALIZED_SIZE+8 , SER_DISK, CLIENT_VERSION);
4396
+ // nRewind indicates where to resume scanning in case something goes wrong,
4397
+ // such as a block fails to deserialize.
4396
4398
uint64_t nRewind = blkdat.GetPos ();
4397
4399
while (!blkdat.eof ()) {
4398
4400
if (ShutdownRequested ()) return ;
@@ -4416,42 +4418,50 @@ void Chainstate::LoadExternalBlockFile(
4416
4418
continue ;
4417
4419
} catch (const std::exception&) {
4418
4420
// no valid block header found; don't complain
4421
+ // (this happens at the end of every blk.dat file)
4419
4422
break ;
4420
4423
}
4421
4424
try {
4422
- // read block
4423
- uint64_t nBlockPos = blkdat.GetPos ();
4425
+ // read block header
4426
+ const uint64_t nBlockPos{ blkdat.GetPos ()} ;
4424
4427
if (dbp)
4425
4428
dbp->nPos = nBlockPos;
4426
4429
blkdat.SetLimit (nBlockPos + nSize);
4427
- std::shared_ptr<CBlock> pblock = std::make_shared<CBlock>();
4428
- CBlock& block = *pblock;
4429
- blkdat >> block;
4430
- nRewind = blkdat.GetPos ();
4431
-
4432
- uint256 hash = block.GetHash ();
4430
+ CBlockHeader header;
4431
+ blkdat >> header;
4432
+ const uint256 hash{header.GetHash ()};
4433
+ // Skip the rest of this block (this may read from disk into memory); position to the marker before the
4434
+ // next block, but it's still possible to rewind to the start of the current block (without a disk read).
4435
+ nRewind = nBlockPos + nSize;
4436
+ blkdat.SkipTo (nRewind);
4433
4437
{
4434
4438
LOCK (cs_main);
4435
4439
// detect out of order blocks, and store them for later
4436
- if (hash != params.GetConsensus ().hashGenesisBlock && !m_blockman.LookupBlockIndex (block .hashPrevBlock )) {
4440
+ if (hash != params.GetConsensus ().hashGenesisBlock && !m_blockman.LookupBlockIndex (header .hashPrevBlock )) {
4437
4441
LogPrint (BCLog::REINDEX, " %s: Out of order block %s, parent %s not known\n " , __func__, hash.ToString (),
4438
- block .hashPrevBlock .ToString ());
4442
+ header .hashPrevBlock .ToString ());
4439
4443
if (dbp && blocks_with_unknown_parent) {
4440
- blocks_with_unknown_parent->emplace (block .hashPrevBlock , *dbp);
4444
+ blocks_with_unknown_parent->emplace (header .hashPrevBlock , *dbp);
4441
4445
}
4442
4446
continue ;
4443
4447
}
4444
4448
4445
4449
// process in case the block isn't known yet
4446
4450
const CBlockIndex* pindex = m_blockman.LookupBlockIndex (hash);
4447
4451
if (!pindex || (pindex->nStatus & BLOCK_HAVE_DATA) == 0 ) {
4448
- BlockValidationState state;
4449
- if (AcceptBlock (pblock, state, nullptr , true , dbp, nullptr , true )) {
4450
- nLoaded++;
4451
- }
4452
- if (state.IsError ()) {
4453
- break ;
4454
- }
4452
+ // This block can be processed immediately; rewind to its start, read and deserialize it.
4453
+ blkdat.SetPos (nBlockPos);
4454
+ std::shared_ptr<CBlock> pblock{std::make_shared<CBlock>()};
4455
+ blkdat >> *pblock;
4456
+ nRewind = blkdat.GetPos ();
4457
+
4458
+ BlockValidationState state;
4459
+ if (AcceptBlock (pblock, state, nullptr , true , dbp, nullptr , true )) {
4460
+ nLoaded++;
4461
+ }
4462
+ if (state.IsError ()) {
4463
+ break ;
4464
+ }
4455
4465
} else if (hash != params.GetConsensus ().hashGenesisBlock && pindex->nHeight % 1000 == 0 ) {
4456
4466
LogPrint (BCLog::REINDEX, " Block Import: already had block %s at height %d\n " , hash.ToString (), pindex->nHeight );
4457
4467
}
0 commit comments