| 4974 | } |
| 4975 | |
| 4976 | void ChainstateManager::LoadExternalBlockFile( |
| 4977 | AutoFile& file_in, |
| 4978 | FlatFilePos* dbp, |
| 4979 | std::multimap<uint256, FlatFilePos>* blocks_with_unknown_parent) |
| 4980 | { |
| 4981 | // Either both should be specified (-reindex), or neither (-loadblock). |
| 4982 | assert(!dbp == !blocks_with_unknown_parent); |
| 4983 | |
| 4984 | const auto start{SteadyClock::now()}; |
| 4985 | const CChainParams& params{GetParams()}; |
| 4986 | |
| 4987 | int nLoaded = 0; |
| 4988 | try { |
| 4989 | BufferedFile blkdat{file_in, 2 * MAX_BLOCK_SERIALIZED_SIZE, MAX_BLOCK_SERIALIZED_SIZE + 8}; |
| 4990 | // nRewind indicates where to resume scanning in case something goes wrong, |
| 4991 | // such as a block fails to deserialize. |
| 4992 | uint64_t nRewind = blkdat.GetPos(); |
| 4993 | while (!blkdat.eof()) { |
| 4994 | if (m_interrupt) return; |
| 4995 | |
| 4996 | blkdat.SetPos(nRewind); |
| 4997 | nRewind++; // start one byte further next time, in case of failure |
| 4998 | blkdat.SetLimit(); // remove former limit |
| 4999 | unsigned int nSize = 0; |
| 5000 | try { |
| 5001 | // locate a header |
| 5002 | MessageStartChars buf; |
| 5003 | blkdat.FindByte(std::byte(params.MessageStart()[0])); |
| 5004 | nRewind = blkdat.GetPos() + 1; |
| 5005 | blkdat >> buf; |
| 5006 | if (buf != params.MessageStart()) { |
| 5007 | continue; |
| 5008 | } |
| 5009 | // read size |
| 5010 | blkdat >> nSize; |
| 5011 | if (nSize < 80 || nSize > MAX_BLOCK_SERIALIZED_SIZE) |
| 5012 | continue; |
| 5013 | } catch (const std::exception&) { |
| 5014 | // no valid block header found; don't complain |
| 5015 | // (this happens at the end of every blk.dat file) |
| 5016 | break; |
| 5017 | } |
| 5018 | try { |
| 5019 | // read block header |
| 5020 | const uint64_t nBlockPos{blkdat.GetPos()}; |
| 5021 | if (dbp) |
| 5022 | dbp->nPos = nBlockPos; |
| 5023 | blkdat.SetLimit(nBlockPos + nSize); |
| 5024 | CBlockHeader header; |
| 5025 | blkdat >> header; |
| 5026 | const uint256 hash{header.GetHash()}; |
| 5027 | // Skip the rest of this block (this may read from disk into memory); position to the marker before the |
| 5028 | // next block, but it's still possible to rewind to the start of the current block (without a disk read). |
| 5029 | nRewind = nBlockPos + nSize; |
| 5030 | blkdat.SkipTo(nRewind); |
| 5031 | |
| 5032 | std::shared_ptr<CBlock> pblock{}; // needs to remain available after the cs_main lock is released to avoid duplicate reads from disk |
| 5033 |
no test coverage detected