diff --git a/src/bitcoindjs.cc b/src/bitcoindjs.cc index a9eb8a86..3c0e32bb 100644 --- a/src/bitcoindjs.cc +++ b/src/bitcoindjs.cc @@ -14,6 +14,10 @@ * Bitcoin headers */ +#if defined(HAVE_CONFIG_H) +#include "bitcoin-config.h" +#endif + #include "core.h" #include "addrman.h" #include "checkpoints.h" @@ -21,14 +25,21 @@ #include "main.h" // #include "random.h" // #include "timedata.h" + +#ifdef ENABLE_WALLET +#include "db.h" +#include "wallet.h" #include "walletdb.h" +#endif + +// #include "walletdb.h" #include "alert.h" #include "checkqueue.h" -#include "db.h" +// #include "db.h" #include "miner.h" #include "rpcclient.h" #include "tinyformat.h" -#include "wallet.h" +// #include "wallet.h" #include "allocators.h" #include "clientversion.h" #include "hash.h" @@ -74,6 +85,21 @@ * ~/bitcoin/src/main.h */ +#include +#include + +#include +#include +#include +#include + +#define MIN_CORE_FILEDESCRIPTORS 150 + +extern volatile bool fRequestShutdown; + +using namespace std; +using namespace boost; + extern void ThreadImport(std::vector); extern void DetectShutdownThread(boost::thread_group*); extern void StartNode(boost::thread_group&); @@ -288,104 +314,678 @@ async_start_node_after(uv_work_t *req) { static int start_node(void) { - /** - * StartNode method (does not work yet): - * ~/bitcoin/src/init.cpp (AppInit2() - starts bitcoind) - * ~/bitcoin/src/net.cpp (StartNode() - starts the network threads) - */ + // + // main: + // - // XXX Run this in a node thread instead to keep the event loop open: - // boost::thread_group threadGroup; - // boost::thread *detectShutdownThread = NULL; - // detectShutdownThread = new boost::thread( - // boost::bind(&DetectShutdownThread, &threadGroup)); - // for (int i = 0; i < nScriptCheckThreads - 1; i++) { - // threadGroup.create_thread(&ThreadScriptCheck); - // } - // std::vector vImportFiles; - // threadGroup.create_thread(boost::bind(&ThreadImport, vImportFiles)); - // StartNode(threadGroup); -#ifdef ENABLE_WALLET - // if (pwalletMain) { - // pwalletMain->ReacceptWalletTransactions(); - // threadGroup.create_thread(boost::bind(&ThreadFlushWalletDB, boost::ref(pwalletMain->strWalletFile))); - // } -#endif - // return 0; + // Connect bitcoind signal handlers + noui_connect(); - /** - * The AppInit2 method 1: - * ~/bitcoin/src/init.cpp (AppInit2() - starts bitcoind) - * ~/bitcoin/src/bitcoind.cpp (AppInit() - calls AppInit2) - */ + // + // appnit1: + // boost::thread_group threadGroup; - boost::thread *detectShutdownThread = NULL; - detectShutdownThread = new boost::thread( - boost::bind(&DetectShutdownThread, &threadGroup)); - return AppInit2(threadGroup) ? 0 : 1; + boost::thread* detectShutdownThread = NULL; - /** - * The AppInit2 method 2: - * ~/bitcoin/src/init.cpp (AppInit2() - starts bitcoind) - * ~/bitcoin/src/bitcoind.cpp (AppInit() - calls AppInit2) - */ + ParseParameters(argc, argv); + ReadConfigFile(mapArgs, mapMultiArgs); + // Check for -testnet or -regtest parameter (TestNet() calls are only valid after this clause) + if (!SelectParamsFromCommandLine()) { + return 1; + } + CreatePidFile(GetPidFile(), pid); + detectShutdownThread = new boost::thread(boost::bind(&DetectShutdownThread, &threadGroup)); - // boost::thread_group threadGroup; - // boost::thread *detectShutdownThread = NULL; - // //mapArgs["-server"] = "1"; - // //mapArgs.insert(std::pair("-server", "1")); - // bool fRet = false; - // try { - // SoftSetBoolArg("-server", true); - // detectShutdownThread = new boost::thread( - // boost::bind(&DetectShutdownThread, &threadGroup)); - // fRet = AppInit2(threadGroup); - // } catch (std::exception& e) { - // PrintExceptionContinue(&e, "AppInit()"); - // } catch (...) { - // PrintExceptionContinue(NULL, "AppInit()"); - // } - // if (!fRet) { - // if (detectShutdownThread) { - // detectShutdownThread->interrupt(); - // } - // threadGroup.interrupt_all(); - // } - // if (detectShutdownThread) { - // detectShutdownThread->join(); - // delete detectShutdownThread; - // detectShutdownThread = NULL; - // } - // Shutdown(); - // return fRet ? 0 : 1; + // + // appnit2: + // - /** - * The AppInit method: - * ~/bitcoin/src/init.cpp (AppInit2() - starts bitcoind) - * ~/bitcoin/src/bitcoind.cpp (AppInit() - calls AppInit2) - * ~/bitcoin/src/bitcoind_main.cpp (main() - calls AppInit()) - */ + // ********************************************************* Step 1: setup + umask(077); - // static const int b_argc = 5; - // static const char *b_argv[b_argc + 1] = { - // "-server", - // "-rpcuser=bitcoinrpc", - // "-rpcpassword=3dDisz5SKhr6O7Pi7LJ2di7zpfunTzhfYEyTauViYwHmlPh4ts", - // "-rpcport=8332", - // "-rpcallowip=127.0.0.1", - // // "-addnode=0.0.0.0", - // NULL - // }; - // bool fRet = false; - // noui_connect(); - // char conf[200] = {0}; - // int r = snprintf(conf, sizeof conf, - // "%s/.bitcoin/bitcoin.conf", getenv("HOME")); - // if (r > 0) unlink(conf); - // fRet = AppInit((int)b_argc, (char **)b_argv); - // if (fRet && fDaemon) return 0; - // return fRet ? 0 : 1; + // Clean shutdown on SIGTERM + struct sigaction sa; + sa.sa_handler = HandleSIGTERM; + sigemptyset(&sa.sa_mask); + sa.sa_flags = 0; + sigaction(SIGTERM, &sa, NULL); + sigaction(SIGINT, &sa, NULL); + + // Reopen debug.log on SIGHUP + struct sigaction sa_hup; + sa_hup.sa_handler = HandleSIGHUP; + sigemptyset(&sa_hup.sa_mask); + sa_hup.sa_flags = 0; + sigaction(SIGHUP, &sa_hup, NULL); + +#if defined (__SVR4) && defined (__sun) + // ignore SIGPIPE on Solaris + signal(SIGPIPE, SIG_IGN); +#endif + + // ********************************************************* Step 2: parameter interactions + + if (mapArgs.count("-bind")) { + // when specifying an explicit binding address, you want to listen on it + // even when -connect or -proxy is specified + SoftSetBoolArg("-listen", true); + } + + if (mapArgs.count("-connect") && mapMultiArgs["-connect"].size() > 0) { + // when only connecting to trusted nodes, do not seed via DNS, or listen by default + SoftSetBoolArg("-dnsseed", false); + SoftSetBoolArg("-listen", false); + } + + if (mapArgs.count("-proxy")) { + // to protect privacy, do not listen by default if a default proxy server is specified + SoftSetBoolArg("-listen", false); + } + + if (!GetBoolArg("-listen", true)) { + // do not map ports or try to retrieve public IP when not listening (pointless) + SoftSetBoolArg("-upnp", false); + SoftSetBoolArg("-discover", false); + } + + if (mapArgs.count("-externalip")) { + // if an explicit public IP is specified, do not try to find others + SoftSetBoolArg("-discover", false); + } + + if (GetBoolArg("-salvagewallet", false)) { + // Rewrite just private keys: rescan to find transactions + SoftSetBoolArg("-rescan", true); + } + + // -zapwallettx implies a rescan + if (GetBoolArg("-zapwallettxes", false)) { + SoftSetBoolArg("-rescan", true); + } + + // Make sure enough file descriptors are available + int nBind = std::max((int)mapArgs.count("-bind"), 1); + nMaxConnections = GetArg("-maxconnections", 125); + nMaxConnections = std::max(std::min(nMaxConnections, (int)(FD_SETSIZE - nBind - MIN_CORE_FILEDESCRIPTORS)), 0); + int nFD = RaiseFileDescriptorLimit(nMaxConnections + MIN_CORE_FILEDESCRIPTORS); + if (nFD < MIN_CORE_FILEDESCRIPTORS) { + return 1; + } + if (nFD - MIN_CORE_FILEDESCRIPTORS < nMaxConnections) { + nMaxConnections = nFD - MIN_CORE_FILEDESCRIPTORS; + } + + // ********************************************************* Step 3: parameter-to-internal-flags + + fDebug = !mapMultiArgs["-debug"].empty(); + // Special-case: if -debug=0/-nodebug is set, turn off debugging messages + const vector& categories = mapMultiArgs["-debug"]; + if (GetBoolArg("-nodebug", false) + || find(categories.begin(), categories.end(), string("0")) != categories.end()) { + fDebug = false; + } + + // Check for -debugnet (deprecated) + GetBoolArg("-debugnet", false); + + fBenchmark = GetBoolArg("-benchmark", false); + mempool.setSanityCheck(GetBoolArg("-checkmempool", RegTest())); + Checkpoints::fEnabled = GetBoolArg("-checkpoints", true); + + // -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; + } + + fServer = GetBoolArg("-server", false); + fPrintToConsole = GetBoolArg("-printtoconsole", false); + fLogTimestamps = GetBoolArg("-logtimestamps", true); +#ifdef ENABLE_WALLET + bool fDisableWallet = GetBoolArg("-disablewallet", false); +#endif + + if (mapArgs.count("-timeout")) { + int nNewTimeout = GetArg("-timeout", 5000); + if (nNewTimeout > 0 && nNewTimeout < 600000) { + nConnectTimeout = nNewTimeout; + } + } + + // Continue to put "/P2SH/" in the coinbase to monitor + // BIP16 support. + // This can be removed eventually... + const char* pszP2SH = "/P2SH/"; + COINBASE_FLAGS << std::vector(pszP2SH, pszP2SH+strlen(pszP2SH)); + + // Fee-per-kilobyte amount considered the same as "free" + // If you are mining, be careful setting this: + // if you set it to zero then + // a transaction spammer can cheaply fill blocks using + // 1-satoshi-fee transactions. It should be set above the real + // cost to you of processing a transaction. + if (mapArgs.count("-mintxfee")) { + int64_t n = 0; + if (ParseMoney(mapArgs["-mintxfee"], n) && n > 0) { + CTransaction::nMinTxFee = n; + } else { + return 1; + } + } + if (mapArgs.count("-minrelaytxfee")) { + int64_t n = 0; + if (ParseMoney(mapArgs["-minrelaytxfee"], n) && n > 0) { + CTransaction::nMinRelayTxFee = n; + } else { + return 1; + } + } + +#ifdef ENABLE_WALLET + if (mapArgs.count("-paytxfee")) { + if (!ParseMoney(mapArgs["-paytxfee"], nTransactionFee)) { + return 1; + } + } + bSpendZeroConfChange = GetArg("-spendzeroconfchange", true); + + strWalletFile = GetArg("-wallet", "wallet.dat"); +#endif + // ********************************************************* Step 4: application initialization: dir lock, daemonize, pidfile, debug log + + std::string strDataDir = GetDataDir().string(); +#ifdef ENABLE_WALLET + // Wallet file must be a plain filename without a directory + if (strWalletFile != boost::filesystem::basename(strWalletFile) + + boost::filesystem::extension(strWalletFile)) { + return 1; + } +#endif + // 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 1; + } + + if (GetBoolArg("-shrinkdebugfile", !fDebug)) { + ShrinkDebugFile(); + } + int failure = 0; + + if (nScriptCheckThreads) { + for (int i = 0; i < nScriptCheckThreads - 1; i++) { + threadGroup.create_thread(&ThreadScriptCheck); + } + } + + int64_t nStart; + + // ********************************************************* Step 5: verify wallet database integrity +#ifdef ENABLE_WALLET + if (!fDisableWallet) { + if (!bitdb.Open(GetDataDir())) { + // try moving the database env out of the way + boost::filesystem::path pathDatabase = GetDataDir() / "database"; + boost::filesystem::path pathDatabaseBak = GetDataDir() / strprintf("database.%d.bak", GetTime()); + try { + boost::filesystem::rename(pathDatabase, pathDatabaseBak); + } catch (boost::filesystem::filesystem_error &error) { + ; // failure is ok (well, not really, but it's not worse than what we started with) + } + + // try again + if (!bitdb.Open(GetDataDir())) { + // if it still fails, it probably means we can't even create the database env + // Error initializing wallet database environment + return 1; + } + } + + if (GetBoolArg("-salvagewallet", false)) { + // Recover readable keypairs: + if (!CWalletDB::Recover(bitdb, strWalletFile, true)) { + return 1; + } + } + + if (filesystem::exists(GetDataDir() / strWalletFile)) { + CDBEnv::VerifyResult r = bitdb.Verify(strWalletFile, CWalletDB::Recover); + if (r == CDBEnv::RECOVER_OK) { + ; // wallet salvaged + } + if (r == CDBEnv::RECOVER_FAIL) { + return 1; + } + } + } // (!fDisableWallet) +#endif // ENABLE_WALLET + // ********************************************************* Step 6: network initialization + + RegisterNodeSignals(GetNodeSignals()); + + int nSocksVersion = GetArg("-socks", 5); + if (nSocksVersion != 4 && nSocksVersion != 5) { + return 1; + } + + if (mapArgs.count("-onlynet")) { + std::set nets; + BOOST_FOREACH(std::string snet, mapMultiArgs["-onlynet"]) { + enum Network net = ParseNetwork(snet); + if (net == NET_UNROUTABLE) { + return 1; + } + nets.insert(net); + } + for (int n = 0; n < NET_MAX; n++) { + enum Network net = (enum Network)n; + if (!nets.count(net)) { + SetLimited(net); + } + } + } +#if defined(USE_IPV6) +#if ! USE_IPV6 + else + SetLimited(NET_IPV6); +#endif +#endif + + CService addrProxy; + bool fProxy = false; + if (mapArgs.count("-proxy")) { + addrProxy = CService(mapArgs["-proxy"], 9050); + if (!addrProxy.IsValid()) { + return 1; + } + + if (!IsLimited(NET_IPV4)) { + SetProxy(NET_IPV4, addrProxy, nSocksVersion); + } + + if (nSocksVersion > 4) { +#ifdef USE_IPV6 + if (!IsLimited(NET_IPV6)) { + SetProxy(NET_IPV6, addrProxy, nSocksVersion); + } +#endif + SetNameProxy(addrProxy, nSocksVersion); + } + fProxy = true; + } + + // -onion can override normal proxy, -noonion disables tor entirely + if (!(mapArgs.count("-onion") + && mapArgs["-onion"] == "0") + && !(mapArgs.count("-tor") + && mapArgs["-tor"] == "0") + && (fProxy || mapArgs.count("-onion") || mapArgs.count("-tor"))) { + CService addrOnion; + if (!mapArgs.count("-onion") && !mapArgs.count("-tor")) { + addrOnion = addrProxy; + } else { + addrOnion = mapArgs.count("-onion")?CService(mapArgs["-onion"], 9050):CService(mapArgs["-tor"], 9050); + } + if (!addrOnion.IsValid()) { + return 1; + } + SetProxy(NET_TOR, addrOnion, 5); + SetReachable(NET_TOR); + } + + // see Step 2: parameter interactions for more information about these + fNoListen = !GetBoolArg("-listen", true); + fDiscover = GetBoolArg("-discover", true); + fNameLookup = GetBoolArg("-dns", true); + + bool fBound = false; + if (!fNoListen) { + if (mapArgs.count("-bind")) { + BOOST_FOREACH(std::string strBind, mapMultiArgs["-bind"]) { + CService addrBind; + if (!Lookup(strBind.c_str(), addrBind, GetListenPort(), false)) + return 1; + fBound |= Bind(addrBind, (BF_EXPLICIT | BF_REPORT_ERROR)); + } + } else { + struct in_addr inaddr_any; + inaddr_any.s_addr = INADDR_ANY; +#ifdef USE_IPV6 + fBound |= Bind(CService(in6addr_any, GetListenPort()), BF_NONE); +#endif + fBound |= Bind(CService(inaddr_any, GetListenPort()), !fBound ? BF_REPORT_ERROR : BF_NONE); + } + if (!fBound) { + return 1; + } + } + + if (mapArgs.count("-externalip")) { + BOOST_FOREACH(string strAddr, mapMultiArgs["-externalip"]) { + CService addrLocal(strAddr, GetListenPort(), fNameLookup); + if (!addrLocal.IsValid()) + return 1; + AddLocal(CService(strAddr, GetListenPort(), fNameLookup), LOCAL_MANUAL); + } + } + + BOOST_FOREACH(string strDest, mapMultiArgs["-seednode"]) { + AddOneShot(strDest); + } + + // ********************************************************* Step 7: load block chain + + fReindex = GetBoolArg("-reindex", false); + + // 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); + 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. + break; + } + } + if (linked) { + fReindex = true; + } + } + + // cache size calculations + size_t nTotalCache = (GetArg("-dbcache", nDefaultDbCache) << 20); + if (nTotalCache < (nMinDbCache << 20)) { + nTotalCache = (nMinDbCache << 20); // total cache cannot be less than nMinDbCache + } else if (nTotalCache > (nMaxDbCache << 20)) { + nTotalCache = (nMaxDbCache << 20); // total cache cannot be greater than nMaxDbCache + } + size_t nBlockTreeDBCache = nTotalCache / 8; + 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 + + bool fLoaded = false; + while (!fLoaded) { + bool fReset = fReindex; + + 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()) { + // Error loading block database + break; + } + + // If the loaded chain has a wrong genesis, bail out immediately + // (we're likely using a testnet datadir, or the other way around). + if (!mapBlockIndex.empty() && chainActive.Genesis() == NULL) { + return 1; + } + + // Initialize the block index (no-op if non-empty database was already loaded) + if (!InitBlockIndex()) { + // Error initializing block database + break; + } + + // Check for changed -txindex state + if (fTxIndex != GetBoolArg("-txindex", false)) { + // You need to rebuild the database using -reindex to change -txindex + break; + } + + if (!VerifyDB(GetArg("-checklevel", 3), GetArg("-checkblocks", 288))) { + // Corrupted block database detected + break; + } + } catch(std::exception &e) { + // Error opening block database + break; + } + + fLoaded = true; + } while (false); + + if (!fLoaded) { + // first suggest a reindex + if (!fReset) { + // automatically reindex: + fReindex = true; + fRequestShutdown = false; + } else { + return 1; + } + } + } + + // As LoadBlockIndex can take several minutes, it's possible the user + // requested to kill the GUI during the last operation. If so, exit. + // As the program has not fully started yet, Shutdown() is possibly overkill. + if (fRequestShutdown) { + return 1; + } + + // ********************************************************* Step 8: load wallet +#ifdef ENABLE_WALLET + if (fDisableWallet) { + pwalletMain = NULL; + } else { + if (GetBoolArg("-zapwallettxes", false)) { + + pwalletMain = new CWallet(strWalletFile); + DBErrors nZapWalletRet = pwalletMain->ZapWalletTx(); + if (nZapWalletRet != DB_LOAD_OK) { + return 1; + } + + delete pwalletMain; + pwalletMain = NULL; + } + + nStart = GetTimeMillis(); + bool fFirstRun = true; + pwalletMain = new CWallet(strWalletFile); + DBErrors nLoadWalletRet = pwalletMain->LoadWallet(fFirstRun); + if (nLoadWalletRet != DB_LOAD_OK) { + if (nLoadWalletRet == DB_CORRUPT) { + // Error loading wallet.dat: Wallet corrupted + failure = 1; + } else if (nLoadWalletRet == DB_NONCRITICAL_ERROR) { + // wallet okay, txs bad + } else if (nLoadWalletRet == DB_TOO_NEW) { + // Error loading wallet.dat: Wallet requires newer version of Bitcoin + failure = 1; + } else if (nLoadWalletRet == DB_NEED_REWRITE) { + // Wallet needed to be rewritten: restart Bitcoin to complete + failure = 1; + return 1; + } else { + // Error loading wallet.dat + failure = 1; + } + } + + if (GetBoolArg("-upgradewallet", fFirstRun)) { + int nMaxVersion = GetArg("-upgradewallet", 0); + if (nMaxVersion == 0) { // the -upgradewallet without argument case + nMaxVersion = CLIENT_VERSION; + pwalletMain->SetMinVersion(FEATURE_LATEST); // permanently upgrade the wallet immediately + } else if (nMaxVersion < pwalletMain->GetVersion()) { + // Cannot downgrade wallet + failure = 1; + } + pwalletMain->SetMaxVersion(nMaxVersion); + } + + if (fFirstRun) { + // Create new keyUser and set as default key + RandAddSeedPerfmon(); + + CPubKey newDefaultKey; + if (pwalletMain->GetKeyFromPool(newDefaultKey)) { + pwalletMain->SetDefaultKey(newDefaultKey); + if (!pwalletMain->SetAddressBook(pwalletMain->vchDefaultKey.GetID(), "", "receive")) { + // Cannot write default address + failure = 1; + } + } + + pwalletMain->SetBestChain(chainActive.GetLocator()); + } + + RegisterWallet(pwalletMain); + + CBlockIndex *pindexRescan = chainActive.Tip(); + if (GetBoolArg("-rescan", false)) { + pindexRescan = chainActive.Genesis(); + } else { + CWalletDB walletdb(strWalletFile); + CBlockLocator locator; + if (walletdb.ReadBestBlock(locator)) { + pindexRescan = chainActive.FindFork(locator); + } else { + pindexRescan = chainActive.Genesis(); + } + } + if (chainActive.Tip() && chainActive.Tip() != pindexRescan) { + nStart = GetTimeMillis(); + pwalletMain->ScanForWalletTransactions(pindexRescan, true); + pwalletMain->SetBestChain(chainActive.GetLocator()); + nWalletDBUpdated++; + } + } // (!fDisableWallet) +#endif // !ENABLE_WALLET + // ********************************************************* Step 9: import blocks + + // scan for better chains in the block chain database, that are not yet connected in the active best chain + CValidationState state; + if (!ActivateBestChain(state)) { + // Failed to connect best block + failure = 1; + } + + std::vector vImportFiles; + if (mapArgs.count("-loadblock")) { + BOOST_FOREACH(string strFile, mapMultiArgs["-loadblock"]) { + vImportFiles.push_back(strFile); + } + } + threadGroup.create_thread(boost::bind(&ThreadImport, vImportFiles)); + + // ********************************************************* Step 10: load peers + + nStart = GetTimeMillis(); + + { + CAddrDB adb; + adb.Read(addrman); + } + + // ********************************************************* Step 11: start node + + if (!CheckDiskSpace()) { + return 1; + } + + if (failure) { + return 1; + } + + RandAddSeedPerfmon(); + + StartNode(threadGroup); + + // InitRPCMining is needed here so getwork/getblocktemplate in the GUI debug console works properly. + InitRPCMining(); + if (fServer) { + StartRPCThreads(); + } + +#ifdef ENABLE_WALLET + // Generate coins in the background + if (pwalletMain) { + GenerateBitcoins(GetBoolArg("-gen", false), pwalletMain, GetArg("-genproclimit", -1)); + } +#endif + + // ********************************************************* Step 12: finished + +#ifdef ENABLE_WALLET + if (pwalletMain) { + // Add wallet transactions that aren't already in a block to mapTransactions + pwalletMain->ReacceptWalletTransactions(); + + // Run a thread to flush wallet periodically + threadGroup.create_thread(boost::bind(&ThreadFlushWalletDB, boost::ref(pwalletMain->strWalletFile))); + } +#endif + + // + // appinit1: + // + + int fRet = !fRequestShutdown; + + if (!fRet) { + if (detectShutdownThread) + detectShutdownThread->interrupt(); + + threadGroup.interrupt_all(); + // threadGroup.join_all(); was left out intentionally here, because we didn't re-test all of + // the startup-failure cases to make sure they don't result in a hang due to some + // thread-blocking-waiting-for-another-thread-during-startup case + } + + if (detectShutdownThread) { + detectShutdownThread->join(); + delete detectShutdownThread; + detectShutdownThread = NULL; + } + Shutdown(); + + // + // main: + // + + if (fRet && fDaemon) { + return 0; + } + + return fRet ? 0 : 1; } /**