diff options
author | Pieter Wuille <pieter.wuille@gmail.com> | 2012-10-21 21:23:13 +0200 |
---|---|---|
committer | Pieter Wuille <pieter.wuille@gmail.com> | 2012-11-09 01:06:32 +0100 |
commit | 7fea48467442079cd0b4021b580761d7e33fa8a1 (patch) | |
tree | b750e95c08a92a39df49a3325c1f124a3e2c7744 | |
parent | 7a5b7535bf3b987c5e2157f25c8b3246033d952e (diff) |
Add -reindex, to perform in-place reindexing of block chain files
Flushes the blktree/ and coins/ databases, and reindexes the
block chain files, as if their contents was loaded via -loadblock.
Based on earlier work by Jeff Garzik.
-rw-r--r-- | src/init.cpp | 66 | ||||
-rw-r--r-- | src/leveldb.cpp | 6 | ||||
-rw-r--r-- | src/leveldb.h | 2 | ||||
-rw-r--r-- | src/main.cpp | 132 | ||||
-rw-r--r-- | src/main.h | 10 | ||||
-rw-r--r-- | src/qt/bitcoingui.cpp | 20 | ||||
-rw-r--r-- | src/qt/clientmodel.cpp | 8 | ||||
-rw-r--r-- | src/qt/clientmodel.h | 9 | ||||
-rw-r--r-- | src/test/test_bitcoin.cpp | 2 | ||||
-rw-r--r-- | src/txdb.cpp | 16 | ||||
-rw-r--r-- | src/txdb.h | 6 |
11 files changed, 202 insertions, 75 deletions
diff --git a/src/init.cpp b/src/init.cpp index 6fa8586426..22e78a9d69 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -294,6 +294,7 @@ std::string HelpMessage() " -checkblocks=<n> " + _("How many blocks to check at startup (default: 2500, 0 = all)") + "\n" + " -checklevel=<n> " + _("How thorough the block verification is (0-6, default: 1)") + "\n" + " -loadblock=<file> " + _("Imports blocks from external blk000?.dat file") + "\n" + + " -reindex " + _("Rebuild blockchain index from current blk000??.dat files") + "\n" + "\n" + _("Block creation options:") + "\n" + " -blockminsize=<n> " + _("Set minimum block size in bytes (default: 0)") + "\n" + @@ -323,33 +324,65 @@ struct CImportingNow } }; +struct CImportData { + std::vector<boost::filesystem::path> vFiles; +}; + void ThreadImport(void *data) { - std::vector<boost::filesystem::path> *vFiles = reinterpret_cast<std::vector<boost::filesystem::path>*>(data); + CImportData *import = reinterpret_cast<CImportData*>(data); RenameThread("bitcoin-loadblk"); - CImportingNow imp; vnThreadsRunning[THREAD_IMPORT]++; - // -loadblock= - BOOST_FOREACH(boost::filesystem::path &path, *vFiles) { - FILE *file = fopen(path.string().c_str(), "rb"); - if (file) - LoadExternalBlockFile(file); + // -reindex + if (fReindex) { + CImportingNow imp; + int nFile = 0; + while (!fShutdown) { + CDiskBlockPos pos; + pos.nFile = nFile; + pos.nPos = 0; + FILE *file = OpenBlockFile(pos, true); + if (!file) + break; + printf("Reindexing block file blk%05u.dat...\n", (unsigned int)nFile); + LoadExternalBlockFile(file, &pos); + nFile++; + } + if (!fShutdown) { + pblocktree->WriteReindexing(false); + fReindex = false; + printf("Reindexing finished\n"); + } } // hardcoded $DATADIR/bootstrap.dat filesystem::path pathBootstrap = GetDataDir() / "bootstrap.dat"; - if (filesystem::exists(pathBootstrap)) { + if (filesystem::exists(pathBootstrap) && !fShutdown) { FILE *file = fopen(pathBootstrap.string().c_str(), "rb"); if (file) { + CImportingNow imp; filesystem::path pathBootstrapOld = GetDataDir() / "bootstrap.dat.old"; + printf("Importing bootstrap.dat...\n"); LoadExternalBlockFile(file); RenameOver(pathBootstrap, pathBootstrapOld); } } - delete vFiles; + // -loadblock= + BOOST_FOREACH(boost::filesystem::path &path, import->vFiles) { + if (fShutdown) + break; + FILE *file = fopen(path.string().c_str(), "rb"); + if (file) { + CImportingNow imp; + printf("Importing %s...\n", path.string().c_str()); + LoadExternalBlockFile(file); + } + } + + delete import; vnThreadsRunning[THREAD_IMPORT]--; } @@ -686,6 +719,8 @@ bool AppInit2() // ********************************************************* Step 7: load block chain + fReindex = GetBoolArg("-reindex"); + if (!bitdb.Open(GetDataDir())) { string msg = strprintf(_("Error initializing database environment %s!" @@ -709,10 +744,13 @@ bool AppInit2() uiInterface.InitMessage(_("Loading block index...")); printf("Loading block index...\n"); nStart = GetTimeMillis(); - pblocktree = new CBlockTreeDB(nBlockTreeDBCache); - pcoinsdbview = new CCoinsViewDB(nCoinDBCache); + pblocktree = new CBlockTreeDB(nBlockTreeDBCache, false, fReindex); + pcoinsdbview = new CCoinsViewDB(nCoinDBCache, false, fReindex); pcoinsTip = new CCoinsViewCache(*pcoinsdbview); + if (fReindex) + pblocktree->WriteReindexing(true); + if (!LoadBlockIndex()) return InitError(_("Error loading blkindex.dat")); @@ -845,13 +883,13 @@ bool AppInit2() if (!ConnectBestBlock()) strErrors << "Failed to connect best block"; - std::vector<boost::filesystem::path> *vPath = new std::vector<boost::filesystem::path>(); + CImportData *pimport = new CImportData(); if (mapArgs.count("-loadblock")) { BOOST_FOREACH(string strFile, mapMultiArgs["-loadblock"]) - vPath->push_back(strFile); + pimport->vFiles.push_back(strFile); } - NewThread(ThreadImport, vPath); + NewThread(ThreadImport, pimport); // ********************************************************* Step 10: load peers diff --git a/src/leveldb.cpp b/src/leveldb.cpp index 58b75e5295..9e2f32a171 100644 --- a/src/leveldb.cpp +++ b/src/leveldb.cpp @@ -21,7 +21,7 @@ static leveldb::Options GetOptions(size_t nCacheSize) { return options; } -CLevelDB::CLevelDB(const boost::filesystem::path &path, size_t nCacheSize, bool fMemory) { +CLevelDB::CLevelDB(const boost::filesystem::path &path, size_t nCacheSize, bool fMemory, bool fWipe) { penv = NULL; readoptions.verify_checksums = true; iteroptions.verify_checksums = true; @@ -33,6 +33,10 @@ CLevelDB::CLevelDB(const boost::filesystem::path &path, size_t nCacheSize, bool penv = leveldb::NewMemEnv(leveldb::Env::Default()); options.env = penv; } else { + if (fWipe) { + printf("Wiping LevelDB in %s\n", path.string().c_str()); + leveldb::DestroyDB(path.string(), options); + } boost::filesystem::create_directory(path); printf("Opening LevelDB in %s\n", path.string().c_str()); } diff --git a/src/leveldb.h b/src/leveldb.h index e5b2e1ef0b..0b83432072 100644 --- a/src/leveldb.h +++ b/src/leveldb.h @@ -69,7 +69,7 @@ private: leveldb::DB *pdb; public: - CLevelDB(const boost::filesystem::path &path, size_t nCacheSize, bool fMemory = false); + CLevelDB(const boost::filesystem::path &path, size_t nCacheSize, bool fMemory = false, bool fWipe = false); ~CLevelDB(); template<typename K, typename V> bool Read(const K& key, V& value) { diff --git a/src/main.cpp b/src/main.cpp index 64adae8edd..0940260f9e 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -41,6 +41,7 @@ CBlockIndex* pindexBest = NULL; set<CBlockIndex*, CBlockIndexWorkComparator> setBlockIndexValid; // may contain all CBlockIndex*'s that have validness >=BLOCK_VALID_TRANSACTIONS, and must contain those who aren't failed int64 nTimeBestReceived = 0; bool fImporting = false; +bool fReindex = false; unsigned int nCoinCacheSize = 5000; CMedianFilter<int> cPeerBlockCounts(5, 0); // Amount of blocks that other nodes claim to have @@ -1145,7 +1146,7 @@ int GetNumBlocksOfPeers() bool IsInitialBlockDownload() { - if (pindexBest == NULL || nBestHeight < Checkpoints::GetTotalBlocksEstimate()) + if (pindexBest == NULL || nBestHeight < Checkpoints::GetTotalBlocksEstimate() || fReindex || fImporting) return true; static int64 nLastUpdate; static CBlockIndex* pindexLastBest; @@ -1862,35 +1863,45 @@ bool CBlock::AddToBlockIndex(const CDiskBlockPos &pos) } -bool FindBlockPos(CDiskBlockPos &pos, unsigned int nAddSize, unsigned int nHeight, uint64 nTime) +bool FindBlockPos(CDiskBlockPos &pos, unsigned int nAddSize, unsigned int nHeight, uint64 nTime, bool fKnown = false) { bool fUpdatedLast = false; LOCK(cs_LastBlockFile); - while (infoLastBlockFile.nSize + nAddSize >= MAX_BLOCKFILE_SIZE) { - printf("Leaving block file %i: %s\n", nLastBlockFile, infoLastBlockFile.ToString().c_str()); - FlushBlockFile(); - nLastBlockFile++; - infoLastBlockFile.SetNull(); - pblocktree->ReadBlockFileInfo(nLastBlockFile, infoLastBlockFile); // check whether data for the new file somehow already exist; can fail just fine - fUpdatedLast = true; + if (fKnown) { + if (nLastBlockFile != pos.nFile) { + nLastBlockFile = pos.nFile; + infoLastBlockFile.SetNull(); + pblocktree->ReadBlockFileInfo(nLastBlockFile, infoLastBlockFile); + } + } else { + while (infoLastBlockFile.nSize + nAddSize >= MAX_BLOCKFILE_SIZE) { + printf("Leaving block file %i: %s\n", nLastBlockFile, infoLastBlockFile.ToString().c_str()); + FlushBlockFile(); + nLastBlockFile++; + infoLastBlockFile.SetNull(); + pblocktree->ReadBlockFileInfo(nLastBlockFile, infoLastBlockFile); // check whether data for the new file somehow already exist; can fail just fine + fUpdatedLast = true; + } + pos.nFile = nLastBlockFile; + pos.nPos = infoLastBlockFile.nSize; } - pos.nFile = nLastBlockFile; - pos.nPos = infoLastBlockFile.nSize; infoLastBlockFile.nSize += nAddSize; infoLastBlockFile.AddBlock(nHeight, nTime); - unsigned int nOldChunks = (pos.nPos + BLOCKFILE_CHUNK_SIZE - 1) / BLOCKFILE_CHUNK_SIZE; - unsigned int nNewChunks = (infoLastBlockFile.nSize + BLOCKFILE_CHUNK_SIZE - 1) / BLOCKFILE_CHUNK_SIZE; - if (nNewChunks > nOldChunks) { - FILE *file = OpenBlockFile(pos); - if (file) { - printf("Pre-allocating up to position 0x%x in blk%05u.dat\n", nNewChunks * BLOCKFILE_CHUNK_SIZE, pos.nFile); - AllocateFileRange(file, pos.nPos, nNewChunks * BLOCKFILE_CHUNK_SIZE - pos.nPos); + if (!fKnown) { + unsigned int nOldChunks = (pos.nPos + BLOCKFILE_CHUNK_SIZE - 1) / BLOCKFILE_CHUNK_SIZE; + unsigned int nNewChunks = (infoLastBlockFile.nSize + BLOCKFILE_CHUNK_SIZE - 1) / BLOCKFILE_CHUNK_SIZE; + if (nNewChunks > nOldChunks) { + FILE *file = OpenBlockFile(pos); + if (file) { + printf("Pre-allocating up to position 0x%x in blk%05u.dat\n", nNewChunks * BLOCKFILE_CHUNK_SIZE, pos.nFile); + AllocateFileRange(file, pos.nPos, nNewChunks * BLOCKFILE_CHUNK_SIZE - pos.nPos); + } + fclose(file); } - fclose(file); } if (!pblocktree->WriteBlockFileInfo(nLastBlockFile, infoLastBlockFile)) @@ -1996,7 +2007,7 @@ bool CBlock::CheckBlock(bool fCheckPOW, bool fCheckMerkleRoot) const return true; } -bool CBlock::AcceptBlock() +bool CBlock::AcceptBlock(CDiskBlockPos *dbp) { // Check for duplicate uint256 hash = GetHash(); @@ -2004,11 +2015,15 @@ bool CBlock::AcceptBlock() return error("AcceptBlock() : block already in mapBlockIndex"); // Get prev block index + CBlockIndex* pindexPrev = NULL; + int nHeight = 0; + if (hash != hashGenesisBlock) { + map<uint256, CBlockIndex*>::iterator mi = mapBlockIndex.find(hashPrevBlock); if (mi == mapBlockIndex.end()) return DoS(10, error("AcceptBlock() : prev block not found")); - CBlockIndex* pindexPrev = (*mi).second; - int nHeight = pindexPrev->nHeight+1; + pindexPrev = (*mi).second; + nHeight = pindexPrev->nHeight+1; // Check proof of work if (nBits != GetNextWorkRequired(pindexPrev, this)) @@ -2048,16 +2063,22 @@ bool CBlock::AcceptBlock() return DoS(100, error("AcceptBlock() : block height mismatch in coinbase")); } } + } // Write block to history file unsigned int nBlockSize = ::GetSerializeSize(*this, SER_DISK, CLIENT_VERSION); - if (!CheckDiskSpace(::GetSerializeSize(*this, SER_DISK, CLIENT_VERSION))) - return error("AcceptBlock() : out of disk space"); CDiskBlockPos blockPos; - if (!FindBlockPos(blockPos, nBlockSize+8, nHeight, nTime)) + if (dbp == NULL) { + if (!CheckDiskSpace(::GetSerializeSize(*this, SER_DISK, CLIENT_VERSION))) + return error("AcceptBlock() : out of disk space"); + } else { + blockPos = *dbp; + } + if (!FindBlockPos(blockPos, nBlockSize+8, nHeight, nTime, dbp != NULL)) return error("AcceptBlock() : FindBlockPos failed"); - if (!WriteToDisk(blockPos)) - return error("AcceptBlock() : WriteToDisk failed"); + if (dbp == NULL) + if (!WriteToDisk(blockPos)) + return error("AcceptBlock() : WriteToDisk failed"); if (!AddToBlockIndex(blockPos)) return error("AcceptBlock() : AddToBlockIndex failed"); @@ -2086,7 +2107,7 @@ bool CBlockIndex::IsSuperMajority(int minVersion, const CBlockIndex* pstart, uns return (nFound >= nRequired); } -bool ProcessBlock(CNode* pfrom, CBlock* pblock) +bool ProcessBlock(CNode* pfrom, CBlock* pblock, CDiskBlockPos *dbp) { // Check for duplicate uint256 hash = pblock->GetHash(); @@ -2124,7 +2145,7 @@ bool ProcessBlock(CNode* pfrom, CBlock* pblock) // If we don't already have its previous block, shunt it off to holding area until we get it - if (!mapBlockIndex.count(pblock->hashPrevBlock)) + if (pblock->hashPrevBlock != 0 && !mapBlockIndex.count(pblock->hashPrevBlock)) { printf("ProcessBlock: ORPHAN BLOCK, prev=%s\n", pblock->hashPrevBlock.ToString().substr(0,20).c_str()); @@ -2141,7 +2162,7 @@ bool ProcessBlock(CNode* pfrom, CBlock* pblock) } // Store to disk - if (!pblock->AcceptBlock()) + if (!pblock->AcceptBlock(dbp)) return error("ProcessBlock() : AcceptBlock FAILED"); // Recursively process any orphan blocks that depended on this one @@ -2304,6 +2325,11 @@ bool static LoadBlockIndexDB() // Load bnBestInvalidWork, OK if it doesn't exist pblocktree->ReadBestInvalidWork(bnBestInvalidWork); + // Check whether we need to continue reindexing + bool fReindexing = false; + pblocktree->ReadReindexing(fReindexing); + fReindex |= fReindexing; + // Verify blocks in the best chain int nCheckLevel = GetArg("-checklevel", 1); int nCheckDepth = GetArg( "-checkblocks", 2500); @@ -2337,7 +2363,7 @@ bool static LoadBlockIndexDB() return true; } -bool LoadBlockIndex(bool fAllowNew) +bool LoadBlockIndex() { if (fTestNet) { @@ -2348,6 +2374,9 @@ bool LoadBlockIndex(bool fAllowNew) hashGenesisBlock = uint256("000000000933ea01ad0ee984209779baaec3ced90fa3f408719526f8d77f4943"); } + if (fReindex) + return true; + // // Load block index from databases // @@ -2359,9 +2388,6 @@ bool LoadBlockIndex(bool fAllowNew) // if (mapBlockIndex.empty()) { - if (!fAllowNew) - return false; - // Genesis Block: // CBlock(hash=000000000019d6, ver=1, hashPrevBlock=00000000000000, hashMerkleRoot=4a5e1e, nTime=1231006505, nBits=1d00ffff, nNonce=2083236893, vtx=1) // CTransaction(hash=4a5e1e, ver=1, vin.size=1, vout.size=1, nLockTime=0) @@ -2487,18 +2513,28 @@ void PrintBlockTree() } } -bool LoadExternalBlockFile(FILE* fileIn) +bool LoadExternalBlockFile(FILE* fileIn, CDiskBlockPos *dbp) { int64 nStart = GetTimeMillis(); int nLoaded = 0; { CBufferedFile blkdat(fileIn, 2*MAX_BLOCK_SIZE, MAX_BLOCK_SIZE+8, SER_DISK, CLIENT_VERSION); + uint64 nStartByte = 0; + if (dbp) { + // (try to) skip already indexed part + CBlockFileInfo info; + if (pblocktree->ReadBlockFileInfo(dbp->nFile, info)) { + nStartByte = info.nSize; + blkdat.Seek(info.nSize); + } + } uint64 nRewind = blkdat.GetPos(); while (blkdat.good() && !blkdat.eof() && !fShutdown) { blkdat.SetPos(nRewind); nRewind++; // start one byte further next time, in case of failure blkdat.SetLimit(); // remove former limit + unsigned int nSize = 0; try { // locate a header unsigned char buf[4]; @@ -2508,18 +2544,27 @@ bool LoadExternalBlockFile(FILE* fileIn) if (memcmp(buf, pchMessageStart, 4)) continue; // read size - unsigned int nSize; blkdat >> nSize; if (nSize < 80 || nSize > MAX_BLOCK_SIZE) continue; + } catch (std::exception &e) { + // no valid block header found; don't complain + break; + } + try { // read block - blkdat.SetLimit(blkdat.GetPos() + nSize); + uint64 nBlockPos = blkdat.GetPos(); + blkdat.SetLimit(nBlockPos + nSize); CBlock block; blkdat >> block; nRewind = blkdat.GetPos(); - { + + // process block + if (nBlockPos >= nStartByte) { LOCK(cs_main); - if (ProcessBlock(NULL,&block)) + if (dbp) + dbp->nPos = nBlockPos; + if (ProcessBlock(NULL, &block, dbp)) nLoaded++; } } catch (std::exception &e) { @@ -2528,7 +2573,8 @@ bool LoadExternalBlockFile(FILE* fileIn) } fclose(fileIn); } - printf("Loaded %i blocks from external file in %"PRI64d"ms\n", nLoaded, GetTimeMillis() - nStart); + if (nLoaded > 0) + printf("Loaded %i blocks from external file in %"PRI64d"ms\n", nLoaded, GetTimeMillis() - nStart); return nLoaded > 0; } @@ -2741,7 +2787,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv) // Ask the first connected node for block updates static int nAskedForBlocks = 0; - if (!pfrom->fClient && !pfrom->fOneShot && !fImporting && + if (!pfrom->fClient && !pfrom->fOneShot && !fImporting && !fReindex && (pfrom->nStartingHeight > (nBestHeight - 144)) && (pfrom->nVersion < NOBLKS_VERSION_START || pfrom->nVersion >= NOBLKS_VERSION_END) && @@ -2878,7 +2924,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv) printf(" got inventory: %s %s\n", inv.ToString().c_str(), fAlreadyHave ? "have" : "new"); if (!fAlreadyHave) { - if (!fImporting) + if (!fImporting && !fReindex) pfrom->AskFor(inv); } else if (inv.type == MSG_BLOCK && mapOrphanBlocks.count(inv.hash)) { pfrom->PushGetBlocks(pindexBest, GetOrphanRoot(mapOrphanBlocks[inv.hash])); @@ -3108,7 +3154,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv) } - else if (strCommand == "block") + else if (strCommand == "block" && !fImporting && !fReindex) // Ignore blocks received while importing { CBlock block; vRecv >> block; diff --git a/src/main.h b/src/main.h index c2ecefa8f0..25dddae0f8 100644 --- a/src/main.h +++ b/src/main.h @@ -88,6 +88,7 @@ extern CCriticalSection cs_setpwalletRegistered; extern std::set<CWallet*> setpwalletRegistered; extern unsigned char pchMessageStart[4]; extern bool fImporting; +extern bool fReindex; extern unsigned int nCoinCacheSize; // Settings @@ -109,12 +110,12 @@ class CCoinsViewCache; void RegisterWallet(CWallet* pwalletIn); void UnregisterWallet(CWallet* pwalletIn); void SyncWithWallets(const uint256 &hash, const CTransaction& tx, const CBlock* pblock = NULL, bool fUpdate = false); -bool ProcessBlock(CNode* pfrom, CBlock* pblock); +bool ProcessBlock(CNode* pfrom, CBlock* pblock, CDiskBlockPos *dbp = NULL); bool CheckDiskSpace(uint64 nAdditionalBytes=0); FILE* OpenBlockFile(const CDiskBlockPos &pos, bool fReadOnly = false); FILE* OpenUndoFile(const CDiskBlockPos &pos, bool fReadOnly = false); -bool LoadExternalBlockFile(FILE* fileIn); -bool LoadBlockIndex(bool fAllowNew=true); +bool LoadExternalBlockFile(FILE* fileIn, CDiskBlockPos *dbp = NULL); +bool LoadBlockIndex(); void PrintBlockTree(); CBlockIndex* FindBlockByHeight(int nHeight); bool ProcessMessages(CNode* pfrom); @@ -1262,7 +1263,8 @@ public: bool CheckBlock(bool fCheckPOW=true, bool fCheckMerkleRoot=true) const; // Store block on disk - bool AcceptBlock(); + // if dbp is provided, the file is known to already reside on disk + bool AcceptBlock(CDiskBlockPos *dbp = NULL); }; diff --git a/src/qt/bitcoingui.cpp b/src/qt/bitcoingui.cpp index 988f4185b9..9c47daf85d 100644 --- a/src/qt/bitcoingui.cpp +++ b/src/qt/bitcoingui.cpp @@ -489,7 +489,8 @@ void BitcoinGUI::setNumBlocks(int count, int nTotalBlocks) statusBar()->clearMessage(); // don't show / hide progress bar and its label if we have no connection to the network - if (!clientModel || (clientModel->getNumConnections() == 0 && !clientModel->isImporting())) + enum BlockSource blockSource = clientModel ? clientModel->getBlockSource() : BLOCK_SOURCE_NONE; + if (blockSource == BLOCK_SOURCE_NONE || (blockSource == BLOCK_SOURCE_NETWORK && clientModel->getNumConnections() == 0)) { progressBarLabel->setVisible(false); progressBar->setVisible(false); @@ -499,26 +500,37 @@ void BitcoinGUI::setNumBlocks(int count, int nTotalBlocks) QString tooltip; + QString importText; + switch (blockSource) { + case BLOCK_SOURCE_NONE: + case BLOCK_SOURCE_NETWORK: + importText = tr("Synchronizing with network..."); + case BLOCK_SOURCE_DISK: + importText = tr("Importing blocks from disk..."); + case BLOCK_SOURCE_REINDEX: + importText = tr("Reindexing blocks on disk..."); + } + if(count < nTotalBlocks) { int nRemainingBlocks = nTotalBlocks - count; float nPercentageDone = count / (nTotalBlocks * 0.01f); - progressBarLabel->setText(tr(clientModel->isImporting() ? "Importing blocks..." : "Synchronizing with network...")); + progressBarLabel->setText(importText); progressBarLabel->setVisible(true); progressBar->setFormat(tr("~%n block(s) remaining", "", nRemainingBlocks)); progressBar->setMaximum(nTotalBlocks); progressBar->setValue(count); progressBar->setVisible(true); - tooltip = tr("Downloaded %1 of %2 blocks of transaction history (%3% done).").arg(count).arg(nTotalBlocks).arg(nPercentageDone, 0, 'f', 2); + tooltip = tr("Processed %1 of %2 blocks of transaction history (%3% done).").arg(count).arg(nTotalBlocks).arg(nPercentageDone, 0, 'f', 2); } else { progressBarLabel->setVisible(false); progressBar->setVisible(false); - tooltip = tr("Downloaded %1 blocks of transaction history.").arg(count); + tooltip = tr("Processed %1 blocks of transaction history.").arg(count); } QDateTime lastBlockDate = clientModel->getLastBlockDate(); diff --git a/src/qt/clientmodel.cpp b/src/qt/clientmodel.cpp index 25db695a0b..9b7362d757 100644 --- a/src/qt/clientmodel.cpp +++ b/src/qt/clientmodel.cpp @@ -101,9 +101,13 @@ bool ClientModel::inInitialBlockDownload() const return IsInitialBlockDownload(); } -bool ClientModel::isImporting() const +enum BlockSource ClientModel::getBlockSource() const { - return fImporting; + if (fReindex) + return BLOCK_SOURCE_REINDEX; + if (fImporting) + return BLOCK_SOURCE_DISK; + return BLOCK_SOURCE_NETWORK; } int ClientModel::getNumBlocksOfPeers() const diff --git a/src/qt/clientmodel.h b/src/qt/clientmodel.h index fd0135b3e6..7d6401ab25 100644 --- a/src/qt/clientmodel.h +++ b/src/qt/clientmodel.h @@ -13,6 +13,13 @@ class QDateTime; class QTimer; QT_END_NAMESPACE +enum BlockSource { + BLOCK_SOURCE_NONE, + BLOCK_SOURCE_NETWORK, + BLOCK_SOURCE_DISK, + BLOCK_SOURCE_REINDEX +}; + /** Model for Bitcoin network client. */ class ClientModel : public QObject { @@ -34,7 +41,7 @@ public: //! Return true if core is doing initial block download bool inInitialBlockDownload() const; //! Return true if core is importing blocks - bool isImporting() const; + enum BlockSource getBlockSource() const; //! Return conservative estimate of total number of blocks, or 0 if unknown int getNumBlocksOfPeers() const; //! Return warnings to be displayed in status bar diff --git a/src/test/test_bitcoin.cpp b/src/test/test_bitcoin.cpp index c1f47f786b..c8a565af3a 100644 --- a/src/test/test_bitcoin.cpp +++ b/src/test/test_bitcoin.cpp @@ -22,7 +22,7 @@ struct TestingSetup { pblocktree = new CBlockTreeDB(true); pcoinsdbview = new CCoinsViewDB(true); pcoinsTip = new CCoinsViewCache(*pcoinsdbview); - LoadBlockIndex(true); + LoadBlockIndex(); bool fFirstRun; pwalletMain = new CWallet("wallet.dat"); pwalletMain->LoadWallet(fFirstRun); diff --git a/src/txdb.cpp b/src/txdb.cpp index d9972d5b06..93c5f23d8b 100644 --- a/src/txdb.cpp +++ b/src/txdb.cpp @@ -19,7 +19,7 @@ void static BatchWriteHashBestChain(CLevelDBBatch &batch, const uint256 &hash) { batch.Write('B', hash); } -CCoinsViewDB::CCoinsViewDB(size_t nCacheSize, bool fMemory) : db(GetDataDir() / "coins", nCacheSize, fMemory) { +CCoinsViewDB::CCoinsViewDB(size_t nCacheSize, bool fMemory, bool fWipe) : db(GetDataDir() / "coins", nCacheSize, fMemory, fWipe) { } bool CCoinsViewDB::GetCoins(uint256 txid, CCoins &coins) { @@ -64,7 +64,7 @@ bool CCoinsViewDB::BatchWrite(const std::map<uint256, CCoins> &mapCoins, CBlockI return db.WriteBatch(batch); } -CBlockTreeDB::CBlockTreeDB(size_t nCacheSize, bool fMemory) : CLevelDB(GetDataDir() / "blktree", nCacheSize, fMemory) { +CBlockTreeDB::CBlockTreeDB(size_t nCacheSize, bool fMemory, bool fWipe) : CLevelDB(GetDataDir() / "blktree", nCacheSize, fMemory, fWipe) { } bool CBlockTreeDB::WriteBlockIndex(const CDiskBlockIndex& blockindex) @@ -94,6 +94,18 @@ bool CBlockTreeDB::WriteLastBlockFile(int nFile) { return Write('l', nFile); } +bool CBlockTreeDB::WriteReindexing(bool fReindexing) { + if (fReindexing) + return Write('R', '1'); + else + return Erase('R'); +} + +bool CBlockTreeDB::ReadReindexing(bool &fReindexing) { + fReindexing = Exists('R'); + return true; +} + bool CBlockTreeDB::ReadLastBlockFile(int &nFile) { return Read('l', nFile); } diff --git a/src/txdb.h b/src/txdb.h index e13925c964..d7d327069f 100644 --- a/src/txdb.h +++ b/src/txdb.h @@ -14,7 +14,7 @@ class CCoinsViewDB : public CCoinsView protected: CLevelDB db; public: - CCoinsViewDB(size_t nCacheSize, bool fMemory = false); + CCoinsViewDB(size_t nCacheSize, bool fMemory = false, bool fWipe = false); bool GetCoins(uint256 txid, CCoins &coins); bool SetCoins(uint256 txid, const CCoins &coins); @@ -29,7 +29,7 @@ public: class CBlockTreeDB : public CLevelDB { public: - CBlockTreeDB(size_t nCacheSize, bool fMemory = false); + CBlockTreeDB(size_t nCacheSize, bool fMemory = false, bool fWipe = false); private: CBlockTreeDB(const CBlockTreeDB&); void operator=(const CBlockTreeDB&); @@ -41,6 +41,8 @@ public: bool WriteBlockFileInfo(int nFile, const CBlockFileInfo &fileinfo); bool ReadLastBlockFile(int &nFile); bool WriteLastBlockFile(int nFile); + bool WriteReindexing(bool fReindex); + bool ReadReindexing(bool &fReindex); bool LoadBlockIndexGuts(); }; |