diff options
Diffstat (limited to 'src/init.cpp')
| -rw-r--r-- | src/init.cpp | 148 |
1 files changed, 127 insertions, 21 deletions
diff --git a/src/init.cpp b/src/init.cpp index 557c23fc9..64f91a349 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -82,8 +82,13 @@ void Shutdown(void* parg) if (fFirstThread) { fShutdown = true; + fRequestShutdown = true; nTransactionsUpdated++; bitdb.Flush(false); + { + LOCK(cs_main); + ThreadScriptCheckQuit(); + } StopNode(); { LOCK(cs_main); @@ -183,9 +188,9 @@ bool AppInit(int argc, char* argv[]) fRet = AppInit2(); } catch (std::exception& e) { - PrintException(&e, "AppInit()"); + PrintExceptionContinue(&e, "AppInit()"); } catch (...) { - PrintException(NULL, "AppInit()"); + PrintExceptionContinue(NULL, "AppInit()"); } if (!fRet) Shutdown(NULL); @@ -295,14 +300,17 @@ std::string HelpMessage() " -rpcallowip=<ip> " + _("Allow JSON-RPC connections from specified IP address") + "\n" + " -rpcconnect=<ip> " + _("Send commands to node running on <ip> (default: 127.0.0.1)") + "\n" + " -blocknotify=<cmd> " + _("Execute command when the best block changes (%s in cmd is replaced by block hash)") + "\n" + + " -walletnotify=<cmd> " + _("Execute command when a wallet transaction changes (%s in cmd is replaced by TxID)") + "\n" + " -upgradewallet " + _("Upgrade wallet to latest format") + "\n" + " -keypool=<n> " + _("Set key pool size to <n> (default: 100)") + "\n" + " -rescan " + _("Rescan the block chain for missing wallet transactions") + "\n" + " -salvagewallet " + _("Attempt to recover private keys from a corrupt wallet.dat") + "\n" + - " -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" + + " -checkblocks=<n> " + _("How many blocks to check at startup (default: 288, 0 = all)") + "\n" + + " -checklevel=<n> " + _("How thorough the block verification is (0-4, default: 3)") + "\n" + + " -txindex " + _("Maintain a full transaction index (default: 0)") + "\n" + " -loadblock=<file> " + _("Imports blocks from external blk000??.dat file") + "\n" + " -reindex " + _("Rebuild blockchain index from current blk000??.dat files") + "\n" + + " -par=N " + _("Set the number of script verification threads (1-16, 0=auto, default: 0)") + "\n" + "\n" + _("Block creation options:") + "\n" + " -blockminsize=<n> " + _("Set minimum block size in bytes (default: 0)") + "\n" + @@ -359,6 +367,8 @@ void ThreadImport(void *data) { pblocktree->WriteReindexing(false); fReindex = false; printf("Reindexing finished\n"); + // To avoid ending up in a situation without genesis block, re-try initializing (no-op if reindexing worked): + InitBlockIndex(); } } @@ -484,6 +494,15 @@ bool AppInit2() fDebug = GetBoolArg("-debug"); fBenchmark = GetBoolArg("-benchmark"); + // -par=0 means autodetect, but nScriptCheckThreads==0 means no concurrency + nScriptCheckThreads = GetArg("-par", 0); + if (nScriptCheckThreads == 0) + nScriptCheckThreads = boost::thread::hardware_concurrency(); + if (nScriptCheckThreads <= 1) + nScriptCheckThreads = 0; + else if (nScriptCheckThreads > MAX_SCRIPTCHECK_THREADS) + nScriptCheckThreads = MAX_SCRIPTCHECK_THREADS; + // -debug implies fDebug* if (fDebug) fDebugNet = true; @@ -579,11 +598,17 @@ bool AppInit2() if (fDaemon) fprintf(stdout, "Bitcoin server starting\n"); + if (nScriptCheckThreads) { + printf("Using %u threads for script verification\n", nScriptCheckThreads); + for (int i=0; i<nScriptCheckThreads-1; i++) + NewThread(ThreadScriptCheck, NULL); + } + int64 nStart; - // ********************************************************* Step 5: verify database integrity + // ********************************************************* Step 5: verify wallet database integrity - uiInterface.InitMessage(_("Verifying database integrity...")); + uiInterface.InitMessage(_("Verifying wallet integrity...")); if (!bitdb.Open(GetDataDir())) { @@ -729,30 +754,111 @@ bool AppInit2() return InitError(msg); } + // Upgrading to 0.8; hard-link the old blknnnn.dat files into /blocks/ + filesystem::path blocksDir = GetDataDir() / "blocks"; + if (!filesystem::exists(blocksDir)) + { + filesystem::create_directories(blocksDir); + bool linked = false; + for (unsigned int i = 1; i < 10000; i++) { + filesystem::path source = GetDataDir() / strprintf("blk%04u.dat", i); + if (!filesystem::exists(source)) break; + filesystem::path dest = blocksDir / strprintf("blk%05u.dat", i-1); + try { + filesystem::create_hard_link(source, dest); + printf("Hardlinked %s -> %s\n", source.string().c_str(), dest.string().c_str()); + linked = true; + } catch (filesystem::filesystem_error & e) { + // Note: hardlink creation failing is not a disaster, it just means + // blocks will get re-downloaded from peers. + printf("Error hardlinking blk%04u.dat : %s\n", i, e.what()); + break; + } + } + if (linked) + { + fReindex = true; + } + } + // cache size calculations size_t nTotalCache = GetArg("-dbcache", 25) << 20; if (nTotalCache < (1 << 22)) nTotalCache = (1 << 22); // total cache cannot be less than 4 MiB size_t nBlockTreeDBCache = nTotalCache / 8; - if (nBlockTreeDBCache > (1 << 21)) + if (nBlockTreeDBCache > (1 << 21) && !GetBoolArg("-txindex", false)) nBlockTreeDBCache = (1 << 21); // block tree db cache shouldn't be larger than 2 MiB nTotalCache -= nBlockTreeDBCache; size_t nCoinDBCache = nTotalCache / 2; // use half of the remaining cache for coindb cache nTotalCache -= nCoinDBCache; nCoinCacheSize = nTotalCache / 300; // coins in memory require around 300 bytes - uiInterface.InitMessage(_("Loading block index...")); - printf("Loading block index...\n"); - nStart = GetTimeMillis(); - pblocktree = new CBlockTreeDB(nBlockTreeDBCache, false, fReindex); - pcoinsdbview = new CCoinsViewDB(nCoinDBCache, false, fReindex); - pcoinsTip = new CCoinsViewCache(*pcoinsdbview); + bool fLoaded = false; + while (!fLoaded) { + bool fReset = fReindex; + std::string strLoadError; + + uiInterface.InitMessage(_("Loading block index...")); + + nStart = GetTimeMillis(); + do { + try { + UnloadBlockIndex(); + delete pcoinsTip; + delete pcoinsdbview; + delete pblocktree; + + pblocktree = new CBlockTreeDB(nBlockTreeDBCache, false, fReindex); + pcoinsdbview = new CCoinsViewDB(nCoinDBCache, false, fReindex); + pcoinsTip = new CCoinsViewCache(*pcoinsdbview); + + if (fReindex) + pblocktree->WriteReindexing(true); + + if (!LoadBlockIndex()) { + strLoadError = _("Error loading block database"); + break; + } + + // Initialize the block index (no-op if non-empty database was already loaded) + if (!InitBlockIndex()) { + strLoadError = _("Error initializing block database"); + break; + } + + uiInterface.InitMessage(_("Verifying database...")); + if (!VerifyDB()) { + strLoadError = _("Corrupted block database detected"); + break; + } + } catch(std::exception &e) { + strLoadError = _("Error opening block database"); + break; + } - if (fReindex) - pblocktree->WriteReindexing(true); + fLoaded = true; + } while(false); + + if (!fLoaded) { + // first suggest a reindex + if (!fReset) { + bool fRet = uiInterface.ThreadSafeMessageBox( + strLoadError + ".\n" + _("Do you want to rebuild the block database now?"), + "", CClientUIInterface::MSG_ERROR | CClientUIInterface::BTN_ABORT); + if (fRet) { + fReindex = true; + fRequestShutdown = false; + } else { + return false; + } + } else { + return InitError(strLoadError); + } + } + } - if (!LoadBlockIndex()) - return InitError(_("Error loading blkindex.dat")); + if (mapArgs.count("-txindex") && fTxIndex != GetBoolArg("-txindex", false)) + return InitError(_("You need to rebuild the databases using -reindex to change -txindex")); // as LoadBlockIndex can take several minutes, it's possible the user // requested to kill bitcoin-qt during the last operation. If so, exit. @@ -796,7 +902,7 @@ bool AppInit2() // ********************************************************* Step 8: load wallet uiInterface.InitMessage(_("Loading wallet...")); - printf("Loading wallet...\n"); + nStart = GetTimeMillis(); bool fFirstRun = true; pwalletMain = new CWallet("wallet.dat"); @@ -880,7 +986,8 @@ bool AppInit2() // scan for better chains in the block chain database, that are not yet connected in the active best chain uiInterface.InitMessage(_("Importing blocks from block database...")); - if (!ConnectBestBlock()) + CValidationState state; + if (!ConnectBestBlock(state)) strErrors << "Failed to connect best block"; CImportData *pimport = new CImportData(); @@ -894,7 +1001,7 @@ bool AppInit2() // ********************************************************* Step 10: load peers uiInterface.InitMessage(_("Loading addresses...")); - printf("Loading addresses...\n"); + nStart = GetTimeMillis(); { @@ -929,7 +1036,6 @@ bool AppInit2() // ********************************************************* Step 12: finished uiInterface.InitMessage(_("Done loading")); - printf("Done loading\n"); if (!strErrors.str().empty()) return InitError(strErrors.str()); |