aboutsummaryrefslogtreecommitdiff
path: root/src/init.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/init.cpp')
-rw-r--r--src/init.cpp271
1 files changed, 215 insertions, 56 deletions
diff --git a/src/init.cpp b/src/init.cpp
index 25756c4e6f..06f7359f80 100644
--- a/src/init.cpp
+++ b/src/init.cpp
@@ -2,7 +2,7 @@
// Copyright (c) 2009-2012 The Bitcoin developers
// Distributed under the MIT/X11 software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "db.h"
+#include "txdb.h"
#include "walletdb.h"
#include "bitcoinrpc.h"
#include "net.h"
@@ -26,6 +26,13 @@ using namespace boost;
CWallet* pwalletMain;
CClientUIInterface uiInterface;
+// Used to pass flags to the Bind() function
+enum BindFlags {
+ BF_NONE = 0,
+ BF_EXPLICIT = (1U << 0),
+ BF_REPORT_ERROR = (1U << 1)
+};
+
//////////////////////////////////////////////////////////////////////////////
//
// Shutdown
@@ -46,10 +53,12 @@ void StartShutdown()
uiInterface.QueueShutdown();
#else
// Without UI, Shutdown() can simply be started in a new thread
- CreateThread(Shutdown, NULL);
+ NewThread(Shutdown, NULL);
#endif
}
+static CCoinsViewDB *pcoinsdbview;
+
void Shutdown(void* parg)
{
static CCriticalSection cs_Shutdown;
@@ -74,11 +83,21 @@ void Shutdown(void* parg)
nTransactionsUpdated++;
bitdb.Flush(false);
StopNode();
+ {
+ LOCK(cs_main);
+ if (pblocktree)
+ pblocktree->Flush();
+ if (pcoinsTip)
+ pcoinsTip->Flush();
+ delete pcoinsTip;
+ delete pcoinsdbview;
+ delete pblocktree;
+ }
bitdb.Flush(true);
boost::filesystem::remove(GetPidFile());
UnregisterWallet(pwalletMain);
delete pwalletMain;
- CreateThread(ExitTimeout, NULL);
+ NewThread(ExitTimeout, NULL);
Sleep(50);
printf("Bitcoin exited\n\n");
fExit = true;
@@ -144,7 +163,7 @@ bool AppInit(int argc, char* argv[])
strUsage += "\n" + HelpMessage();
- fprintf(stderr, "%s", strUsage.c_str());
+ fprintf(stdout, "%s", strUsage.c_str());
return false;
}
@@ -201,12 +220,12 @@ bool static InitWarning(const std::string &str)
}
-bool static Bind(const CService &addr, bool fError = true) {
- if (IsLimited(addr))
+bool static Bind(const CService &addr, unsigned int flags) {
+ if (!(flags & BF_EXPLICIT) && IsLimited(addr))
return false;
std::string strError;
if (!BindListenPort(addr, strError)) {
- if (fError)
+ if (flags & BF_REPORT_ERROR)
return InitError(strError);
return false;
}
@@ -224,8 +243,7 @@ std::string HelpMessage()
" -gen=0 " + _("Don't generate coins") + "\n" +
" -datadir=<dir> " + _("Specify data directory") + "\n" +
" -dbcache=<n> " + _("Set database cache size in megabytes (default: 25)") + "\n" +
- " -dblogsize=<n> " + _("Set database disk log size in megabytes (default: 100)") + "\n" +
- " -timeout=<n> " + _("Specify connection timeout (in milliseconds)") + "\n" +
+ " -timeout=<n> " + _("Specify connection timeout in milliseconds (default: 5000)") + "\n" +
" -proxy=<ip:port> " + _("Connect through socks proxy") + "\n" +
" -socks=<n> " + _("Select the version of socks proxy to use (4-5, default: 5)") + "\n" +
" -tor=<ip:port> " + _("Use proxy to reach tor hidden services (default: same as -proxy)") + "\n"
@@ -240,7 +258,7 @@ std::string HelpMessage()
" -discover " + _("Discover own IP address (default: 1 when listening and no -externalip)") + "\n" +
" -irc " + _("Find peers using internet relay chat (default: 0)") + "\n" +
" -listen " + _("Accept connections from outside (default: 1 if no -proxy or -connect)") + "\n" +
- " -bind=<addr> " + _("Bind to given address. Use [host]:port notation for IPv6") + "\n" +
+ " -bind=<addr> " + _("Bind to given address and always listen on it. Use [host]:port notation for IPv6") + "\n" +
" -dnsseed " + _("Find peers using DNS lookup (default: 1 unless -connect)") + "\n" +
" -banscore=<n> " + _("Threshold for disconnecting misbehaving peers (default: 100)") + "\n" +
" -bantime=<n> " + _("Number of seconds to keep misbehaving peers from reconnecting (default: 86400)") + "\n" +
@@ -253,7 +271,6 @@ std::string HelpMessage()
" -upnp " + _("Use UPnP to map the listening port (default: 0)") + "\n" +
#endif
#endif
- " -detachdb " + _("Detach block and address databases. Increases shutdown time (default: 0)") + "\n" +
" -paytxfee=<amt> " + _("Fee per KB to add to transactions you send") + "\n" +
#ifdef QT_GUI
" -server " + _("Accept command line and JSON-RPC commands") + "\n" +
@@ -272,16 +289,18 @@ std::string HelpMessage()
#endif
" -rpcuser=<user> " + _("Username for JSON-RPC connections") + "\n" +
" -rpcpassword=<pw> " + _("Password for JSON-RPC connections") + "\n" +
- " -rpcport=<port> " + _("Listen for JSON-RPC connections on <port> (default: 8332)") + "\n" +
+ " -rpcport=<port> " + _("Listen for JSON-RPC connections on <port> (default: 8332 or testnet: 18332)") + "\n" +
" -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" +
" -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" +
" -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" +
@@ -297,6 +316,82 @@ std::string HelpMessage()
return strUsage;
}
+struct CImportingNow
+{
+ CImportingNow() {
+ assert(fImporting == false);
+ fImporting = true;
+ }
+
+ ~CImportingNow() {
+ assert(fImporting == true);
+ fImporting = false;
+ }
+};
+
+struct CImportData {
+ std::vector<boost::filesystem::path> vFiles;
+};
+
+void ThreadImport(void *data) {
+ CImportData *import = reinterpret_cast<CImportData*>(data);
+
+ RenameThread("bitcoin-loadblk");
+
+ vnThreadsRunning[THREAD_IMPORT]++;
+
+ // -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) && !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);
+ }
+ }
+
+ // -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]--;
+}
+
/** Initialize bitcoin.
* @pre Parameters should be parsed and config file should be read.
*/
@@ -379,6 +474,11 @@ bool AppInit2()
SoftSetBoolArg("-discover", false);
}
+ if (GetBoolArg("-salvagewallet")) {
+ // Rewrite just private keys: rescan to find transactions
+ SoftSetBoolArg("-rescan", true);
+ }
+
// ********************************************************* Step 3: parameter-to-internal-flags
fDebug = GetBoolArg("-debug");
@@ -389,8 +489,6 @@ bool AppInit2()
else
fDebugNet = GetBoolArg("-debugnet");
- bitdb.SetDetach(GetBoolArg("-detachdb", false));
-
#if !defined(WIN32) && !defined(QT_GUI)
fDaemon = GetBoolArg("-daemon");
#else
@@ -434,13 +532,15 @@ bool AppInit2()
// ********************************************************* Step 4: application initialization: dir lock, daemonize, pidfile, debug log
+ std::string strDataDir = GetDataDir().string();
+
// Make sure only a single Bitcoin process is using the data directory.
boost::filesystem::path pathLockFile = GetDataDir() / ".lock";
FILE* file = fopen(pathLockFile.string().c_str(), "a"); // empty lock file; created if it doesn't exist.
if (file) fclose(file);
static boost::interprocess::file_lock lock(pathLockFile.string().c_str());
if (!lock.try_lock())
- return InitError(strprintf(_("Cannot obtain a lock on data directory %s. Bitcoin is probably already running."), GetDataDir().string().c_str()));
+ return InitError(strprintf(_("Cannot obtain a lock on data directory %s. Bitcoin is probably already running."), strDataDir.c_str()));
#if !defined(WIN32) && !defined(QT_GUI)
if (fDaemon)
@@ -469,9 +569,10 @@ bool AppInit2()
printf("\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n");
printf("Bitcoin version %s (%s)\n", FormatFullVersion().c_str(), CLIENT_DATE.c_str());
printf("Using OpenSSL version %s\n", SSLeay_version(SSLEAY_VERSION));
- printf("Startup time: %s\n", DateTimeStrFormat("%x %H:%M:%S", GetTime()).c_str());
+ if (!fLogTimestamps)
+ printf("Startup time: %s\n", DateTimeStrFormat("%x %H:%M:%S", GetTime()).c_str());
printf("Default data directory %s\n", GetDefaultDataDir().string().c_str());
- printf("Used data directory %s\n", GetDataDir().string().c_str());
+ printf("Used data directory %s\n", strDataDir.c_str());
std::ostringstream strErrors;
if (fDaemon)
@@ -479,7 +580,41 @@ bool AppInit2()
int64 nStart;
- // ********************************************************* Step 5: network initialization
+ // ********************************************************* Step 5: verify database integrity
+
+ uiInterface.InitMessage(_("Verifying database integrity..."));
+
+ if (!bitdb.Open(GetDataDir()))
+ {
+ string msg = strprintf(_("Error initializing database environment %s!"
+ " To recover, BACKUP THAT DIRECTORY, then remove"
+ " everything from it except for wallet.dat."), strDataDir.c_str());
+ return InitError(msg);
+ }
+
+ if (GetBoolArg("-salvagewallet"))
+ {
+ // Recover readable keypairs:
+ if (!CWalletDB::Recover(bitdb, "wallet.dat", true))
+ return false;
+ }
+
+ if (filesystem::exists(GetDataDir() / "wallet.dat"))
+ {
+ CDBEnv::VerifyResult r = bitdb.Verify("wallet.dat", CWalletDB::Recover);
+ if (r == CDBEnv::RECOVER_OK)
+ {
+ string msg = strprintf(_("Warning: wallet.dat corrupt, data salvaged!"
+ " Original wallet.dat saved as wallet.{timestamp}.bak in %s; if"
+ " your balance or transactions are incorrect you should"
+ " restore from a backup."), strDataDir.c_str());
+ uiInterface.ThreadSafeMessageBox(msg, _("Bitcoin"), CClientUIInterface::OK | CClientUIInterface::ICON_EXCLAMATION | CClientUIInterface::MODAL);
+ }
+ if (r == CDBEnv::RECOVER_FAIL)
+ return InitError(_("wallet.dat corrupt, salvage failed"));
+ }
+
+ // ********************************************************* Step 6: network initialization
int nSocksVersion = GetArg("-socks", 5);
@@ -548,32 +683,28 @@ bool AppInit2()
#endif
bool fBound = false;
- if (!fNoListen)
- {
- std::string strError;
+ if (!fNoListen) {
if (mapArgs.count("-bind")) {
BOOST_FOREACH(std::string strBind, mapMultiArgs["-bind"]) {
CService addrBind;
if (!Lookup(strBind.c_str(), addrBind, GetListenPort(), false))
return InitError(strprintf(_("Cannot resolve -bind address: '%s'"), strBind.c_str()));
- fBound |= Bind(addrBind);
+ fBound |= Bind(addrBind, (BF_EXPLICIT | BF_REPORT_ERROR));
}
- } else {
+ }
+ else {
struct in_addr inaddr_any;
inaddr_any.s_addr = INADDR_ANY;
#ifdef USE_IPV6
- if (!IsLimited(NET_IPV6))
- fBound |= Bind(CService(in6addr_any, GetListenPort()), false);
+ fBound |= Bind(CService(in6addr_any, GetListenPort()), BF_NONE);
#endif
- if (!IsLimited(NET_IPV4))
- fBound |= Bind(CService(inaddr_any, GetListenPort()), !fBound);
+ fBound |= Bind(CService(inaddr_any, GetListenPort()), !fBound ? BF_REPORT_ERROR : BF_NONE);
}
if (!fBound)
return InitError(_("Failed to listen on any port. Use -listen=0 if you want this."));
}
- if (mapArgs.count("-externalip"))
- {
+ if (mapArgs.count("-externalip")) {
BOOST_FOREACH(string strAddr, mapMultiArgs["-externalip"]) {
CService addrLocal(strAddr, GetListenPort(), fNameLookup);
if (!addrLocal.IsValid())
@@ -585,21 +716,42 @@ bool AppInit2()
BOOST_FOREACH(string strDest, mapMultiArgs["-seednode"])
AddOneShot(strDest);
- // ********************************************************* Step 6: load blockchain
+ // ********************************************************* Step 7: load block chain
- if (GetBoolArg("-loadblockindextest"))
+ fReindex = GetBoolArg("-reindex");
+
+ if (!bitdb.Open(GetDataDir()))
{
- CTxDB txdb("r");
- txdb.LoadBlockIndex();
- PrintBlockTree();
- return false;
+ string msg = strprintf(_("Error initializing database environment %s!"
+ " To recover, BACKUP THAT DIRECTORY, then remove"
+ " everything from it except for wallet.dat."), strDataDir.c_str());
+ return InitError(msg);
}
+ // 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))
+ 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);
+
+ if (fReindex)
+ pblocktree->WriteReindexing(true);
+
if (!LoadBlockIndex())
- strErrors << _("Error loading blkindex.dat") << "\n";
+ return InitError(_("Error loading blkindex.dat"));
// as LoadBlockIndex can take several minutes, it's possible the user
// requested to kill bitcoin-qt during the last operation. If so, exit.
@@ -640,18 +792,24 @@ bool AppInit2()
return false;
}
- // ********************************************************* Step 7: load wallet
+ // ********************************************************* Step 8: load wallet
uiInterface.InitMessage(_("Loading wallet..."));
printf("Loading wallet...\n");
nStart = GetTimeMillis();
- bool fFirstRun;
+ bool fFirstRun = true;
pwalletMain = new CWallet("wallet.dat");
- int nLoadWalletRet = pwalletMain->LoadWallet(fFirstRun);
+ DBErrors nLoadWalletRet = pwalletMain->LoadWallet(fFirstRun);
if (nLoadWalletRet != DB_LOAD_OK)
{
if (nLoadWalletRet == DB_CORRUPT)
strErrors << _("Error loading wallet.dat: Wallet corrupted") << "\n";
+ else if (nLoadWalletRet == DB_NONCRITICAL_ERROR)
+ {
+ string msg(_("Warning: error reading wallet.dat! All keys read correctly, but transaction data"
+ " or address book entries might be missing or incorrect."));
+ uiInterface.ThreadSafeMessageBox(msg, _("Bitcoin"), CClientUIInterface::OK | CClientUIInterface::ICON_EXCLAMATION | CClientUIInterface::MODAL);
+ }
else if (nLoadWalletRet == DB_TOO_NEW)
strErrors << _("Error loading wallet.dat: Wallet requires newer version of Bitcoin") << "\n";
else if (nLoadWalletRet == DB_NEED_REWRITE)
@@ -717,20 +875,22 @@ bool AppInit2()
printf(" rescan %15"PRI64d"ms\n", GetTimeMillis() - nStart);
}
- // ********************************************************* Step 8: import blocks
+ // ********************************************************* Step 9: import blocks
+
+ // 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())
+ strErrors << "Failed to connect best block";
+ CImportData *pimport = new CImportData();
if (mapArgs.count("-loadblock"))
{
- uiInterface.InitMessage(_("Importing blocks..."));
BOOST_FOREACH(string strFile, mapMultiArgs["-loadblock"])
- {
- FILE *file = fopen(strFile.c_str(), "rb");
- if (file)
- LoadExternalBlockFile(file);
- }
+ pimport->vFiles.push_back(strFile);
}
+ NewThread(ThreadImport, pimport);
- // ********************************************************* Step 9: load peers
+ // ********************************************************* Step 10: load peers
uiInterface.InitMessage(_("Loading addresses..."));
printf("Loading addresses...\n");
@@ -745,7 +905,7 @@ bool AppInit2()
printf("Loaded %i addresses from peers.dat %"PRI64d"ms\n",
addrman.size(), GetTimeMillis() - nStart);
- // ********************************************************* Step 10: start node
+ // ********************************************************* Step 11: start node
if (!CheckDiskSpace())
return false;
@@ -753,19 +913,19 @@ bool AppInit2()
RandAddSeedPerfmon();
//// debug print
- printf("mapBlockIndex.size() = %d\n", mapBlockIndex.size());
+ printf("mapBlockIndex.size() = %"PRIszu"\n", mapBlockIndex.size());
printf("nBestHeight = %d\n", nBestHeight);
- printf("setKeyPool.size() = %d\n", pwalletMain->setKeyPool.size());
- printf("mapWallet.size() = %d\n", pwalletMain->mapWallet.size());
- printf("mapAddressBook.size() = %d\n", pwalletMain->mapAddressBook.size());
+ printf("setKeyPool.size() = %"PRIszu"\n", pwalletMain->setKeyPool.size());
+ printf("mapWallet.size() = %"PRIszu"\n", pwalletMain->mapWallet.size());
+ printf("mapAddressBook.size() = %"PRIszu"\n", pwalletMain->mapAddressBook.size());
- if (!CreateThread(StartNode, NULL))
+ if (!NewThread(StartNode, NULL))
InitError(_("Error: could not start node"));
if (fServer)
- CreateThread(ThreadRPCServer, NULL);
+ NewThread(ThreadRPCServer, NULL);
- // ********************************************************* Step 11: finished
+ // ********************************************************* Step 12: finished
uiInterface.InitMessage(_("Done loading"));
printf("Done loading\n");
@@ -785,4 +945,3 @@ bool AppInit2()
return true;
}
-