/** Initialize Gridcoin. * @pre Parameters should be parsed and config file should be read. */ bool AppInit2(ThreadHandlerPtr threads) { // ********************************************************* Step 1: setup #ifdef _MSC_VER // Turn off Microsoft heap dump noise _CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_FILE); _CrtSetReportFile(_CRT_WARN, CreateFileA("NUL", GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, 0)); #endif #if _MSC_VER >= 1400 // Disable confusing "helpful" text message on abort, Ctrl-C _set_abort_behavior(0, _WRITE_ABORT_MSG | _CALL_REPORTFAULT); #endif #ifdef WIN32 // Enable Data Execution Prevention (DEP) // Minimum supported OS versions: WinXP SP3, WinVista >= SP1, Win Server 2008 // A failure is non-critical and needs no further attention! #ifndef PROCESS_DEP_ENABLE // We define this here, because GCCs winbase.h limits this to _WIN32_WINNT >= 0x0601 (Windows 7), // which is not correct. Can be removed, when GCCs winbase.h is fixed! #define PROCESS_DEP_ENABLE 0x00000001 #endif typedef BOOL (WINAPI *PSETPROCDEPPOL)(DWORD); PSETPROCDEPPOL setProcDEPPol = (PSETPROCDEPPOL)GetProcAddress(GetModuleHandleA("Kernel32.dll"), "SetProcessDEPPolicy"); if (setProcDEPPol != NULL) setProcDEPPol(PROCESS_DEP_ENABLE); #endif #ifndef WIN32 umask(077); // 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); #endif // ********************************************************* Step 2: parameter interactions // Gridcoin - Check to see if config is empty? if (IsConfigFileEmpty()) { uiInterface.ThreadSafeMessageBox( "Configuration file empty. \n" + _("Please wait for new user wizard to start..."), "", 0); } //6-10-2014: R Halford: Updating Boost version to 1.5.5 to prevent sync issues; print the boost version to verify: //5-04-2018: J Owens: Boost now needs to be 1.65 or higher to avoid thread sleep problems with system clock resets. std::string boost_version = ""; std::ostringstream s; s << boost_version << "Using Boost " << BOOST_VERSION / 100000 << "." // major version << BOOST_VERSION / 100 % 1000 << "." // minior version << BOOST_VERSION % 100 // patch level << "\n"; LogPrintf("Boost Version: %s", s.str()); //Placeholder: Load Remote CPIDs Here nNodeLifespan = GetArg("-addrlifespan", 7); fUseFastIndex = GetBoolArg("-fastindex", false); nMinerSleep = GetArg("-minersleep", 8000); nDerivationMethodIndex = 0; fTestNet = GetBoolArg("-testnet"); 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 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")) { // Rewrite just private keys: rescan to find transactions SoftSetBoolArg("-rescan", true); } if (GetBoolArg("-zapwallettxes", false)) { // -zapwallettx implies a rescan SoftSetBoolArg("-rescan", true); } // Verify testnet is using the testnet directory for the config file: std::string sTestNetSpecificArg = GetArgument("testnetarg","default"); LogPrintf("Using specific arg %s",sTestNetSpecificArg); // ********************************************************* Step 3: parameter-to-internal-flags fDebug=false; if (fDebug) fDebugNet = true; else fDebugNet = GetBoolArg("-debugnet"); if (GetArg("-debug", "false")=="true") { fDebug = true; LogPrintf("Entering debug mode."); } fDebug2 = false; if (GetArg("-debug2", "false")=="true") { fDebug2 = true; LogPrintf("Entering GRC debug mode 2."); } fDebug3 = false; if (GetArg("-debug3", "false")=="true") { fDebug3 = true; LogPrintf("Entering GRC debug mode 3."); } if (GetArg("-debug4", "false")=="true") { fDebug4 = true; LogPrintf("Entering RPC time debug mode"); } fDebug10= (GetArg("-debug10","false")=="true"); #if defined(WIN32) fDaemon = false; #else if(fQtActive) fDaemon = false; else fDaemon = GetBoolArg("-daemon"); #endif if (fDaemon) fServer = true; else fServer = GetBoolArg("-server"); /* force fServer when running without GUI */ if(!fQtActive) fServer = true; fPrintToConsole = GetBoolArg("-printtoconsole"); fPrintToDebugger = GetBoolArg("-printtodebugger"); fLogTimestamps = GetBoolArg("-logtimestamps"); fLogTimestamps = true; if (mapArgs.count("-timeout")) { int nNewTimeout = GetArg("-timeout", 4000); if (nNewTimeout > 0 && nNewTimeout < 600000) nConnectTimeout = nNewTimeout; } if (mapArgs.count("-paytxfee")) { if (!ParseMoney(mapArgs["-paytxfee"], nTransactionFee)) return InitError(strprintf(_("Invalid amount for -paytxfee=<amount>: '%s'"), mapArgs["-paytxfee"])); if (nTransactionFee > 0.25 * COIN) InitWarning(_("Warning: -paytxfee is set very high! This is the transaction fee you will pay if you send a transaction.")); } fConfChange = GetBoolArg("-confchange", false); fEnforceCanonical = GetBoolArg("-enforcecanonical", true); if (mapArgs.count("-mininput")) { if (!ParseMoney(mapArgs["-mininput"], nMinimumInputValue)) return InitError(strprintf(_("Invalid amount for -mininput=<amount>: '%s'"), mapArgs["-mininput"])); } // ********************************************************* Step 4: application initialization: dir lock, daemonize, pidfile, debug log // Sanity check if (!InitSanityCheck()) return InitError(_("Initialization sanity check failed. Gridcoin is shutting down.")); // Initialize internal hashing code with SSE/AVX2 optimizations. In the future we will also have ARM/NEON optimizations. std::string sha256_algo = SHA256AutoDetect(); LogPrintf("Using the '%s' SHA256 implementation\n", sha256_algo); std::string strDataDir = GetDataDir().string(); std::string strWalletFileName = GetArg("-wallet", "wallet.dat"); // strWalletFileName must be a plain filename without a directory if (strWalletFileName != boost::filesystem::basename(strWalletFileName) + boost::filesystem::extension(strWalletFileName)) return InitError(strprintf(_("Wallet %s resides outside data directory %s."), strWalletFileName, strDataDir)); // 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. Gridcoin is probably already running."), strDataDir)); #if !defined(WIN32) if (fDaemon) { // Daemonize pid_t pid = fork(); if (pid < 0) { fprintf(stderr, "Error: fork() returned %d errno %d\n", pid, errno); return false; } if (pid > 0) { CreatePidFile(GetPidFile(), pid); // Now that we are forked we can request a shutdown so the parent // exits while the child lives on. StartShutdown(); return true; } pid_t sid = setsid(); if (sid < 0) fprintf(stderr, "Error: setsid() returned %d errno %d\n", sid, errno); } #endif ShrinkDebugFile(); LogPrintf("\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n"); LogPrintf("Gridcoin version %s (%s)", FormatFullVersion(), CLIENT_DATE); LogPrintf("Using OpenSSL version %s", SSLeay_version(SSLEAY_VERSION)); if (!fLogTimestamps) LogPrintf("Startup time: %s", DateTimeStrFormat("%x %H:%M:%S", GetAdjustedTime())); LogPrintf("Default data directory %s", GetDefaultDataDir().string()); LogPrintf("Used data directory %s", strDataDir); std::ostringstream strErrors; fDevbuildCripple = false; if((CLIENT_VERSION_BUILD != 0) && !fTestNet) { fDevbuildCripple = true; LogPrintf("WARNING: Running development version outside of testnet!\n" "Staking and sending transactions will be disabled."); if( (GetArg("-devbuild", "") == "override") && fDebug ) fDevbuildCripple = false; } if (fDaemon) fprintf(stdout, "Gridcoin server starting\n"); int64_t nStart; // ********************************************************* 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); return InitError(msg); } if (GetBoolArg("-salvagewallet")) { // Recover readable keypairs: if (!CWalletDB::Recover(bitdb, strWalletFileName, true)) return false; } if (filesystem::exists(GetDataDir() / strWalletFileName)) { CDBEnv::VerifyResult r = bitdb.Verify(strWalletFileName, 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); uiInterface.ThreadSafeMessageBox(msg, _("Gridcoin"), 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); if (nSocksVersion != 4 && nSocksVersion != 5) return InitError(strprintf(_("Unknown -socks proxy version requested: %i"), nSocksVersion)); if (mapArgs.count("-onlynet")) { std::set<enum Network> nets; for (auto const& snet : mapMultiArgs["-onlynet"]) { enum Network net = ParseNetwork(snet); if (net == NET_UNROUTABLE) return InitError(strprintf(_("Unknown network specified in -onlynet: '%s'"), snet)); nets.insert(net); } for (int n = 0; n < NET_MAX; n++) { enum Network net = (enum Network)n; if (!nets.count(net)) SetLimited(net); } } CService addrProxy; bool fProxy = false; if (mapArgs.count("-proxy")) { addrProxy = CService(mapArgs["-proxy"], 9050); if (!addrProxy.IsValid()) return InitError(strprintf(_("Invalid -proxy address: '%s'"), mapArgs["-proxy"])); if (!IsLimited(NET_IPV4)) SetProxy(NET_IPV4, addrProxy, nSocksVersion); if (nSocksVersion > 4) { if (!IsLimited(NET_IPV6)) SetProxy(NET_IPV6, addrProxy, nSocksVersion); SetNameProxy(addrProxy, nSocksVersion); } fProxy = true; } // -tor can override normal proxy, -notor disables tor entirely if (!(mapArgs.count("-tor") && mapArgs["-tor"] == "0") && (fProxy || mapArgs.count("-tor"))) { CService addrOnion; if (!mapArgs.count("-tor")) addrOnion = addrProxy; else addrOnion = CService(mapArgs["-tor"], 9050); if (!addrOnion.IsValid()) return InitError(strprintf(_("Invalid -tor address: '%s'"), mapArgs["-tor"])); 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); #ifdef USE_UPNP fUseUPnP = GetBoolArg("-upnp", USE_UPNP); #endif bool fBound = false; if (!fNoListen) { std::string strError; if (mapArgs.count("-bind")) { for (auto const& strBind : mapMultiArgs["-bind"]) { CService addrBind; if (!Lookup(strBind.c_str(), addrBind, GetListenPort(), false)) return InitError(strprintf(_("Cannot resolve -bind address: '%s'"), strBind)); fBound |= Bind(addrBind); } } else { struct in_addr inaddr_any; inaddr_any.s_addr = INADDR_ANY; if (!IsLimited(NET_IPV6)) fBound |= Bind(CService(in6addr_any, GetListenPort()), false); if (!IsLimited(NET_IPV4)) fBound |= Bind(CService(inaddr_any, GetListenPort()), !fBound); } if (!fBound) return InitError(_("Failed to listen on any port. Use -listen=0 if you want this.")); } if (mapArgs.count("-externalip")) { for (auto const& strAddr : mapMultiArgs["-externalip"]) { CService addrLocal(strAddr, GetListenPort(), fNameLookup); if (!addrLocal.IsValid()) return InitError(strprintf(_("Cannot resolve -externalip address: '%s'"), strAddr)); AddLocal(CService(strAddr, GetListenPort(), fNameLookup), LOCAL_MANUAL); } } if (mapArgs.count("-reservebalance")) // ppcoin: reserve balance amount { if (!ParseMoney(mapArgs["-reservebalance"], nReserveBalance)) { InitError(_("Invalid amount for -reservebalance=<amount>")); return false; } } for (auto const& strDest : mapMultiArgs["-seednode"]) AddOneShot(strDest); // ********************************************************* Step 7: load blockchain 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); return InitError(msg); } if (GetBoolArg("-loadblockindextest")) { CTxDB txdb("r"); txdb.LoadBlockIndex(); PrintBlockTree(); return false; } uiInterface.InitMessage(_("Loading block index...")); LogPrintf("Loading block index..."); nStart = GetTimeMillis(); if (!LoadBlockIndex()) 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. // As the program has not fully started yet, Shutdown() is possibly overkill. if (fRequestShutdown) { LogPrintf("Shutdown requested. Exiting."); return false; } LogPrintf(" block index %15" PRId64 "ms", GetTimeMillis() - nStart); if (GetBoolArg("-printblockindex") || GetBoolArg("-printblocktree")) { PrintBlockTree(); return false; } if (mapArgs.count("-printblock")) { string strMatch = mapArgs["-printblock"]; int nFound = 0; for (BlockMap::iterator mi = mapBlockIndex.begin(); mi != mapBlockIndex.end(); ++mi) { uint256 hash = (*mi).first; if (strncmp(hash.ToString().c_str(), strMatch.c_str(), strMatch.size()) == 0) { CBlockIndex* pindex = (*mi).second; CBlock block; block.ReadFromDisk(pindex); block.BuildMerkleTree(); block.print(); LogPrintf(""); nFound++; } } if (nFound == 0) LogPrintf("No blocks matching %s were found", strMatch); return false; } // ********************************************************* Step 8: load wallet uiInterface.InitMessage(_("Loading wallet...")); LogPrintf("Loading wallet..."); nStart = GetTimeMillis(); bool fFirstRun = true; pwalletMain = new CWallet(strWalletFileName); 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, _("Gridcoin"), CClientUIInterface::OK | CClientUIInterface::ICON_EXCLAMATION | CClientUIInterface::MODAL); } else if (nLoadWalletRet == DB_TOO_NEW) strErrors << _("Error loading wallet.dat: Wallet requires newer version of Gridcoin") << "\n"; else if (nLoadWalletRet == DB_NEED_REWRITE) { strErrors << _("Wallet needed to be rewritten: restart Gridcoin to complete") << "\n"; LogPrintf("%s", strErrors.str()); return InitError(strErrors.str()); } else strErrors << _("Error loading wallet.dat") << "\n"; } if (GetBoolArg("-upgradewallet", fFirstRun)) { int nMaxVersion = GetArg("-upgradewallet", 0); if (nMaxVersion == 0) // the -upgradewallet without argument case { LogPrintf("Performing wallet upgrade to %i", FEATURE_LATEST); nMaxVersion = CLIENT_VERSION; pwalletMain->SetMinVersion(FEATURE_LATEST); // permanently upgrade the wallet immediately } else LogPrintf("Allowing wallet upgrade up to %i", nMaxVersion); if (nMaxVersion < pwalletMain->GetVersion()) strErrors << _("Cannot downgrade wallet") << "\n"; pwalletMain->SetMaxVersion(nMaxVersion); } if (fFirstRun) { // Create new keyUser and set as default key RandAddSeedPerfmon(); CPubKey newDefaultKey; if (pwalletMain->GetKeyFromPool(newDefaultKey, false)) { pwalletMain->SetDefaultKey(newDefaultKey); if (!pwalletMain->SetAddressBookName(pwalletMain->vchDefaultKey.GetID(), "")) strErrors << _("Cannot write default address") << "\n"; } } LogPrintf("%s", strErrors.str()); LogPrintf(" wallet %15" PRId64 "ms", GetTimeMillis() - nStart); RegisterWallet(pwalletMain); CBlockIndex *pindexRescan = pindexBest; if (GetBoolArg("-rescan")) pindexRescan = pindexGenesisBlock; else { CWalletDB walletdb(strWalletFileName); CBlockLocator locator; if (walletdb.ReadBestBlock(locator)) pindexRescan = locator.GetBlockIndex(); } if (pindexBest != pindexRescan && pindexBest && pindexRescan && pindexBest->nHeight > pindexRescan->nHeight) { uiInterface.InitMessage(_("Rescanning...")); LogPrintf("Rescanning last %i blocks (from block %i)...", pindexBest->nHeight - pindexRescan->nHeight, pindexRescan->nHeight); nStart = GetTimeMillis(); pwalletMain->ScanForWalletTransactions(pindexRescan, true); LogPrintf(" rescan %15" PRId64 "ms", GetTimeMillis() - nStart); } // ********************************************************* Step 9: import blocks if (mapArgs.count("-loadblock")) { uiInterface.InitMessage(_("Importing blockchain data file.")); for (auto const& strFile : mapMultiArgs["-loadblock"]) { FILE *file = fopen(strFile.c_str(), "rb"); if (file) LoadExternalBlockFile(file); } exit(0); } filesystem::path pathBootstrap = GetDataDir() / "bootstrap.dat"; if (filesystem::exists(pathBootstrap)) { uiInterface.InitMessage(_("Importing bootstrap blockchain data file.")); FILE *file = fopen(pathBootstrap.string().c_str(), "rb"); if (file) { filesystem::path pathBootstrapOld = GetDataDir() / "bootstrap.dat.old"; LoadExternalBlockFile(file); RenameOver(pathBootstrap, pathBootstrapOld); } } // ********************************************************* Step 10: load peers uiInterface.InitMessage(_("Loading addresses...")); if (fDebug10) LogPrintf("Loading addresses..."); nStart = GetTimeMillis(); { CAddrDB adb; if (!adb.Read(addrman)) LogPrintf("Invalid or missing peers.dat; recreating"); } LogPrintf("Loaded %i addresses from peers.dat %" PRId64 "ms", addrman.size(), GetTimeMillis() - nStart); // ********************************************************* Step 11: start node uiInterface.InitMessage(_("Loading Persisted Data Cache...")); // std::string sOut = ""; if (fDebug3) LogPrintf("Loading admin Messages"); LoadAdminMessages(true,sOut); LogPrintf("Done loading Admin messages"); uiInterface.InitMessage(_("Compute Neural Network Hashes...")); ComputeNeuralNetworkSupermajorityHashes(); LoadCPIDs(); uiInterface.InitMessage(_("Finding first applicable Research Project...")); if (!CheckDiskSpace()) return false; RandAddSeedPerfmon(); //// debug print if (fDebug) { LogPrintf("mapBlockIndex.size() = %" PRIszu, mapBlockIndex.size()); LogPrintf("nBestHeight = %d", nBestHeight); LogPrintf("setKeyPool.size() = %" PRIszu, pwalletMain->setKeyPool.size()); LogPrintf("mapWallet.size() = %" PRIszu, pwalletMain->mapWallet.size()); LogPrintf("mapAddressBook.size() = %" PRIszu, pwalletMain->mapAddressBook.size()); } uiInterface.InitMessage(_("Loading Network Averages...")); if (fDebug3) LogPrintf("Loading network averages"); CBlockIndex* tallyHeight = FindTallyTrigger(pindexBest); if(tallyHeight) TallyResearchAverages(tallyHeight); if (!threads->createThread(StartNode, NULL, "Start Thread")) InitError(_("Error: could not start node")); if (fServer) StartRPCThreads(); // ********************************************************* Step 12: finished uiInterface.InitMessage(_("Done loading")); LogPrintf("Done loading"); if (!strErrors.str().empty()) return InitError(strErrors.str()); // Add wallet transactions that aren't already in a block to mapTransactions pwalletMain->ReacceptWalletTransactions(); int nMismatchSpent; int64_t nBalanceInQuestion; pwalletMain->FixSpentCoins(nMismatchSpent, nBalanceInQuestion); return true; }